Merge "p2p: support factory reset for P2P group"
diff --git a/Android.bp b/Android.bp
index e7815ee..93e6963 100644
--- a/Android.bp
+++ b/Android.bp
@@ -287,6 +287,8 @@
"core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl",
"core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
"core/java/android/service/gatekeeper/IGateKeeperService.aidl",
+ "core/java/android/service/intelligence/IIntelligenceService.aidl",
+
"core/java/android/service/notification/INotificationListener.aidl",
"core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
"core/java/android/service/notification/IConditionListener.aidl",
@@ -343,6 +345,7 @@
"core/java/android/view/autofill/IAutoFillManager.aidl",
"core/java/android/view/autofill/IAutoFillManagerClient.aidl",
"core/java/android/view/autofill/IAutofillWindowPresenter.aidl",
+ "core/java/android/view/intelligence/IIntelligenceManager.aidl",
"core/java/android/view/IApplicationToken.aidl",
"core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
"core/java/android/view/IDockedStackListener.aidl",
@@ -595,6 +598,8 @@
"telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
"wifi/java/android/net/wifi/ISoftApCallback.aidl",
"wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
"wifi/java/android/net/wifi/IWifiManager.aidl",
@@ -693,6 +698,7 @@
],
static_libs: [
+ "apex_aidl_interface-java",
"framework-protos",
"mediaplayer2-protos",
"android.hidl.base-V1.0-java",
@@ -700,6 +706,8 @@
"android.hardware.contexthub-V1.0-java",
"android.hardware.health-V1.0-java-constants",
"android.hardware.thermal-V1.0-java-constants",
+ "android.hardware.thermal-V1.1-java",
+ "android.hardware.thermal-V2.0-java",
"android.hardware.tv.input-V1.0-java-constants",
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
@@ -758,6 +766,16 @@
],
}
+// A host library containing the inspector annotations for inspector-annotation-processor.
+java_library_host {
+ name: "inspector-annotation",
+ srcs: [
+ "core/java/android/view/inspector/InspectableChildren.java",
+ "core/java/android/view/inspector/InspectableNodeName.java",
+ "core/java/android/view/inspector/InspectableProperty.java",
+ ],
+}
+
// A host library including just UnsupportedAppUsage.java so that the annotation
// processor can also use this annotation.
java_library_host {
diff --git a/api/current.txt b/api/current.txt
index f387c5d..774831d 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -11176,12 +11176,17 @@
public static class PackageInstaller.Session implements java.io.Closeable {
method public void abandon();
+ method public void addChildSessionId(int);
method public void close();
method public void commit(android.content.IntentSender);
method public void fsync(java.io.OutputStream) throws java.io.IOException;
+ method public int[] getChildSessionIds();
method public java.lang.String[] getNames() throws java.io.IOException;
+ method public int getParentSessionId();
+ method public boolean isMultiPackage();
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+ method public void removeChildSessionId(int);
method public void removeSplit(java.lang.String) throws java.io.IOException;
method public void setStagingProgress(float);
method public void transfer(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11202,20 +11207,24 @@
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int[] getChildSessionIds();
method public int getInstallLocation();
method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public int getMode();
method public int getOriginatingUid();
method public android.net.Uri getOriginatingUri();
+ method public int getParentSessionId();
method public float getProgress();
method public android.net.Uri getReferrerUri();
method public int getSessionId();
method public long getSize();
method public boolean isActive();
+ method public boolean isMultiPackage();
method public boolean isSealed();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
+ field public static final int INVALID_ID = -1; // 0xffffffff
}
public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -11226,6 +11235,7 @@
method public void setAppPackageName(java.lang.String);
method public void setInstallLocation(int);
method public void setInstallReason(int);
+ method public void setMultiPackage();
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -13878,6 +13888,7 @@
field public static final int RAW_SENSOR = 32; // 0x20
field public static final int RGB_565 = 4; // 0x4
field public static final int UNKNOWN = 0; // 0x0
+ field public static final int Y8 = 538982489; // 0x20203859
field public static final int YUV_420_888 = 35; // 0x23
field public static final int YUV_422_888 = 39; // 0x27
field public static final int YUV_444_888 = 40; // 0x28
@@ -14769,9 +14780,10 @@
public static class Typeface.CustomFallbackBuilder {
ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily);
+ method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(android.graphics.fonts.FontFamily);
method public android.graphics.Typeface build();
- method public android.graphics.Typeface.CustomFallbackBuilder setFallback(java.lang.String);
method public android.graphics.Typeface.CustomFallbackBuilder setStyle(android.graphics.fonts.FontStyle);
+ method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(java.lang.String);
}
public class Xfermode {
@@ -16291,6 +16303,7 @@
method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
method public java.util.Set<java.lang.String> getPhysicalCameraIds();
+ method public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int);
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
@@ -16953,6 +16966,33 @@
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
}
+ public final class RecommendedStreamConfigurationMap {
+ method public java.util.Set<android.util.Size> getHighResolutionOutputSizes(int);
+ method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRanges();
+ method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRangesFor(android.util.Size);
+ method public java.util.Set<android.util.Size> getHighSpeedVideoSizes();
+ method public java.util.Set<android.util.Size> getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>);
+ method public java.util.Set<java.lang.Integer> getInputFormats();
+ method public java.util.Set<android.util.Size> getInputSizes(int);
+ method public java.util.Set<java.lang.Integer> getOutputFormats();
+ method public long getOutputMinFrameDuration(int, android.util.Size);
+ method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+ method public java.util.Set<android.util.Size> getOutputSizes(int);
+ method public <T> java.util.Set<android.util.Size> getOutputSizes(java.lang.Class<T>);
+ method public long getOutputStallDuration(int, android.util.Size);
+ method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+ method public int getRecommendedUseCase();
+ method public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
+ method public boolean isOutputSupportedFor(int);
+ method public boolean isOutputSupportedFor(android.view.Surface);
+ field public static final int USECASE_PREVIEW = 0; // 0x0
+ field public static final int USECASE_RAW = 5; // 0x5
+ field public static final int USECASE_RECORD = 1; // 0x1
+ field public static final int USECASE_SNAPSHOT = 3; // 0x3
+ field public static final int USECASE_VIDEO_SNAPSHOT = 2; // 0x2
+ field public static final int USECASE_ZSL = 4; // 0x4
+ }
+
public final class RggbChannelVector {
ctor public RggbChannelVector(float, float, float, float);
method public void copyTo(float[], int);
@@ -28690,7 +28730,7 @@
enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
method public android.net.ProxyInfo getHttpProxy();
@@ -28702,9 +28742,11 @@
field public java.lang.String SSID;
field public java.util.BitSet allowedAuthAlgorithms;
field public java.util.BitSet allowedGroupCiphers;
+ field public java.util.BitSet allowedGroupMgmtCiphers;
field public java.util.BitSet allowedKeyManagement;
field public java.util.BitSet allowedPairwiseCiphers;
field public java.util.BitSet allowedProtocols;
+ field public java.util.BitSet allowedSuiteBCiphers;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
field public boolean isHomeProviderNetwork;
@@ -28728,6 +28770,7 @@
public static class WifiConfiguration.GroupCipher {
field public static final int CCMP = 3; // 0x3
+ field public static final int GCMP_256 = 5; // 0x5
field public static final int TKIP = 2; // 0x2
field public static final deprecated int WEP104 = 1; // 0x1
field public static final deprecated int WEP40 = 0; // 0x0
@@ -28735,9 +28778,18 @@
field public static final java.lang.String varName = "group";
}
+ public static class WifiConfiguration.GroupMgmtCipher {
+ field public static final int BIP_CMAC_256 = 0; // 0x0
+ field public static final int BIP_GMAC_128 = 1; // 0x1
+ field public static final int BIP_GMAC_256 = 2; // 0x2
+ }
+
public static class WifiConfiguration.KeyMgmt {
field public static final int IEEE8021X = 3; // 0x3
field public static final int NONE = 0; // 0x0
+ field public static final int OWE = 9; // 0x9
+ field public static final int SAE = 8; // 0x8
+ field public static final int SUITE_B_192 = 10; // 0xa
field public static final int WPA_EAP = 2; // 0x2
field public static final int WPA_PSK = 1; // 0x1
field public static final java.lang.String[] strings;
@@ -28746,6 +28798,7 @@
public static class WifiConfiguration.PairwiseCipher {
field public static final int CCMP = 2; // 0x2
+ field public static final int GCMP_256 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final deprecated int TKIP = 1; // 0x1
field public static final java.lang.String[] strings;
@@ -28844,7 +28897,8 @@
}
public class WifiManager {
- method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>, android.app.PendingIntent);
method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
@@ -28852,10 +28906,10 @@
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);
- method public boolean disableNetwork(int);
- method public boolean disconnect();
- method public boolean enableNetwork(int, boolean);
- method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+ method public deprecated boolean disableNetwork(int);
+ method public deprecated boolean disconnect();
+ method public deprecated boolean enableNetwork(int, boolean);
+ method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
@@ -28866,22 +28920,23 @@
method public boolean isEnhancedPowerReportingSupported();
method public boolean isP2pSupported();
method public boolean isPreferredNetworkOffloadSupported();
- method public boolean isScanAlwaysAvailable();
+ method public deprecated boolean isScanAlwaysAvailable();
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public deprecated boolean pingSupplicant();
- method public boolean reassociate();
- method public boolean reconnect();
- method public boolean removeNetwork(int);
+ method public deprecated boolean reassociate();
+ method public deprecated boolean reconnect();
+ method public deprecated boolean removeNetwork(int);
+ method public boolean removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
method public void removePasspointConfiguration(java.lang.String);
method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
- method public boolean setWifiEnabled(boolean);
+ method public deprecated boolean setWifiEnabled(boolean);
method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
method public deprecated boolean startScan();
method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
- method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
@@ -28955,6 +29010,29 @@
method public abstract deprecated void onSucceeded();
}
+ public class WifiNetworkConfigBuilder {
+ ctor public WifiNetworkConfigBuilder();
+ method public android.net.NetworkSpecifier buildNetworkSpecifier();
+ method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
+ method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
+ }
+
+ public final class WifiNetworkSuggestion 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.WifiNetworkSuggestion> CREATOR;
+ }
+
public deprecated class WpsInfo implements android.os.Parcelable {
ctor public deprecated WpsInfo();
ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
@@ -34374,7 +34452,7 @@
}
public final class StorageVolume implements android.os.Parcelable {
- method public android.content.Intent createAccessIntent(java.lang.String);
+ method public deprecated android.content.Intent createAccessIntent(java.lang.String);
method public int describeContents();
method public java.lang.String getDescription(android.content.Context);
method public java.lang.String getState();
@@ -35613,6 +35691,15 @@
method public static java.lang.String getLastOutgoingCall(android.content.Context);
field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
field public static final int BLOCKED_TYPE = 6; // 0x6
+ field public static final java.lang.String BLOCK_REASON = "block_reason";
+ field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
+ field public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; // 0x1
+ field public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; // 0x2
+ field public static final int BLOCK_REASON_NOT_BLOCKED = 0; // 0x0
+ field public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7; // 0x7
+ field public static final int BLOCK_REASON_PAY_PHONE = 6; // 0x6
+ field public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; // 0x5
+ field public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; // 0x4
field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
@@ -35622,6 +35709,8 @@
field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
+ field public static final java.lang.String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+ field public static final java.lang.String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -37414,7 +37503,7 @@
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
- field public static final java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
+ field public static final deprecated java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
@@ -42806,6 +42895,16 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR;
}
+ public final class CellIdentityNr extends android.telephony.CellIdentity {
+ method public int getChannelNumber();
+ method public java.lang.String getMccString();
+ method public java.lang.String getMncString();
+ method public int getPci();
+ method public int getTac();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityNr> CREATOR;
+ }
+
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
method public int getCid();
method public int getCpid();
@@ -42865,6 +42964,13 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
}
+ public final class CellInfoNr extends android.telephony.CellInfo {
+ method public android.telephony.CellIdentity getCellIdentity();
+ method public android.telephony.CellSignalStrength getCellSignalStrength();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellInfoNr> CREATOR;
+ }
+
public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
method public android.telephony.CellIdentityWcdma getCellIdentity();
method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
@@ -42931,6 +43037,21 @@
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthLte> CREATOR;
}
+ public final class CellSignalStrengthNr extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAsuLevel();
+ method public int getCsiRsrp();
+ method public int getCsiRsrq();
+ method public int getCsiSinr();
+ method public int getDbm();
+ method public int getLevel();
+ method public int getSsRsrp();
+ method public int getSsRsrq();
+ method public int getSsSinr();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthNr> CREATOR;
+ }
+
public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
method public int describeContents();
method public int getAsuLevel();
@@ -50118,17 +50239,29 @@
method public int getStableInsetLeft();
method public int getStableInsetRight();
method public int getStableInsetTop();
+ method public android.graphics.Insets getStableInsets();
method public int getSystemWindowInsetBottom();
method public int getSystemWindowInsetLeft();
method public int getSystemWindowInsetRight();
method public int getSystemWindowInsetTop();
+ method public android.graphics.Insets getSystemWindowInsets();
method public boolean hasInsets();
method public boolean hasStableInsets();
method public boolean hasSystemWindowInsets();
+ method public android.view.WindowInsets inset(int, int, int, int);
method public boolean isConsumed();
method public boolean isRound();
- method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
- method public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
+ method public deprecated android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
+ method public deprecated android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
+ }
+
+ public static class WindowInsets.Builder {
+ ctor public WindowInsets.Builder();
+ ctor public WindowInsets.Builder(android.view.WindowInsets);
+ method public android.view.WindowInsets build();
+ method public android.view.WindowInsets.Builder setDisplayCutout(android.view.DisplayCutout);
+ method public android.view.WindowInsets.Builder setStableInsets(android.graphics.Insets);
+ method public android.view.WindowInsets.Builder setSystemWindowInsets(android.graphics.Insets);
}
public abstract interface WindowManager implements android.view.ViewManager {
@@ -73666,10 +73799,13 @@
method public abstract void beginHandshake() throws javax.net.ssl.SSLException;
method public abstract void closeInbound() throws javax.net.ssl.SSLException;
method public abstract void closeOutbound();
+ method public java.lang.String getApplicationProtocol();
method public abstract java.lang.Runnable getDelegatedTask();
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public java.lang.String getHandshakeApplicationProtocol();
+ method public java.util.function.BiFunction<javax.net.ssl.SSLEngine, java.util.List<java.lang.String>, java.lang.String> getHandshakeApplicationProtocolSelector();
method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
method public abstract boolean getNeedClientAuth();
@@ -73686,6 +73822,7 @@
method public abstract void setEnableSessionCreation(boolean);
method public abstract void setEnabledCipherSuites(java.lang.String[]);
method public abstract void setEnabledProtocols(java.lang.String[]);
+ method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLEngine, java.util.List<java.lang.String>, java.lang.String>);
method public abstract void setNeedClientAuth(boolean);
method public void setSSLParameters(javax.net.ssl.SSLParameters);
method public abstract void setUseClientMode(boolean);
@@ -73744,6 +73881,7 @@
ctor public SSLParameters(java.lang.String[]);
ctor public SSLParameters(java.lang.String[], java.lang.String[]);
method public java.security.AlgorithmConstraints getAlgorithmConstraints();
+ method public java.lang.String[] getApplicationProtocols();
method public java.lang.String[] getCipherSuites();
method public java.lang.String getEndpointIdentificationAlgorithm();
method public boolean getNeedClientAuth();
@@ -73753,6 +73891,7 @@
method public final boolean getUseCipherSuitesOrder();
method public boolean getWantClientAuth();
method public void setAlgorithmConstraints(java.security.AlgorithmConstraints);
+ method public void setApplicationProtocols(java.lang.String[]);
method public void setCipherSuites(java.lang.String[]);
method public void setEndpointIdentificationAlgorithm(java.lang.String);
method public void setNeedClientAuth(boolean);
@@ -73857,9 +73996,12 @@
ctor protected SSLSocket(java.lang.String, int, java.net.InetAddress, int) throws java.io.IOException, java.net.UnknownHostException;
ctor protected SSLSocket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
method public abstract void addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
+ method public java.lang.String getApplicationProtocol();
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public java.lang.String getHandshakeApplicationProtocol();
+ method public java.util.function.BiFunction<javax.net.ssl.SSLSocket, java.util.List<java.lang.String>, java.lang.String> getHandshakeApplicationProtocolSelector();
method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract boolean getNeedClientAuth();
method public javax.net.ssl.SSLParameters getSSLParameters();
@@ -73872,6 +74014,7 @@
method public abstract void setEnableSessionCreation(boolean);
method public abstract void setEnabledCipherSuites(java.lang.String[]);
method public abstract void setEnabledProtocols(java.lang.String[]);
+ method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLSocket, java.util.List<java.lang.String>, java.lang.String>);
method public abstract void setNeedClientAuth(boolean);
method public void setSSLParameters(javax.net.ssl.SSLParameters);
method public abstract void setUseClientMode(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7c87a21..da1adac 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -300,8 +300,8 @@
method public static java.lang.String[] getOpStrs();
method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOpStrs(java.lang.String[]);
+ method public static int opToDefaultMode(java.lang.String);
method public static java.lang.String opToPermission(java.lang.String);
- method public void resetUidMode(java.lang.String, int, boolean);
method public void setMode(java.lang.String, int, java.lang.String, int);
method public void setUidMode(java.lang.String, int, int);
field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
@@ -3615,7 +3615,7 @@
field public byte id;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
method public boolean hasNoInternetAccess();
method public boolean isEphemeral();
method public boolean isNoInternetAccessExpected();
@@ -3641,11 +3641,16 @@
method public int getWifiApState();
method public boolean isDeviceToApRttSupported();
method public boolean isDeviceToDeviceRttSupported();
+ method public boolean isOweSupported();
method public boolean isPortableHotspotSupported();
method public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
+ method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
+ method public boolean isWpa3SaeSupported();
+ method public boolean isWpa3SuiteBSupported();
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method public boolean startScan(android.os.WorkSource);
+ method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
@@ -3673,6 +3678,18 @@
method public abstract void onSuccess();
}
+ public static abstract interface WifiManager.NetworkRequestMatchCallback {
+ method public abstract void onMatch(java.util.List<android.net.wifi.WifiConfiguration>);
+ method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+ method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration);
+ method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration);
+ }
+
+ public static abstract interface WifiManager.NetworkRequestUserSelectionCallback {
+ method public abstract void reject();
+ method public abstract void select(android.net.wifi.WifiConfiguration);
+ }
+
public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
ctor public WifiNetworkConnectionStatistics(int, int);
ctor public WifiNetworkConnectionStatistics();
@@ -5551,8 +5568,12 @@
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
- field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri VT_ENABLED_CONTENT_URI;
field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_MODE_CONTENT_URI;
+ field public static final android.net.Uri WFC_ROAMING_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI;
}
public final class SubscriptionPlan implements android.os.Parcelable {
@@ -5911,6 +5932,7 @@
field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
+ field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd
field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
field public static final int RESULT_OK = 0; // 0x0
field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
@@ -6035,6 +6057,7 @@
method public void setCallExtra(java.lang.String, java.lang.String);
method public void setCallExtraBoolean(java.lang.String, boolean);
method public void setCallExtraInt(java.lang.String, int);
+ method public void setCallRestrictCause(int);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
diff --git a/api/test-current.txt b/api/test-current.txt
index 604eebd..b2cf4c8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -208,10 +208,12 @@
method public int getActivityType();
method public android.graphics.Rect getAppBounds();
method public android.graphics.Rect getBounds();
+ method public int getRotation();
method public int getWindowingMode();
method public void setActivityType(int);
method public void setAppBounds(android.graphics.Rect);
method public void setBounds(android.graphics.Rect);
+ method public void setRotation(int);
method public void setTo(android.app.WindowConfiguration);
method public void setWindowingMode(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -220,6 +222,7 @@
field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3
field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1
field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int ROTATION_UNDEFINED = -1; // 0xffffffff
field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 6547b3a..a3cd8a3 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -205,10 +205,6 @@
],
srcs: [
- // atom_field_options.proto needs field_options.proto, but that is
- // not included in libprotobuf-cpp-lite, so compile it here.
- ":libprotobuf-internal-protos",
-
"src/atom_field_options.proto",
"src/atoms.proto",
"src/stats_log.proto",
@@ -263,11 +259,11 @@
],
proto: {
- type: "lite",
+ type: "full",
include_dirs: ["external/protobuf/src"],
},
- shared_libs: ["libprotobuf-cpp-lite"],
+ shared_libs: ["libprotobuf-cpp-full"],
}
@@ -280,10 +276,6 @@
defaults: ["statsd_defaults"],
srcs: [
- // atom_field_options.proto needs field_options.proto, but that is
- // not included in libprotobuf-cpp-lite, so compile it here.
- ":libprotobuf-internal-protos",
-
"src/atom_field_options.proto",
"src/atoms.proto",
"src/stats_log.proto",
@@ -298,7 +290,7 @@
],
proto: {
- type: "lite",
+ type: "full",
include_dirs: ["external/protobuf/src"],
},
@@ -320,7 +312,7 @@
shared_libs: [
"libgtest_prod",
"libstatslog",
- "libprotobuf-cpp-lite",
+ "libprotobuf-cpp-full",
],
}
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index fc1a61c..80ed807 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "FieldValue.h"
#include "HashableDimensionKey.h"
+#include "math.h"
namespace android {
namespace os {
@@ -174,6 +175,25 @@
}
}
+bool Value::isZero() const {
+ switch (type) {
+ case INT:
+ return int_value == 0;
+ case LONG:
+ return long_value == 0;
+ case FLOAT:
+ return fabs(float_value) <= std::numeric_limits<float>::epsilon();
+ case DOUBLE:
+ return fabs(double_value) <= std::numeric_limits<double>::epsilon();
+ case STRING:
+ return str_value.size() == 0;
+ case STORAGE:
+ return storage_value.size() == 0;
+ default:
+ return false;
+ }
+}
+
bool Value::operator==(const Value& that) const {
if (type != that.getType()) return false;
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 77163f9..a5d00ac 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -331,6 +331,8 @@
std::string toString() const;
+ bool isZero() const;
+
Type getType() const {
return type;
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 12e2560..f0f5993 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -272,26 +272,25 @@
}
/*
- * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ * onDumpReport dumps serialized ConfigMetricsReportList into proto.
*/
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
- vector<uint8_t>* outData) {
+ ProtoOutputStream* proto) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- ProtoOutputStream proto;
-
// Start of ConfigKey.
- uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
- proto.end(configKeyToken);
+ uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
+ proto->end(configKeyToken);
// End of ConfigKey.
// Then, check stats-data directory to see there's any file containing
// ConfigMetricsReport from previous shutdowns to concatenate to reports.
- StorageManager::appendConfigMetricsReport(key, &proto);
+ StorageManager::appendConfigMetricsReport(key, proto);
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
@@ -301,14 +300,27 @@
// Start of ConfigMetricsReport (reports).
uint64_t reportsToken =
- proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
+ proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
- dumpReportReason, &proto);
- proto.end(reportsToken);
+ erase_data, dumpReportReason, proto);
+ proto->end(reportsToken);
// End of ConfigMetricsReport (reports).
} else {
ALOGW("Config source %s does not exist", key.ToString().c_str());
}
+}
+
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
+ const bool erase_data,
+ const DumpReportReason dumpReportReason,
+ vector<uint8_t>* outData) {
+ ProtoOutputStream proto;
+ onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ dumpReportReason, &proto);
if (outData != nullptr) {
outData->clear();
@@ -332,6 +344,7 @@
void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
ProtoOutputStream* proto) {
// We already checked whether key exists in mMetricsManagers in
@@ -348,7 +361,7 @@
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
- &str_set, proto);
+ erase_data, &str_set, proto);
// Fill in UidMap if there is at least one metric to report.
// This skips the uid map if it's an empty config.
@@ -479,7 +492,7 @@
}
ProtoOutputStream proto;
onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
- dumpReportReason, &proto);
+ true /* erase_data */, dumpReportReason, &proto);
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
android::base::unique_fd fd(open(file_name.c_str(),
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 3e8b9b8..ecfd819 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -61,8 +61,11 @@
size_t GetMetricsSize(const ConfigKey& key) const;
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
- const bool include_current_partial_bucket,
+ const bool include_current_partial_bucket, const bool erase_data,
const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
+ void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket, const bool erase_data,
+ const DumpReportReason dumpReportReason, ProtoOutputStream* proto);
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
void onAnomalyAlarmFired(
@@ -141,6 +144,7 @@
void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
util::ProtoOutputStream* proto);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ce28777..27685fc 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -46,6 +46,8 @@
using namespace android;
using android::base::StringPrintf;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_MESSAGE;
namespace android {
namespace os {
@@ -58,6 +60,9 @@
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+// for StatsDataDumpProto
+const int FIELD_ID_REPORTS_LIST = 1;
+
static binder::Status ok() {
return binder::Status::ok();
}
@@ -224,31 +229,48 @@
}
/**
- * Write debugging data about statsd.
+ * Write data from statsd.
+ * Format for statsdStats: adb shell dumpsys stats --metadata [-v] [--proto]
+ * Format for data report: adb shell dumpsys stats [anything other than --metadata] [--proto]
+ * Anything ending in --proto will be in proto format.
+ * Anything without --metadata as the first argument will be report information.
+ * (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
+ * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
if (!checkCallingPermission(String16(kPermissionDump))) {
return PERMISSION_DENIED;
}
-
- bool verbose = false;
- bool proto = false;
- if (args.size() > 0 && !args[0].compare(String16("-v"))) {
- verbose = true;
+ int lastArg = args.size() - 1;
+ bool asProto = false;
+ if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument
+ asProto = true;
+ lastArg--;
}
- if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) {
- proto = true;
+ if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument
+ // Request is to dump statsd stats.
+ bool verbose = false;
+ if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) {
+ verbose = true;
+ lastArg--;
+ }
+ dumpStatsdStats(fd, verbose, asProto);
+ } else {
+ // Request is to dump statsd report data.
+ if (asProto) {
+ dumpIncidentSection(fd);
+ } else {
+ dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n");
+ }
}
- dump_impl(fd, verbose, proto);
-
return NO_ERROR;
}
/**
* Write debugging data about statsd in text or proto format.
*/
-void StatsService::dump_impl(int out, bool verbose, bool proto) {
+void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) {
if (proto) {
vector<uint8_t> data;
StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
@@ -262,6 +284,22 @@
}
/**
+ * Write stats report data in StatsDataDumpProto incident section format.
+ */
+void StatsService::dumpIncidentSection(int out) {
+ ProtoOutputStream proto;
+ for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
+ uint64_t reportsListToken =
+ proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
+ mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
+ true /* includeCurrentBucket */, false /* erase_data */,
+ ADB_DUMP, &proto);
+ proto.end(reportsListToken);
+ proto.flush(out);
+ }
+}
+
+/**
* Implementation of the adb shell cmd stats command.
*/
status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
@@ -283,7 +321,7 @@
}
if (!args[0].compare(String8("dump-report"))) {
- return cmd_dump_report(out, err, args);
+ return cmd_dump_report(out, args);
}
if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
@@ -546,7 +584,7 @@
return UNKNOWN_ERROR;
}
-status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
+status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
if (mProcessor != nullptr) {
int argCount = args.size();
bool good = false;
@@ -589,14 +627,13 @@
if (good) {
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
- includeCurrentBucket, ADB_DUMP, &data);
+ includeCurrentBucket, true /* erase_data */, ADB_DUMP, &data);
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
dprintf(out, "%c", data[i]);
}
} else {
- dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
- dprintf(out, "See the StatsLogReport in logcat...\n");
+ dprintf(out, "Non-proto stats data dump not currently supported.\n");
}
return android::OK;
} else {
@@ -888,7 +925,7 @@
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
ConfigKey configKey(ipc->getCallingUid(), key);
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
- GET_DATA_CALLED, output);
+ true /* erase_data */, GET_DATA_CALLED, output);
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index cbf3429..4a5f05f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -213,9 +213,14 @@
uint32_t serial);
/**
- * Text or proto output of dumpsys.
+ * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto.
*/
- void dump_impl(int outFd, bool verbose, bool proto);
+ void dumpIncidentSection(int outFd);
+
+ /**
+ * Text or proto output of statsdStats dumpsys.
+ */
+ void dumpStatsdStats(int outFd, bool verbose, bool proto);
/**
* Print usage information for the commands
@@ -240,7 +245,7 @@
/**
* Print the event log.
*/
- status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
+ status_t cmd_dump_report(int outFd, const Vector<String8>& args);
/**
* Print the mapping of uids to package names.
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 13ab844..ee111cd 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -24,7 +24,6 @@
#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
-#include <inttypes.h>
#include <statslog.h>
#include <time.h>
@@ -224,7 +223,7 @@
}
if (!mSubscriptions.empty()) {
- ALOGI("An anomaly (%" PRId64 ") %s has occurred! Informing subscribers.",
+ ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
mAlert.id(), key.toString().c_str());
informSubscribers(key);
} else {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index d2919c5..a0d77d6 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -362,11 +362,17 @@
lock_guard<std::mutex> lock(mLock);
auto& pullStats = mPulledAtomStats[pullAtomId];
pullStats.maxPullDelayNs = std::max(pullStats.maxPullDelayNs, pullDelayNs);
- pullStats.avgPullDelayNs = (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) /
- (pullStats.numPullDelay + 1);
+ pullStats.avgPullDelayNs =
+ (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) /
+ (pullStats.numPullDelay + 1);
pullStats.numPullDelay += 1;
}
+void StatsdStats::notePullDataError(int pullAtomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[pullAtomId].dataError++;
+}
+
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
@@ -422,6 +428,7 @@
pullStats.second.avgPullDelayNs = 0;
pullStats.second.maxPullDelayNs = 0;
pullStats.second.numPullDelay = 0;
+ pullStats.second.dataError = 0;
}
}
@@ -530,11 +537,11 @@
dprintf(out,
"Atom %d->(total pull)%ld, (pull from cache)%ld, (min pull interval)%ld, (average "
"pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay nanos)%lld, "
- "(max pull delay nanos)%lld\n",
+ "(max pull delay nanos)%lld, (data error)%ld\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs,
(long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs,
- (long long)pair.second.maxPullDelayNs);
+ (long long)pair.second.maxPullDelayNs, pair.second.dataError);
}
if (mAnomalyAlarmRegisteredStats > 0) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 777d865..2008abd 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -279,6 +279,11 @@
void notePullFromCache(int pullAtomId);
/*
+ * Notify data error for pulled atom.
+ */
+ void notePullDataError(int pullAtomId);
+
+ /*
* Records time for actual pulling, not including those served from cache and not including
* statsd processing delays.
*/
@@ -329,6 +334,7 @@
int64_t avgPullDelayNs = 0;
int64_t maxPullDelayNs = 0;
long numPullDelay = 0;
+ long dataError = 0;
} PulledAtomStats;
private:
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 6b8c12a..eddc86e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -82,7 +82,9 @@
// Create the service
gStatsService = new StatsService(looper);
- if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
+ if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
+ != 0) {
ALOGE("Failed to add service as AIDL service");
return -1;
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index bd94800..5ca8814 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -143,6 +143,7 @@
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -230,7 +231,9 @@
protoOutput->end(protoToken);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ }
}
void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 39d4ae2..1ac44264 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -56,6 +56,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index dd3402d..35deffe 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -453,6 +453,7 @@
void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -541,7 +542,9 @@
}
protoOutput->end(protoToken);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ }
}
void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 12addb8..1b830a3 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -63,6 +63,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index afd8ec2..a18e406 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -105,6 +105,7 @@
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (mProto->size() <= 0) {
@@ -120,7 +121,9 @@
protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
- mProto->clear();
+ if (erase_data) {
+ mProto->clear();
+ }
}
void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 7f7aa37..96adfdd 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -47,6 +47,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index f5a16e9..05103a9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -182,6 +182,7 @@
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("Gauge metric %lld report now...", (long long)mMetricId);
@@ -226,7 +227,6 @@
(long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
- mSkippedBuckets.clear();
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
@@ -304,7 +304,11 @@
}
protoOutput->end(protoToken);
- mPastBuckets.clear();
+
+ if (erase_data) {
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+ }
}
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 99827bb..5866139 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -94,6 +94,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index b21fd50..127cbbd 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -133,10 +133,12 @@
// This method clears all the past buckets.
void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, str_set, protoOutput);
+ return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
+ str_set, protoOutput);
}
void clearPastBuckets(const int64_t dumpTimeNs) {
@@ -210,6 +212,7 @@
const int64_t eventTime) = 0;
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) = 0;
virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index f85ba1f..4244d5b 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -197,6 +197,7 @@
void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
@@ -206,11 +207,11 @@
uint64_t token = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
if (mHashStringsInReport) {
- producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
- protoOutput);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ str_set, protoOutput);
} else {
- producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, nullptr,
- protoOutput);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ nullptr, protoOutput);
}
protoOutput->end(token);
} else {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 649222ff..a4672b6 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -107,6 +107,7 @@
virtual void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 192a54b..c8b1cf0 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -92,7 +92,9 @@
: StatsdStats::kDimensionKeySizeHardLimit),
mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()),
mAggregationType(metric.aggregation_type()),
- mValueType(metric.aggregation_type() == ValueMetric::AVG ? DOUBLE : LONG) {
+ mUseDiff(metric.has_use_diff() ? metric.use_diff() : (mIsPulled ? true : false)),
+ mValueDirection(metric.value_direction()),
+ mSkipZeroDiffOutput(metric.skip_zero_diff_output()) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -125,24 +127,25 @@
}
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
- HasPositionALL(metric.dimensions_in_condition());
+ HasPositionALL(metric.dimensions_in_condition());
flushIfNeededLocked(startTimeNs);
- // Kicks off the puller immediately.
+
if (mIsPulled) {
mPullerManager->RegisterReceiver(mPullTagId, this, getCurrentBucketEndTimeNs(),
mBucketSizeNs);
}
- // TODO: Only do this for partial buckets like first bucket. All other buckets should use
+ // Only do this for partial buckets like first bucket. All other buckets should use
// flushIfNeeded to adjust start and end to bucket boundaries.
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
- if (mIsPulled) {
+ // Kicks off the puller immediately if condition is true and diff based.
+ if (mIsPulled && mCondition && mUseDiff) {
pullLocked(startTimeNs);
}
- VLOG("value metric %lld created. bucket size %lld start_time: %lld",
- (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs);
+ VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
+ (long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
ValueMetricProducer::~ValueMetricProducer() {
@@ -170,6 +173,7 @@
void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
@@ -187,14 +191,14 @@
// Fills the dimension path if not slicing by ALL.
if (!mSliceByPositionALL) {
if (!mDimensionsInWhat.empty()) {
- uint64_t dimenPathToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+ uint64_t dimenPathToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
protoOutput->end(dimenPathToken);
}
if (!mDimensionsInCondition.empty()) {
- uint64_t dimenPathToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+ uint64_t dimenPathToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
protoOutput->end(dimenPathToken);
}
@@ -211,7 +215,6 @@
(long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
- mSkippedBuckets.clear();
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
@@ -221,15 +224,15 @@
// First fill dimension.
if (mSliceByPositionALL) {
- uint64_t dimensionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+ uint64_t dimensionToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
protoOutput->end(dimensionToken);
if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
- str_set, protoOutput);
+ uint64_t dimensionInConditionToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set,
+ protoOutput);
protoOutput->end(dimensionInConditionToken);
}
} else {
@@ -237,8 +240,8 @@
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
if (dimensionKey.hasDimensionKeyInCondition()) {
writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
- FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
- str_set, protoOutput);
+ FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set,
+ protoOutput);
}
}
@@ -256,28 +259,34 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
(long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
}
- if (mValueType == LONG) {
+ if (bucket.value.getType() == LONG) {
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_LONG,
- (long long)bucket.mValueLong);
+ (long long)bucket.value.long_value);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.value.long_value);
+ } else if (bucket.value.getType() == DOUBLE) {
+ protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE,
+ bucket.value.double_value);
+ VLOG("\t bucket [%lld - %lld] count: %.2f", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, bucket.value.double_value);
} else {
- protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE, bucket.mValueDouble);
+ VLOG("Wrong value type for ValueMetric output: %d", bucket.value.getType());
}
protoOutput->end(bucketInfoToken);
- VLOG("\t bucket [%lld - %lld] count: %lld, %.2f", (long long)bucket.mBucketStartNs,
- (long long)bucket.mBucketEndNs, (long long)bucket.mValueLong, bucket.mValueDouble);
}
protoOutput->end(wrapperToken);
}
protoOutput->end(protoToken);
VLOG("metric %lld dump report now...", (long long)mMetricId);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+ }
}
void ValueMetricProducer::onConditionChangedLocked(const bool condition,
const int64_t eventTimeNs) {
- mCondition = condition;
-
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
@@ -286,9 +295,19 @@
flushIfNeededLocked(eventTimeNs);
- if (mIsPulled) {
+ // Pull on condition changes.
+ if (mIsPulled && (mCondition != condition)) {
pullLocked(eventTimeNs);
}
+
+ // when condition change from true to false, clear diff base
+ if (mUseDiff && mCondition && !condition) {
+ for (auto& slice : mCurrentSlicedBucket) {
+ slice.second.hasBase = false;
+ }
+ }
+
+ mCondition = condition;
}
void ValueMetricProducer::pullLocked(const int64_t timestampNs) {
@@ -303,30 +322,33 @@
}
}
+int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
+ return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
+}
+
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mCondition == true || mConditionTrackerIndex < 0) {
+ if (mCondition) {
if (allData.size() == 0) {
return;
}
// For scheduled pulled data, the effective event time is snap to the nearest
- // bucket boundary to make bucket finalize.
+ // bucket end. In the case of waking up from a deep sleep state, we will
+ // attribute to the previous bucket end. If the sleep was long but not very long, we
+ // will be in the immediate next bucket. Previous bucket may get a larger number as
+ // we pull at a later time than real bucket end.
+ // If the sleep was very long, we skip more than one bucket before sleep. In this case,
+ // if the diff base will be cleared and this new data will serve as new diff base.
int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
- int64_t eventTime = mTimeBaseNs +
- ((realEventTime - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
-
- // close the end of the bucket
- mCondition = false;
- for (const auto& data : allData) {
- data->setElapsedTimestampNs(eventTime - 1);
- onMatchedLogEventLocked(0, *data);
+ int64_t bucketEndTime = calcPreviousBucketEndTime(realEventTime) - 1;
+ if (bucketEndTime < mCurrentBucketStartTimeNs) {
+ VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime,
+ (long long)mCurrentBucketStartTimeNs);
+ return;
}
-
- // start a new bucket
- mCondition = true;
for (const auto& data : allData) {
- data->setElapsedTimestampNs(eventTime);
+ data->setElapsedTimestampNs(bucketEndTime);
onMatchedLogEventLocked(0, *data);
}
}
@@ -360,8 +382,8 @@
StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > mDimensionHardLimit) {
- ALOGE("ValueMetric %lld dropping data for dimension key %s",
- (long long)mMetricId, newKey.toString().c_str());
+ ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
+ newKey.toString().c_str());
return true;
}
}
@@ -390,10 +412,10 @@
return v;
}
-void ValueMetricProducer::onMatchedLogEventInternalLocked(
- const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) {
+void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIndex,
+ const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKey,
+ bool condition, const LogEvent& event) {
int64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
@@ -403,6 +425,14 @@
flushIfNeededLocked(eventTimeNs);
+ // For pulled data, we already check condition when we decide to pull or
+ // in onDataPulled. So take all of them.
+ // For pushed data, just check condition.
+ if (!(mIsPulled || condition)) {
+ VLOG("ValueMetric skip event because condition is false");
+ return;
+ }
+
if (hitGuardRailLocked(eventKey)) {
return;
}
@@ -415,71 +445,70 @@
}
Value value = getDoubleOrLong(event.getValues()[mField - 1].mValue);
- Value diff;
- bool hasDiff = false;
- if (mIsPulled) {
- // Always require condition for pulled events. In the case of no condition, only pull
- // on bucket boundaries, in which we fake condition changes.
- if (mCondition == true) {
- if (!interval.startUpdated) {
- interval.start = value;
- interval.startUpdated = true;
- } else {
- // Skip it if there is already value recorded for the start. Happens when puller
- // takes too long to finish. In this case we take the previous value.
- VLOG("Already recorded value for this dimension %s", eventKey.toString().c_str());
- }
- } else {
- // Generally we expect value to be monotonically increasing.
- // If not, take absolute value or drop it, based on config.
- if (interval.startUpdated) {
- if (value >= interval.start) {
- diff = (value - interval.start);
- hasDiff = true;
+ if (mUseDiff) {
+ // no base. just update base and return.
+ if (!interval.hasBase) {
+ interval.base = value;
+ interval.hasBase = true;
+ return;
+ }
+ Value diff;
+ switch (mValueDirection) {
+ case ValueMetric::INCREASING:
+ if (value >= interval.base) {
+ diff = value - interval.base;
+ } else if (mUseAbsoluteValueOnReset) {
+ diff = value;
} else {
- if (mUseAbsoluteValueOnReset) {
- diff = value;
- hasDiff = true;
- } else {
- VLOG("Dropping data for atom %d, prev: %s, now: %s", mPullTagId,
- interval.start.toString().c_str(), value.toString().c_str());
- }
+ VLOG("Unexpected decreasing value");
+ StatsdStats::getInstance().notePullDataError(mPullTagId);
+ interval.base = value;
+ return;
}
- interval.startUpdated = false;
- } else {
- VLOG("No start for matching end %s", value.toString().c_str());
- }
+ break;
+ case ValueMetric::DECREASING:
+ if (interval.base >= value) {
+ diff = interval.base - value;
+ } else if (mUseAbsoluteValueOnReset) {
+ diff = value;
+ } else {
+ VLOG("Unexpected increasing value");
+ StatsdStats::getInstance().notePullDataError(mPullTagId);
+ interval.base = value;
+ return;
+ }
+ break;
+ case ValueMetric::ANY:
+ diff = value - interval.base;
+ break;
+ default:
+ break;
+ }
+ interval.base = value;
+ value = diff;
+ }
+
+ if (interval.hasValue) {
+ switch (mAggregationType) {
+ case ValueMetric::SUM:
+ // for AVG, we add up and take average when flushing the bucket
+ case ValueMetric::AVG:
+ interval.value += value;
+ break;
+ case ValueMetric::MIN:
+ interval.value = std::min(value, interval.value);
+ break;
+ case ValueMetric::MAX:
+ interval.value = std::max(value, interval.value);
+ break;
+ default:
+ break;
}
} else {
- // for pushed events, only aggregate when sliced condition is true
- if (condition == true || mConditionTrackerIndex < 0) {
- diff = value;
- hasDiff = true;
- }
+ interval.value = value;
+ interval.hasValue = true;
}
- if (hasDiff) {
- if (interval.hasValue) {
- switch (mAggregationType) {
- case ValueMetric::SUM:
- // for AVG, we add up and take average when flushing the bucket
- case ValueMetric::AVG:
- interval.value += diff;
- break;
- case ValueMetric::MIN:
- interval.value = diff < interval.value ? diff : interval.value;
- break;
- case ValueMetric::MAX:
- interval.value = diff > interval.value ? diff : interval.value;
- break;
- default:
- break;
- }
- } else {
- interval.value = diff;
- interval.hasValue = true;
- }
- interval.sampleSize += 1;
- }
+ interval.sampleSize += 1;
// TODO: propgate proper values down stream when anomaly support doubles
long wholeBucketVal = interval.value.long_value;
@@ -509,6 +538,10 @@
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+ // take base again in future good bucket.
+ for (auto& slice : mCurrentSlicedBucket) {
+ slice.second.hasBase = false;
+ }
}
VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
@@ -531,8 +564,18 @@
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
if (slice.second.hasValue) {
- info.mValueLong = slice.second.value.long_value;
- info.mValueDouble = (double)slice.second.value.long_value / slice.second.sampleSize;
+ // skip the output if the diff is zero
+ if (mSkipZeroDiffOutput && mUseDiff && slice.second.value.isZero()) {
+ continue;
+ }
+ if (mAggregationType != ValueMetric::AVG) {
+ info.value = slice.second.value;
+ } else {
+ double sum = slice.second.value.type == LONG
+ ? (double)slice.second.value.long_value
+ : slice.second.value.double_value;
+ info.value.setDouble(sum / slice.second.sampleSize);
+ }
// it will auto create new vector of ValuebucketInfo if the key is not found.
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(info);
@@ -578,7 +621,10 @@
}
// Reset counters
- mCurrentSlicedBucket.clear();
+ for (auto& slice : mCurrentSlicedBucket) {
+ slice.second.hasValue = false;
+ slice.second.sampleSize = 0;
+ }
}
size_t ValueMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b2f0b6f..3416afe 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -34,8 +34,7 @@
struct ValueBucket {
int64_t mBucketStartNs;
int64_t mBucketEndNs;
- int64_t mValueLong;
- double mValueDouble;
+ Value value;
};
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
@@ -54,35 +53,11 @@
void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
const int64_t version) override {
std::lock_guard<std::mutex> lock(mMutex);
-
- if (mIsPulled && (mCondition == true || mConditionTrackerIndex < 0)) {
- vector<shared_ptr<LogEvent>> allData;
- mPullerManager->Pull(mPullTagId, eventTimeNs, &allData);
- if (allData.size() == 0) {
- // This shouldn't happen since this valuemetric is not useful now.
- }
-
- // Pretend the pulled data occurs right before the app upgrade event.
- mCondition = false;
- for (const auto& data : allData) {
- data->setElapsedTimestampNs(eventTimeNs - 1);
- onMatchedLogEventLocked(0, *data);
- }
-
- flushCurrentBucketLocked(eventTimeNs);
- mCurrentBucketStartTimeNs = eventTimeNs;
-
- mCondition = true;
- for (const auto& data : allData) {
- data->setElapsedTimestampNs(eventTimeNs);
- onMatchedLogEventLocked(0, *data);
- }
- } else {
- // For pushed value metric or pulled metric where condition is not true,
- // we simply flush and reset the current bucket start.
- flushCurrentBucketLocked(eventTimeNs);
- mCurrentBucketStartTimeNs = eventTimeNs;
+ if (mIsPulled && mCondition) {
+ pullLocked(eventTimeNs - 1);
}
+ flushCurrentBucketLocked(eventTimeNs);
+ mCurrentBucketStartTimeNs = eventTimeNs;
};
protected:
@@ -94,6 +69,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -116,6 +92,9 @@
void dropDataLocked(const int64_t dropTimeNs) override;
+ // Calculate previous bucket end time based on current time.
+ int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs);
+
sp<StatsPullerManager> mPullerManager;
const FieldMatcher mValueField;
@@ -130,11 +109,10 @@
// internal state of a bucket.
typedef struct {
- // Pulled data always come in pair of <start, end>. This holds the value
- // for start. The diff (end - start) is taken as the real value.
- Value start;
- // Whether the start data point is updated
- bool startUpdated;
+ // Holds current base value of the dimension. Take diff and update if necessary.
+ Value base;
+ // Whether there is a base to diff to.
+ bool hasBase;
// Current value, depending on the aggregation type.
Value value;
// Number of samples collected.
@@ -171,7 +149,11 @@
const ValueMetric::AggregationType mAggregationType;
- const Type mValueType;
+ const bool mUseDiff;
+
+ const ValueMetric::ValueDirection mValueDirection;
+
+ const bool mSkipZeroDiffOutput;
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
@@ -186,13 +168,13 @@
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
- FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3);
FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin);
FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax);
FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg);
FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum);
- FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced);
FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
+ FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
+ FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 4a9b521..136ba07 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -35,8 +35,6 @@
#include "stats_util.h"
#include "statslog.h"
-#include <inttypes.h>
-
using std::set;
using std::string;
using std::unordered_map;
@@ -575,7 +573,7 @@
for (int i = 0; i < config.no_report_metric_size(); ++i) {
const auto no_report_metric = config.no_report_metric(i);
if (metricMap.find(no_report_metric) == metricMap.end()) {
- ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
+ ALOGW("no_report_metric %lld not exist", no_report_metric);
return false;
}
noReportMetricIds.insert(no_report_metric);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 8bfa360..4da3828 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -374,6 +374,7 @@
optional int64 max_pull_time_nanos = 6;
optional int64 average_pull_delay_nanos = 7;
optional int64 max_pull_delay_nanos = 8;
+ optional int64 data_error = 9;
}
repeated PulledAtomStats pulled_atom_stats = 10;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 44fa72e..504c586 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -63,6 +63,7 @@
const int FIELD_ID_MAX_PULL_TIME_NANOS = 6;
const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
+const int FIELD_ID_DATA_ERROR = 9;
namespace {
@@ -446,6 +447,7 @@
(long long)pair.second.avgPullDelayNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
(long long)pair.second.maxPullDelayNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index b8f6850..61f31eb 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -21,6 +21,7 @@
#include "HashableDimensionKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "guardrail/StatsdStats.h"
+#include "statslog.h"
namespace android {
namespace os {
@@ -87,6 +88,10 @@
// Returns the truncated timestamp.
int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs);
+inline bool isPushedAtom(int atomId) {
+ return atomId <= util::kMaxPushedAtomId && atomId > 1;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index d5f81a59..5c46a29 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -270,6 +270,17 @@
optional int64 min_bucket_size_nanos = 10;
optional bool use_absolute_value_on_reset = 11 [default = false];
+
+ optional bool use_diff = 12;
+
+ enum ValueDirection {
+ INCREASING = 1;
+ DECREASING = 2;
+ ANY = 3;
+ }
+ optional ValueDirection value_direction = 13 [default = INCREASING];
+
+ optional bool skip_zero_diff_output = 14 [default = true];
}
message Alert {
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index b6f635c..8864252 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -168,7 +168,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -197,7 +197,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -227,7 +227,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a8fcc81..5c47af7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -144,8 +144,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -290,8 +290,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index 75bd40f..a8914da 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -212,7 +212,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -548,7 +548,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -798,7 +798,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index c5a8a2e..621b6ed 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -130,8 +130,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -346,8 +346,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -530,8 +530,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -732,8 +732,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 5bcc9ee..9f8acaf 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -143,7 +143,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -438,7 +438,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -658,8 +658,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index d7b9c11..2d090e0 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -123,8 +123,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -246,8 +246,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -350,8 +350,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 5c1ef01..71afedf 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -149,8 +149,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 0f13a4a..29e86f3 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -167,8 +167,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index cc8894b..9349c85 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -199,8 +199,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -318,8 +318,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 67acd61..3cb553f 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
- ADB_DUMP, &output);
+ true /* erase_data */, ADB_DUMP, &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index f2e8f58..095b401 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -49,6 +49,7 @@
CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
valueMetric->set_bucket(FIVE_MINUTES);
valueMetric->set_use_absolute_value_on_reset(true);
+ valueMetric->set_skip_zero_diff_output(false);
return config;
}
@@ -117,8 +118,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -224,8 +225,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index b9d0c62..6d1317c 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -127,8 +127,8 @@
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -164,8 +164,8 @@
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -215,8 +215,8 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -248,8 +248,8 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -277,8 +277,8 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -323,8 +323,8 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 57aab97..ffa07081 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -47,7 +47,35 @@
const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
-const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+double epsilon = 0.001;
+
+/*
+ * Tests that the first bucket works correctly
+ */
+TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+
+ int64_t startTimeBase = 11;
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ // statsd started long ago.
+ // The metric starts in the middle of the bucket
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ -1, startTimeBase, 22, pullerManager);
+
+ EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
+ EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
+ EXPECT_EQ(60 * NS_PER_SEC + startTimeBase,
+ valueProducer.calcPreviousBucketEndTime(2 * 60 * NS_PER_SEC));
+ EXPECT_EQ(2 * 60 * NS_PER_SEC + startTimeBase,
+ valueProducer.calcPreviousBucketEndTime(3 * 60 * NS_PER_SEC));
+}
/*
* Tests that the first bucket works correctly
@@ -90,7 +118,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(tagId);
event->write(3);
event->init();
@@ -114,12 +142,11 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:true sum:0 start:11
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(11, curInterval.start.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(8, curInterval.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -131,12 +158,14 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // tartUpdated:false sum:12
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(23, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(12, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -147,12 +176,14 @@
valueProducer.onDataPulled(allData);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:false sum:12
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(13, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
/*
@@ -170,7 +201,7 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
@@ -188,9 +219,9 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(11, curInterval.start.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
allData.clear();
@@ -203,11 +234,11 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(10, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -218,11 +249,13 @@
valueProducer.onDataPulled(allData);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(26, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
/*
@@ -257,9 +290,9 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(11, curInterval.start.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
allData.clear();
@@ -272,7 +305,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
@@ -285,11 +319,11 @@
valueProducer.onDataPulled(allData);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(26, curInterval.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
}
/*
@@ -309,21 +343,10 @@
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- // should not take effect
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
- event->write(tagId);
- event->write(3);
- event->init();
- data->push_back(event);
- return true;
- }))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
- data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
event->write(100);
event->init();
@@ -333,7 +356,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
event->write(120);
event->init();
@@ -349,8 +372,8 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
// startUpdated:false sum:0 start:100
- EXPECT_EQ(100, curInterval.start.long_value);
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(100, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
@@ -366,20 +389,20 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:false sum:0 start:110
- EXPECT_EQ(110, curInterval.start.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(110, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:false sum:0 start:110
+ EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
- EXPECT_EQ(false, curInterval.startUpdated);
+ EXPECT_EQ(false, curInterval.hasBase);
}
TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
@@ -401,9 +424,9 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ valueProducer.notifyAppUpgrade(bucketStartTimeNs + 150, "ANY.APP", 1, 1);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
event2->write(1);
@@ -411,7 +434,7 @@
event2->init();
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
// Next value should create a new bucket.
shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
@@ -435,11 +458,11 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Return(false))
+ .WillOnce(Return(true))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 149);
event->write(tagId);
event->write(120);
event->init();
@@ -451,7 +474,7 @@
vector<shared_ptr<LogEvent>> allData;
allData.clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
event->write(100);
event->init();
@@ -460,21 +483,21 @@
valueProducer.onDataPulled(allData);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
- EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong);
+ EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
allData.clear();
- event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
event->write(tagId);
event->write(150);
event->init();
allData.push_back(event);
valueProducer.onDataPulled(allData);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
- EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValueLong);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
}
TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
@@ -490,11 +513,10 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Return(false))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
event->write(tagId);
event->write(100);
event->init();
@@ -504,7 +526,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs - 100);
event->write(tagId);
event->write(120);
event->init();
@@ -523,7 +545,7 @@
EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
- EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong);
+ EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value);
EXPECT_FALSE(valueProducer.mCondition);
}
@@ -565,7 +587,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -587,9 +609,7 @@
event1->init();
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has 1 slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
@@ -600,6 +620,7 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
EXPECT_EQ(20, curInterval.value.long_value);
@@ -629,7 +650,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -727,7 +748,7 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
@@ -747,9 +768,9 @@
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
// startUpdated:true sum:0 start:11
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(11, curInterval.start.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// pull 2 at correct time
@@ -764,11 +785,11 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
// tartUpdated:false sum:12
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(23, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(12, curInterval.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// pull 3 come late.
// The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -784,12 +805,12 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
// startUpdated:false sum:12
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(36, curInterval.start.long_value);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
/*
@@ -810,12 +831,11 @@
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Return(false))
// condition becomes true
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
event->write(100);
event->init();
@@ -826,7 +846,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
event->write(120);
event->init();
@@ -841,17 +861,17 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:false sum:0 start:100
- EXPECT_EQ(100, curInterval.start.long_value);
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(100, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// pull on bucket boundary come late, condition change happens before it
valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// Now the alarm is delivered.
@@ -866,8 +886,9 @@
valueProducer.onDataPulled(allData);
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
}
@@ -889,12 +910,11 @@
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Return(false))
// condition becomes true
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
event->write(100);
event->init();
@@ -905,7 +925,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
event->write(120);
event->init();
@@ -916,7 +936,7 @@
.WillOnce(Invoke([](int tagId, int64_t timeNs,
vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30);
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 25);
event->write(tagId);
event->write(130);
event->init();
@@ -932,24 +952,26 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
// startUpdated:false sum:0 start:100
- EXPECT_EQ(100, curInterval.start.long_value);
- EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(100, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// pull on bucket boundary come late, condition change happens before it
valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// condition changed to true again, before the pull alarm is delivered
valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25);
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(130, curInterval.start.long_value);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(130, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
// Now the alarm is delivered, but it is considered late, it has no effect
@@ -963,89 +985,10 @@
valueProducer.onDataPulled(allData);
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(130, curInterval.start.long_value);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-}
-
-/*
- * Test pulled event with non sliced condition. The pull on boundary come late because the puller is
- * very slow.
- */
-TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
-
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Return(false))
- // condition becomes true
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
- data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
- event->write(tagId);
- event->write(100);
- event->init();
- data->push_back(event);
- return true;
- }))
- // condition becomes false
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
- data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20);
- event->write(tagId);
- event->write(120);
- event->init();
- data->push_back(event);
- return true;
- }));
-
- ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
- bucketStartTimeNs, pullerManager);
- valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
-
- // has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- // startUpdated:false sum:0 start:100
- EXPECT_EQ(100, curInterval.start.long_value);
- EXPECT_EQ(true, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-
- // pull on bucket boundary come late, condition change happens before it.
- // But puller is very slow in this one, so the data come after bucket finish
- valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
-
- // Alarm is delivered in time, but the pull is very slow, and pullers are called in order,
- // so this one comes even later
- vector<shared_ptr<LogEvent>> allData;
- allData.clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30);
- event->write(1);
- event->write(110);
- event->init();
- allData.push_back(event);
- valueProducer.onDataPulled(allData);
-
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(false, curInterval.startUpdated);
- EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(130, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
}
@@ -1088,7 +1031,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1130,7 +1073,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
@@ -1175,7 +1118,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(12.5, valueProducer.mPastBuckets.begin()->second.back().mValueDouble);
+ EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().value.double_value - 12.5) < epsilon);
}
TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
@@ -1217,67 +1160,75 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
-TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced) {
- string slicedConditionName = "UID";
- const int conditionTagId = 2;
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
ValueMetric metric;
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(1);
- metric.set_aggregation_type(ValueMetric::SUM);
-
- metric.set_condition(StringToId(slicedConditionName));
- MetricConditionLink* link = metric.add_links();
- link->set_condition(StringToId(slicedConditionName));
- buildSimpleAtomFieldMatcher(tagId, 2, link->mutable_fields_in_what());
- buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-
- LogEvent event1(tagId, bucketStartTimeNs + 10);
- event1.write(10); // value
- event1.write("111"); // uid
- event1.init();
- ConditionKey key1;
- key1[StringToId(slicedConditionName)] =
- {getMockedDimensionKey(conditionTagId, 2, "111")};
-
- LogEvent event2(tagId, bucketStartTimeNs + 20);
- event2.write(15);
- event2.write("222");
- event2.init();
- ConditionKey key2;
- key2[StringToId(slicedConditionName)] =
- {getMockedDimensionKey(conditionTagId, 2, "222")};
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_aggregation_type(ValueMetric::MIN);
+ metric.set_use_diff(true);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
- EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
-
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event1->write(1);
+ event1->write(10);
+ event1->init();
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+ event2->write(1);
+ event2->write(15);
+ event2->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+ // has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
- EXPECT_EQ(15, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(5, curInterval.value.long_value);
+
+ // no change in data.
+ shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+ event3->write(1);
+ event3->write(15);
+ event3->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(15, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
+ event4->write(1);
+ event4->write(15);
+ event4->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(15, curInterval.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(15, valueProducer.mPastBuckets.begin()->second.back().mValueLong);
+ EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().value.long_value);
}
} // namespace statsd
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index ff436f1..e5764f04 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -24213,7 +24213,90 @@
HSPLandroid/icu/util/CharsTrie;->next(I)Landroid/icu/util/BytesTrie$Result;
HSPLandroid/icu/util/CharsTrie;->nextImpl(II)Landroid/icu/util/BytesTrie$Result;
HSPLandroid/icu/util/CharsTrie;->readValue(Ljava/lang/CharSequence;II)I
-HSPLandroid/icu/util/Currency$1;-><init>()V
+HSPLandroid/icu/util/CodePointTrie$Small8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small8;
+HSPLandroid/icu/util/CodePointTrie$Small32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small32;
+HSPLandroid/icu/util/CodePointTrie$Small16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small16;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast8;
+HSPLandroid/icu/util/CodePointTrie$Fast8;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast8;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast32;
+HSPLandroid/icu/util/CodePointTrie$Fast32;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast32;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast16;
+HSPLandroid/icu/util/CodePointTrie$Fast16;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->get(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast16;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small;
+HSPLandroid/icu/util/CodePointTrie$Small;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Small;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Small;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast;
+HSPLandroid/icu/util/CodePointTrie$Fast;->bmpGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Fast;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Fast;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;
+HSPLandroid/icu/util/CodePointTrie$Fast;->suppGet(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data8;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data8;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data32;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data32;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data16;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data16;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getDataLength()I
+HSPLandroid/icu/util/CodePointTrie$Data;->getFromIndex(I)I
+HSPLandroid/icu/util/CodePointTrie$Data;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Data;->write(Ljava/io/DataOutputStream;)I
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$ValueWidth;->values()[Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie$Type;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie$Type;->values()[Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->fromBinary(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/CodePointTrie;->internalSmallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/CodePointTrie;->asciiGet(I)I
+HSPLandroid/icu/util/CodePointTrie;->cpIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->fastIndex(I)I
+HSPLandroid/icu/util/CodePointTrie;->get(I)I
+HSPLandroid/icu/util/CodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointTrie;->getType()Landroid/icu/util/CodePointTrie$Type;
+HSPLandroid/icu/util/CodePointTrie;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth;
+HSPLandroid/icu/util/CodePointTrie;->smallIndex(Landroid/icu/util/CodePointTrie$Type;I)I
+HSPLandroid/icu/util/CodePointTrie;->toBinary(Ljava/io/OutputStream;)I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getCodePoint()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getIndex()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->getValue()I
+HSPLandroid/icu/util/CodePointMap$StringIterator;->next()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->previous()Z
+HSPLandroid/icu/util/CodePointMap$StringIterator;->reset(Ljava/lang/CharSequence;I)V
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->hasNext()Z
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Landroid/icu/util/CodePointMap$Range;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Ljava/lang/Object;
+HSPLandroid/icu/util/CodePointMap$RangeIterator;->remove()V
+HSPLandroid/icu/util/CodePointMap$Range;->access$000(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$002(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$100(Landroid/icu/util/CodePointMap$Range;)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$102(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->access$202(Landroid/icu/util/CodePointMap$Range;I)I
+HSPLandroid/icu/util/CodePointMap$Range;->getEnd()I
+HSPLandroid/icu/util/CodePointMap$Range;->getStart()I
+HSPLandroid/icu/util/CodePointMap$Range;->getValue()I
+HSPLandroid/icu/util/CodePointMap$Range;->set(III)V
+HSPLandroid/icu/util/CodePointMap$ValueFilter;->apply(I)I
+HSPLandroid/icu/util/CodePointMap$RangeOption;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap$RangeOption;->values()[Landroid/icu/util/CodePointMap$RangeOption;
+HSPLandroid/icu/util/CodePointMap;->get(I)I
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$RangeOption;ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/CodePointMap;->iterator()Ljava/util/Iterator;
+HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;HSPLandroid/icu/util/Currency$1;-><init>()V
HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/String;Ljava/lang/Void;)Landroid/icu/util/Currency;
HSPLandroid/icu/util/Currency$CurrencyUsage;-><init>(Ljava/lang/String;I)V
@@ -24259,6 +24342,61 @@
HSPLandroid/icu/util/MeasureUnit;->equals(Ljava/lang/Object;)Z
HSPLandroid/icu/util/MeasureUnit;->hashCode()I
HSPLandroid/icu/util/MeasureUnit;->internalGetInstance(Ljava/lang/String;Ljava/lang/String;)Landroid/icu/util/MeasureUnit;
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->addEntry([I[CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([III)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([I[C[I[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode(I)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->modulo(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->nextIndex(II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([CIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findAllSameBlock([II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[CI)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([I[II)I
+HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->init(II)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->add(III)V
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findMostUsed()I
+HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findOrAdd(III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->access$000([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$100([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$200([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->access$300([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allValuesSameAs([IIII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->allocDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->build(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clear()V
+HSPLandroid/icu/util/MutableCodePointTrie;->compactData(I[IILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactIndex(ILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactTrie(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->compactWholeDataBlocks(ILandroid/icu/util/MutableCodePointTrie$AllSameBlocks;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->ensureHighStart(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[CII)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([II[III)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->fillBlock(IIII)V
+HSPLandroid/icu/util/MutableCodePointTrie;->findAllSameBlock([IIIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->findHighStart()I
+HSPLandroid/icu/util/MutableCodePointTrie;->findSameBlock([CII[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->fromCodePointMap(Landroid/icu/util/CodePointMap;)Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->getAllSameOverlap([IIII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getDataBlock(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[CII)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([II[III)I
+HSPLandroid/icu/util/MutableCodePointTrie;->isStartOfSomeFastBlock(I[II)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->maskValues(I)V
+HSPLandroid/icu/util/MutableCodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I
+HSPLandroid/icu/util/MutableCodePointTrie;->writeBlock(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->buildImmutable(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Landroid/icu/util/MutableCodePointTrie;
+HSPLandroid/icu/util/MutableCodePointTrie;->clone()Ljava/lang/Object;
+HSPLandroid/icu/util/MutableCodePointTrie;->get(I)I
+HSPLandroid/icu/util/MutableCodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z
+HSPLandroid/icu/util/MutableCodePointTrie;->set(II)V
+HSPLandroid/icu/util/MutableCodePointTrie;->setRange(III)V
HSPLandroid/icu/util/SimpleTimeZone;-><init>(ILjava/lang/String;IIIIIIIIIII)V
HSPLandroid/icu/util/SimpleTimeZone;->clone()Ljava/lang/Object;
HSPLandroid/icu/util/SimpleTimeZone;->cloneAsThawed()Landroid/icu/util/TimeZone;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 43e926f..0d9a393 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1,4 +1,6 @@
Landroid/accessibilityservice/IAccessibilityServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accessibilityservice/IAccessibilityServiceConnection;
+Landroid/accounts/AccountManager$AmsTask;-><init>(Landroid/accounts/AccountManager;Landroid/app/Activity;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V
+Landroid/accounts/AccountManager$Future2Task;-><init>(Landroid/accounts/AccountManager;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V
Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/accounts/IAccountAuthenticator$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/accounts/IAccountAuthenticator$Stub;-><init>()V
@@ -30,6 +32,7 @@
Landroid/app/ActivityManagerNative;-><init>()V
Landroid/app/ActivityThread$AppBindData;-><init>()V
Landroid/app/ActivityThread$CreateServiceData;-><init>()V
+Landroid/app/ActivityThread$H;-><init>(Landroid/app/ActivityThread;)V
Landroid/app/admin/IDevicePolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/admin/IDevicePolicyManager;
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
@@ -212,6 +215,7 @@
Landroid/app/job/IJobService;->stopJob(Landroid/app/job/JobParameters;)V
Landroid/app/PackageDeleteObserver;-><init>()V
Landroid/app/PackageInstallObserver;-><init>()V
+Landroid/app/ReceiverRestrictedContext;-><init>(Landroid/content/Context;)V
Landroid/app/ResourcesManager$ActivityResources;-><init>()V
Landroid/app/ResourcesManager;-><init>()V
Landroid/app/TaskStackListener;-><init>()V
@@ -262,6 +266,7 @@
Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V
Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
+Landroid/content/ContentProviderProxy;->mRemote:Landroid/os/IBinder;
Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -415,9 +420,14 @@
Landroid/content/res/ConfigurationBoundResourceCache;-><init>()V
Landroid/content/res/DrawableCache;-><init>()V
Landroid/content/UndoManager;-><init>()V
+Landroid/database/BulkCursorProxy;->mRemote:Landroid/os/IBinder;
Landroid/database/IContentObserver$Stub;-><init>()V
Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver;
Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V
+Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z
+Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z
+Landroid/filterfw/GraphEnvironment;->addReferences([Ljava/lang/Object;)V
+Landroid/hardware/camera2/utils/HashCodeHelpers;->hashCode([I)I
Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
Landroid/hardware/display/IDisplayManager;->getDisplayInfo(I)Landroid/view/DisplayInfo;
Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -432,6 +442,9 @@
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
Landroid/icu/impl/CurrencyData;-><init>()V
+Landroid/icu/impl/ICUResourceBundle;->getULocale()Landroid/icu/util/ULocale;
+Landroid/icu/impl/ICUResourceBundle;->getWithFallback(Ljava/lang/String;)Landroid/icu/impl/ICUResourceBundle;
+Landroid/icu/impl/IllegalIcuArgumentException;-><init>(Ljava/lang/String;)V
Landroid/icu/text/ArabicShaping;-><init>(I)V
Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
@@ -462,6 +475,8 @@
Landroid/icu/util/UResourceBundle;->getType()I
Landroid/icu/util/UResourceBundleIterator;->hasNext()Z
Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle;
+Landroid/inputmethodservice/IInputMethodSessionWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
+Landroid/inputmethodservice/IInputMethodWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
Landroid/location/ICountryListener$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;-><init>()V
@@ -479,9 +494,11 @@
Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
+Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
+Landroid/media/effect/SingleFilterEffect;-><init>(Landroid/media/effect/EffectContext;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/media/IAudioFocusDispatcher;->dispatchAudioFocusChange(ILjava/lang/String;)V
Landroid/media/IAudioRoutesObserver$Stub;-><init>()V
Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -500,6 +517,7 @@
Landroid/media/IRingtonePlayer;->play(Landroid/os/IBinder;Landroid/net/Uri;Landroid/media/AudioAttributes;FZ)V
Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
Landroid/media/MediaFile;-><init>()V
+Landroid/media/MediaScanner$MyMediaScannerClient;-><init>(Landroid/media/MediaScanner;)V
Landroid/media/projection/IMediaProjectionManager;->hasProjectionPermission(ILjava/lang/String;)Z
Landroid/media/session/ISessionManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/session/ISessionManager;
Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -547,6 +565,7 @@
Landroid/net/MobileLinkQualityInfo;-><init>()V
Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
Landroid/net/nsd/INsdManager;->getMessenger()Landroid/os/Messenger;
+Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
Landroid/net/SntpClient;-><init>()V
Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager;
@@ -637,6 +656,7 @@
Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J
Landroid/os/BatteryStats;->computeBatteryUptime(JI)J
Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J
+Landroid/os/BatteryStats;->dumpLine(Ljava/io/PrintWriter;ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/os/BatteryStats;->getBatteryUptime(J)J
Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
@@ -725,6 +745,7 @@
Landroid/os/Environment;->buildExternalStorageAppFilesDirs(Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/Environment;->buildPaths([Ljava/io/File;[Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
Landroid/os/Environment;->initForCurrentUser()V
@@ -930,6 +951,8 @@
Landroid/os/ServiceManager;->sCache:Ljava/util/Map;
Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
+Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder;
Landroid/os/ServiceSpecificException;-><init>(ILjava/lang/String;)V
Landroid/os/SharedMemory;->getFd()I
Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
@@ -1064,6 +1087,7 @@
Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/String;)V
Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/Throwable;)V
+Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference;
Landroid/R$styleable;->ActionBar:[I
Landroid/R$styleable;->ActionBar_background:I
Landroid/R$styleable;->ActionBar_backgroundSplit:I
@@ -1346,6 +1370,17 @@
Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B
Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I
Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I
+Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V
+Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B
+Landroid/security/keymaster/KeymasterBooleanArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterDateArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterIntArgument;-><init>(II)V
+Landroid/security/keymaster/KeymasterIntArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterIntArgument;->value:I
+Landroid/security/keymaster/KeymasterLongArgument;-><init>(IJ)V
+Landroid/security/keymaster/KeymasterLongArgument;-><init>(ILandroid/os/Parcel;)V
+Landroid/security/keymaster/KeymasterLongArgument;->value:J
Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
@@ -1383,9 +1418,42 @@
Landroid/service/wallpaper/IWallpaperEngine;->setVisibility(Z)V
Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService;
Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
+Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
+Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
+Landroid/telephony/JapanesePhoneNumberFormatter;->format(Landroid/text/Editable;)V
+Landroid/telephony/SmsCbCmasInfo;->getCategory()I
+Landroid/telephony/SmsCbCmasInfo;->getCertainty()I
+Landroid/telephony/SmsCbCmasInfo;->getMessageClass()I
+Landroid/telephony/SmsCbCmasInfo;->getResponseType()I
+Landroid/telephony/SmsCbCmasInfo;->getSeverity()I
+Landroid/telephony/SmsCbCmasInfo;->getUrgency()I
+Landroid/telephony/SmsCbEtwsInfo;->getWarningType()I
+Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;)V
+Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;II)V
+Landroid/telephony/SmsCbLocation;->getCid()I
+Landroid/telephony/SmsCbLocation;->getLac()I
+Landroid/telephony/SmsCbLocation;->getPlmn()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;-><init>(Landroid/os/Parcel;)V
+Landroid/telephony/SmsCbMessage;->getCmasWarningInfo()Landroid/telephony/SmsCbCmasInfo;
+Landroid/telephony/SmsCbMessage;->getEtwsWarningInfo()Landroid/telephony/SmsCbEtwsInfo;
+Landroid/telephony/SmsCbMessage;->getGeographicalScope()I
+Landroid/telephony/SmsCbMessage;->getLanguageCode()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;->getLocation()Landroid/telephony/SmsCbLocation;
+Landroid/telephony/SmsCbMessage;->getMessageBody()Ljava/lang/String;
+Landroid/telephony/SmsCbMessage;->getMessageFormat()I
+Landroid/telephony/SmsCbMessage;->getSerialNumber()I
+Landroid/telephony/SmsCbMessage;->getServiceCategory()I
+Landroid/telephony/SmsCbMessage;->isCmasMessage()Z
+Landroid/telephony/SmsCbMessage;->isEmergencyMessage()Z
Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
+Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
+Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
+Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
+Landroid/test/RepetitiveTest;->numIterations()I
Landroid/util/Singleton;-><init>()V
+Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
+Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfoResult(Landroid/view/accessibility/AccessibilityNodeInfo;I)V
Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfosResult(Ljava/util/List;I)V
Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setPerformAccessibilityActionResult(ZI)V
@@ -1443,7 +1511,9 @@
Landroid/view/IWindowSession;->setTransparentRegion(Landroid/view/IWindow;Landroid/graphics/Region;)V
Landroid/view/IWindowSession;->wallpaperCommandComplete(Landroid/os/IBinder;Landroid/os/Bundle;)V
Landroid/view/IWindowSession;->wallpaperOffsetsComplete(Landroid/os/IBinder;)V
+Landroid/view/RenderNodeAnimator;->setDuration(J)Landroid/view/RenderNodeAnimator;
Landroid/view/View$AttachInfo$InvalidateInfo;-><init>()V
+Landroid/view/View$CheckForLongPress;-><init>(Landroid/view/View;)V
Landroid/view/View$ListenerInfo;-><init>()V
Landroid/view/ViewTreeObserver$InternalInsetsInfo;-><init>()V
Landroid/webkit/CacheManager$CacheResult;-><init>()V
@@ -1453,9 +1523,102 @@
Landroid/webkit/IWebViewUpdateService;->getCurrentWebViewPackageName()Ljava/lang/String;
Landroid/webkit/IWebViewUpdateService;->getValidWebViewPackages()[Landroid/webkit/WebViewProviderInfo;
Landroid/webkit/IWebViewUpdateService;->isFallbackPackage(Ljava/lang/String;)Z
+Landroid/widget/DigitalClock$FormatChangeObserver;-><init>(Landroid/widget/DigitalClock;)V
+Landroid/widget/QuickContactBadge$QueryHandler;-><init>(Landroid/widget/QuickContactBadge;Landroid/content/ContentResolver;)V
Landroid/widget/RelativeLayout$DependencyGraph$Node;-><init>()V
Landroid/widget/ScrollBarDrawable;-><init>()V
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->clear()V
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->getRememberedPosition()I
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigit(C)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigitAndRememberPosition(C)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getDescriptionForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getInstance()Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;
+Lcom/android/i18n/phonenumbers/NumberParseException;->getErrorType()Lcom/android/i18n/phonenumbers/NumberParseException$ErrorType;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getDomesticCarrierCodeFormattingRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getFormat()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPattern(I)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getNationalPrefixFormattingRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getPattern()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->leadingDigitsPatternSize()I
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getCountryCode()I
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getGeneralDesc()Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixForParsing()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixTransformRule()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPreferredExtnPrefix()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasNationalPrefix()Z
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasPreferredExtnPrefix()Z
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->intlNumberFormats()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->numberFormats()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;-><init>()V
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->getMetadataList()Ljava/util/List;
+Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getNationalNumberPattern()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_DEFAULT_COUNTRY:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITHOUT_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_IDD:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->values()[Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->clearCountryCode()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCode()I
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCodeSource()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getExtension()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getNationalNumber()J
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasCountryCode()Z
+Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasExtension()Z
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->end()I
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->number()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->rawString()Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->start()I
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;->POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->EXACT_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NOT_A_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NO_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->SHORT_NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->E164:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->INTERNATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->NATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->RFC3966:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE_OR_MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PAGER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PERSONAL_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PREMIUM_RATE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->SHARED_COST:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->TOLL_FREE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->UAN:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOICEMAIL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOIP:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->IS_POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->TOO_LONG:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->findNumbers(Ljava/lang/CharSequence;Ljava/lang/String;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;J)Ljava/lang/Iterable;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->formatInOriginalFormat(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getAsYouTypeFormatter(Ljava/lang/String;)Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getCountryCodeForRegion(Ljava/lang/String;)I
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getInstance()Lcom/android/i18n/phonenumbers/PhoneNumberUtil;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNationalSignificantNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNumberType(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isNumberMatch(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumberWithReason(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;
+Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isValidNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z
+Lcom/android/ims/ImsCall;->deflect(Ljava/lang/String;)V
+Lcom/android/ims/ImsCall;->isMultiparty()Z
+Lcom/android/ims/ImsCall;->reject(I)V
+Lcom/android/ims/ImsCall;->terminate(I)V
Lcom/android/ims/ImsConfigListener$Stub;-><init>()V
+Lcom/android/ims/ImsEcbm;->exitEmergencyCallbackMode()V
+Lcom/android/ims/ImsManager;->getConfigInterface()Lcom/android/ims/ImsConfig;
+Lcom/android/ims/ImsManager;->getInstance(Landroid/content/Context;I)Lcom/android/ims/ImsManager;
+Lcom/android/ims/ImsManager;->isEnhanced4gLteModeSettingEnabledByUser(Landroid/content/Context;)Z
+Lcom/android/ims/ImsManager;->isNonTtyOrTtyOnVolteEnabled(Landroid/content/Context;)Z
+Lcom/android/ims/ImsManager;->isVolteEnabledByPlatform(Landroid/content/Context;)Z
+Lcom/android/ims/ImsUtInterface;->queryCallForward(ILjava/lang/String;Landroid/os/Message;)V
Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V
Lcom/android/ims/internal/IImsCallSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsCallSession;
Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V
@@ -1473,7 +1636,15 @@
Lcom/android/ims/internal/IImsVideoCallCallback;->receiveSessionModifyResponse(ILandroid/telecom/VideoProfile;Landroid/telecom/VideoProfile;)V
Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V
Lcom/android/ims/internal/IImsVideoCallProvider;->setCallback(Lcom/android/ims/internal/IImsVideoCallCallback;)V
+Lcom/android/ims/internal/ImsVideoCallProviderWrapper;-><init>(Lcom/android/ims/internal/IImsVideoCallProvider;)V
Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V
+Lcom/android/internal/app/AlertActivity;-><init>()V
+Lcom/android/internal/app/AlertActivity;->mAlert:Lcom/android/internal/app/AlertController;
+Lcom/android/internal/app/AlertActivity;->mAlertParams:Lcom/android/internal/app/AlertController$AlertParams;
+Lcom/android/internal/app/AlertActivity;->setupAlert()V
+Lcom/android/internal/app/AssistUtils;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/app/AssistUtils;->getAssistComponentForUser(I)Landroid/content/ComponentName;
+Lcom/android/internal/app/ChooserActivity;-><init>()V
Lcom/android/internal/app/IAppOpsCallback$Stub;-><init>()V
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
@@ -1508,9 +1679,35 @@
Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
Lcom/android/internal/app/IBatteryStats;->isCharging()Z
Lcom/android/internal/app/IMediaContainerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IMediaContainerService;
+Lcom/android/internal/app/IntentForwarderActivity;->TAG:Ljava/lang/String;
Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
Lcom/android/internal/app/IVoiceInteractionManagerService;->getKeyphraseSoundModel(ILjava/lang/String;)Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel;
+Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;-><init>(Ljava/util/Locale;Z)V
+Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;->compare(Lcom/android/internal/app/LocaleStore$LocaleInfo;Lcom/android/internal/app/LocaleStore$LocaleInfo;)I
+Lcom/android/internal/app/LocaleHelper;->getDisplayCountry(Ljava/util/Locale;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/internal/app/LocaleHelper;->getDisplayName(Ljava/util/Locale;Ljava/util/Locale;Z)Ljava/lang/String;
+Lcom/android/internal/app/LocaleHelper;->normalizeForSearch(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String;
+Lcom/android/internal/app/LocalePicker$LocaleInfo;->getLocale()Ljava/util/Locale;
+Lcom/android/internal/app/LocalePicker;->getLocales()Landroid/os/LocaleList;
+Lcom/android/internal/app/LocalePicker;->updateLocale(Ljava/util/Locale;)V
+Lcom/android/internal/app/LocalePicker;->updateLocales(Landroid/os/LocaleList;)V
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameInUiLanguage()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameNative()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getId()Ljava/lang/String;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getLocale()Ljava/util/Locale;
+Lcom/android/internal/app/LocaleStore$LocaleInfo;->getParent()Ljava/util/Locale;
+Lcom/android/internal/app/LocaleStore;->fillCache(Landroid/content/Context;)V
+Lcom/android/internal/app/LocaleStore;->getLevelLocales(Landroid/content/Context;Ljava/util/Set;Lcom/android/internal/app/LocaleStore$LocaleInfo;Z)Ljava/util/Set;
+Lcom/android/internal/app/LocaleStore;->getLocaleInfo(Ljava/util/Locale;)Lcom/android/internal/app/LocaleStore$LocaleInfo;
+Lcom/android/internal/app/NetInitiatedActivity;->handleNIVerify(Landroid/content/Intent;)V
+Lcom/android/internal/app/ResolverActivity;-><init>()V
+Lcom/android/internal/app/ResolverActivity;->mAdapter:Lcom/android/internal/app/ResolverActivity$ResolveListAdapter;
+Lcom/android/internal/app/ResolverActivity;->mPm:Landroid/content/pm/PackageManager;
+Lcom/android/internal/app/ResolverActivity;->onCreate(Landroid/os/Bundle;Landroid/content/Intent;Ljava/lang/CharSequence;[Landroid/content/Intent;Ljava/util/List;Z)V
+Lcom/android/internal/app/WindowDecorActionBar$TabImpl;->mCallback:Landroid/app/ActionBar$TabListener;
+Lcom/android/internal/app/WindowDecorActionBar;->mTabScrollView:Lcom/android/internal/widget/ScrollingTabContainerView;
+Lcom/android/internal/app/WindowDecorActionBar;->setShowHideAnimationEnabled(Z)V
Lcom/android/internal/appwidget/IAppWidgetService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/appwidget/IAppWidgetService;
Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidgetId:I
Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z
@@ -1518,17 +1715,80 @@
Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I
Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews;
Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
+Lcom/android/internal/database/SortCursor;-><init>([Landroid/database/Cursor;Ljava/lang/String;)V
+Lcom/android/internal/database/SortCursor;->mCursor:Landroid/database/Cursor;
+Lcom/android/internal/database/SortCursor;->mCursors:[Landroid/database/Cursor;
+Lcom/android/internal/http/HttpDateTime;->parse(Ljava/lang/String;)J
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;-><init>()V
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorId:Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorIdEncoding:I
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->text:Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->textEncoding:I
+Lcom/android/internal/location/GpsNetInitiatedHandler;->decodeString(Ljava/lang/String;ZI)Ljava/lang/String;
+Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;)V
+Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/logging/MetricsLogger;-><init>()V
Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
Lcom/android/internal/net/VpnConfig;-><init>()V
+Lcom/android/internal/os/AndroidPrintStream;-><init>(ILjava/lang/String;)V
+Lcom/android/internal/os/BaseCommand;-><init>()V
+Lcom/android/internal/os/BaseCommand;->mArgs:Landroid/os/ShellCommand;
Lcom/android/internal/os/BatterySipper$DrainType;->values()[Lcom/android/internal/os/BatterySipper$DrainType;
+Lcom/android/internal/os/BinderInternal;->getContextObject()Landroid/os/IBinder;
+Lcom/android/internal/os/BinderInternal;->handleGc()V
+Lcom/android/internal/os/ClassLoaderFactory;->createClassloaderNamespace(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZZ)Ljava/lang/String;
Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
Lcom/android/internal/os/IDropBoxManagerService;->getNextEntry(Ljava/lang/String;JLjava/lang/String;)Landroid/os/DropBoxManager$Entry;
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->name:Ljava/lang/String;
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_stime:I
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_uptime:J
+Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_utime:I
+Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V
+Lcom/android/internal/os/ProcessCpuTracker;->countWorkingStats()I
+Lcom/android/internal/os/ProcessCpuTracker;->getWorkingStats(I)Lcom/android/internal/os/ProcessCpuTracker$Stats;
+Lcom/android/internal/os/ProcessCpuTracker;->update()V
+Lcom/android/internal/os/RuntimeInit;->commonInit()V
+Lcom/android/internal/os/RuntimeInit;->getApplicationObject()Landroid/os/IBinder;
+Lcom/android/internal/os/RuntimeInit;->initialized:Z
+Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder;
+Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V
+Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J
+Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I
+Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I
+Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J
+Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String;
+Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList;
+Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I
+Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V
+Lcom/android/internal/os/ZygoteConnection;->closeSocket()V
+Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor;
+Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I
+Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket;
+Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream;
+Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials;
+Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String;
+Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
+Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources;
+Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/policy/DecorView;->mLastBottomInset:I
+Lcom/android/internal/policy/DecorView;->mLastLeftInset:I
+Lcom/android/internal/policy/DecorView;->mLastRightInset:I
+Lcom/android/internal/policy/DecorView;->mWindow:Lcom/android/internal/policy/PhoneWindow;
Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
Lcom/android/internal/policy/IKeyguardService;->doKeyguardTimeout(Landroid/os/Bundle;)V
Lcom/android/internal/policy/IKeyguardService;->setKeyguardEnabled(Z)V
Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->mContext:Landroid/content/Context;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->mView:Landroid/view/View;
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyDown(ILandroid/view/KeyEvent;)Z
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyUp(ILandroid/view/KeyEvent;)Z
+Lcom/android/internal/policy/PhoneFallbackEventHandler;->startCallActivity()V
+Lcom/android/internal/policy/PhoneWindow;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/policy/PhoneWindow;->mTitle:Ljava/lang/CharSequence;
+Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
Lcom/android/internal/R$anim;->fade_in:I
Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
@@ -1996,9 +2256,961 @@
Lcom/android/internal/statusbar/IStatusBarService;->setIconVisibility(Ljava/lang/String;Z)V
Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService;
Lcom/android/internal/telecom/ITelecomService;->getCallState()I
+Lcom/android/internal/telephony/BaseCommands;->mCallStateRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCallWaitingInfoRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCatCallSetUpRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatCcAlphaRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatEventRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatProCmdRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCatSessionEndRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaPrlChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mCdmaSubscriptionChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/BaseCommands;->mEmergencyCallbackModeRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mExitEmergencyCallbackModeRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mGsmBroadcastSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mGsmSmsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mHardwareConfigChangeRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mIccRefreshRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mIccSmsFullRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mIccStatusChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mImsNetworkStateChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mNITZTimeRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mOtaProvisionRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mPhoneRadioCapabilityChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mPhoneType:I
+Lcom/android/internal/telephony/BaseCommands;->mPreferredNetworkType:I
+Lcom/android/internal/telephony/BaseCommands;->mResendIncallMuteRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRestrictedStateRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mRilCellInfoListRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRingbackToneRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mRingRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSignalStrengthRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSmsOnSimRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSmsStatusRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSrvccStateRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mSsnRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mSsRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mStateMonitor:Ljava/lang/Object;
+Lcom/android/internal/telephony/BaseCommands;->mSubscriptionStatusRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/BaseCommands;->mUnsolOemHookRawRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mUSSDRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/BaseCommands;->mVoiceRadioTechChangedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/Call$State;->ACTIVE:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->DISCONNECTING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->isAlive()Z
+Lcom/android/internal/telephony/Call$State;->isRinging()Z
+Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call;-><init>()V
+Lcom/android/internal/telephony/Call;->getConnections()Ljava/util/List;
+Lcom/android/internal/telephony/Call;->getEarliestConnection()Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/Call;->getLatestConnection()Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/Call;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Call;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Call;->hangup()V
+Lcom/android/internal/telephony/Call;->isIdle()Z
+Lcom/android/internal/telephony/Call;->isMultiparty()Z
+Lcom/android/internal/telephony/Call;->mConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/Call;->mState:Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V
+Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V
+Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V
+Lcom/android/internal/telephony/CallForwardInfo;-><init>()V
+Lcom/android/internal/telephony/CallForwardInfo;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/CallForwardInfo;->reason:I
+Lcom/android/internal/telephony/CallForwardInfo;->serviceClass:I
+Lcom/android/internal/telephony/CallForwardInfo;->status:I
+Lcom/android/internal/telephony/CallForwardInfo;->timeSeconds:I
+Lcom/android/internal/telephony/CallForwardInfo;->toa:I
+Lcom/android/internal/telephony/CallManager;->canConference(Lcom/android/internal/telephony/Call;I)Z
+Lcom/android/internal/telephony/CallManager;->canDial(Lcom/android/internal/telephony/Phone;)Z
+Lcom/android/internal/telephony/CallManager;->conference(Lcom/android/internal/telephony/Call;)V
+Lcom/android/internal/telephony/CallManager;->getActiveFgCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getActiveFgCallState(I)Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/CallManager;->getBackgroundCalls()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getBgCallConnections()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getBgPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getContext()Landroid/content/Context;
+Lcom/android/internal/telephony/CallManager;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFgCallConnections()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getFgPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFgPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall(I)Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/CallManager;->getInstance()Lcom/android/internal/telephony/CallManager;
+Lcom/android/internal/telephony/CallManager;->getPhoneInCall()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getRingingCalls()Ljava/util/List;
+Lcom/android/internal/telephony/CallManager;->getRingingPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/CallManager;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallManager;->getState(I)Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallManager;->hasActiveBgCall()Z
+Lcom/android/internal/telephony/CallManager;->hasActiveBgCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasActiveFgCall()Z
+Lcom/android/internal/telephony/CallManager;->hasActiveFgCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasActiveRingingCall(I)Z
+Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall()Z
+Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall(I)Z
+Lcom/android/internal/telephony/CallManager;->mBackgroundCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mEmptyConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mForegroundCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mPhones:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->mRingingCalls:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/CallManager;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CallManager;->registerPhone(Lcom/android/internal/telephony/Phone;)Z
+Lcom/android/internal/telephony/CallManager;->unregisterForDisconnect(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CallManager;->unregisterPhone(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/CallStateException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/CallTracker;-><init>()V
+Lcom/android/internal/telephony/CallTracker;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/CallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/CallTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/CallTracker;->mNeedsPoll:Z
+Lcom/android/internal/telephony/CallTracker;->mNumberConverted:Z
+Lcom/android/internal/telephony/CallTracker;->mPendingOperations:I
+Lcom/android/internal/telephony/CallTracker;->registerForVoiceCallEnded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CarrierServiceBindHelper;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/CarrierServiceBindHelper;->mHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->CLOSE_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->DISPLAY_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->fromInt(I)Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_CHANNEL_STATUS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INKEY:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INPUT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LANGUAGE_NOTIFICATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LAUNCH_BROWSER:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->OPEN_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PLAY_TONE:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PROVIDE_LOCAL_INFORMATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->RECEIVE_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->REFRESH:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SELECT_ITEM:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DTMF:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SMS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_USSD:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_CALL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_EVENT_LIST:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_IDLE_MODE_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_MENU:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->callMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->confirmMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;->eventList:[I
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getCallSettings()Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getCmdType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->geTextMessage()Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->getSetEventList()Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->hasIconLoadFailed()Z
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mCallSettings:Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mInput:Lcom/android/internal/telephony/cat/Input;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mMenu:Lcom/android/internal/telephony/cat/Menu;
+Lcom/android/internal/telephony/cat/CatCmdMessage;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/Object;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatLog;->e(Ljava/lang/Object;Ljava/lang/String;)V
+Lcom/android/internal/telephony/cat/CatResponseMessage;->setEventDownload(I[B)V
+Lcom/android/internal/telephony/cat/CatService;->dispose()V
+Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z
+Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
+Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread;
+Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
+Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/CatService;->mSlotId:I
+Lcom/android/internal/telephony/cat/CatService;->mStkAppInstalled:Z
+Lcom/android/internal/telephony/cat/CatService;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/cat/CatService;->sendTerminalResponse(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/ResultCode;ZILcom/android/internal/telephony/cat/ResponseData;)V
+Lcom/android/internal/telephony/cat/CatService;->sInstance:[Lcom/android/internal/telephony/cat/CatService;
+Lcom/android/internal/telephony/cat/CatService;->sInstanceLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/cat/CommandDetails;->commandNumber:I
+Lcom/android/internal/telephony/cat/CommandDetails;->commandQualifier:I
+Lcom/android/internal/telephony/cat/CommandDetails;->compRequired:Z
+Lcom/android/internal/telephony/cat/CommandDetails;->typeOfCommand:I
+Lcom/android/internal/telephony/cat/CommandParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;)V
+Lcom/android/internal/telephony/cat/CommandParams;->getCommandType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
+Lcom/android/internal/telephony/cat/CommandParams;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->dispose()V
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->mIconLoader:Lcom/android/internal/telephony/cat/IconLoader;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForNextTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/Iterator;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
+Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/List;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getLength()I
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getRawValue()[B
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getTag()I
+Lcom/android/internal/telephony/cat/ComprehensionTlv;->getValueIndex()I
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ADDRESS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ALPHA_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->COMMAND_DETAILS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->DEVICE_IDENTITIES:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ICON_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->RESULT:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->SMS_TPDU:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_ATTRIBUTE:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->USSD_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
+Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->value()I
+Lcom/android/internal/telephony/cat/DeviceIdentities;->destinationId:I
+Lcom/android/internal/telephony/cat/DisplayTextParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;)V
+Lcom/android/internal/telephony/cat/DisplayTextParams;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
+Lcom/android/internal/telephony/cat/Duration$TimeUnit;->value()I
+Lcom/android/internal/telephony/cat/Duration;->timeInterval:I
+Lcom/android/internal/telephony/cat/Duration;->timeUnit:Lcom/android/internal/telephony/cat/Duration$TimeUnit;
+Lcom/android/internal/telephony/cat/GetInputParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Input;)V
+Lcom/android/internal/telephony/cat/IconId;->recordNumber:I
+Lcom/android/internal/telephony/cat/IconLoader;->loadIcon(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/cat/Menu;->titleAttrs:Ljava/util/List;
+Lcom/android/internal/telephony/cat/PlayToneParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;Lcom/android/internal/telephony/cat/Tone;Lcom/android/internal/telephony/cat/Duration;Z)V
+Lcom/android/internal/telephony/cat/ResponseData;-><init>()V
+Lcom/android/internal/telephony/cat/ResponseData;->format(Ljava/io/ByteArrayOutputStream;)V
+Lcom/android/internal/telephony/cat/ResultCode;->BACKWARD_MOVE_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->BEYOND_TERMINAL_CAPABILITY:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->BIP_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->CMD_DATA_NOT_UNDERSTOOD:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->HELP_INFO_REQUIRED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->LAUNCH_BROWSER_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->NETWORK_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->NO_RESPONSE_FROM_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->OK:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_ICON_NOT_DISPLAYED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_LIMITED_SERVICE:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_MODIFIED_BY_NAA:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_NAA_NOT_ACTIVE:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_TONE_NOT_PLAYED:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_ADDITIONAL_EFS_READ:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MISSING_INFO:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MODIFICATION:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_PARTIAL_COMPREHENSION:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->REQUIRED_VALUES_MISSING:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->TERMINAL_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->UICC_SESSION_TERM_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->USER_NOT_ACCEPT:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->USIM_CALL_CONTROL_PERMANENT:Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultCode;->value()I
+Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode;
+Lcom/android/internal/telephony/cat/ResultException;-><init>(Lcom/android/internal/telephony/cat/ResultCode;)V
+Lcom/android/internal/telephony/cat/RilMessage;-><init>(ILjava/lang/String;)V
+Lcom/android/internal/telephony/cat/RilMessage;->mData:Ljava/lang/Object;
+Lcom/android/internal/telephony/cat/RilMessage;->mId:I
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->getInstance(Landroid/os/Handler;Lcom/android/internal/telephony/uicc/IccFileHandler;I)Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCmdParamsFactory:Lcom/android/internal/telephony/cat/CommandParamsFactory;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mInstance:[Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->mStateStart:Lcom/android/internal/telephony/cat/RilMessageDecoder$StateStart;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V
+Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V
+Lcom/android/internal/telephony/cat/SelectItemParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Menu;Z)V
+Lcom/android/internal/telephony/cat/TextMessage;-><init>()V
+Lcom/android/internal/telephony/cat/TextMessage;->iconSelfExplanatory:Z
+Lcom/android/internal/telephony/cat/TextMessage;->text:Ljava/lang/String;
+Lcom/android/internal/telephony/cat/ValueObject;-><init>()V
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveAlphaId(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextAttribute(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/util/List;
+Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextString(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaCallWaitingNotification;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaMmiCode;->mSc:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->handleCdmaStatusReport(Lcom/android/internal/telephony/cdma/SmsMessage;)V
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getCdmaSubscriptionSource()I
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getInstance(Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;Landroid/os/Handler;ILjava/lang/Object;)Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
+Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;->mEriIconText:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/EriManager;->getEriDisplayInformation(II)Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;
+Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/BearerData;->countAsciiSeptets(Ljava/lang/CharSequence;Z)I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->decodeUserDataPayload(Lcom/android/internal/telephony/cdma/sms/UserData;Z)V
+Lcom/android/internal/telephony/cdma/sms/BearerData;->displayMode:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->encode(Lcom/android/internal/telephony/cdma/sms/BearerData;)[B
+Lcom/android/internal/telephony/cdma/sms/BearerData;->encode7bitAscii(Ljava/lang/String;Z)[B
+Lcom/android/internal/telephony/cdma/sms/BearerData;->getBitsForNumFields(II)I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->hasUserDataHeader:Z
+Lcom/android/internal/telephony/cdma/sms/BearerData;->messageId:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->msgCenterTimeStamp:Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;
+Lcom/android/internal/telephony/cdma/sms/BearerData;->priority:I
+Lcom/android/internal/telephony/cdma/sms/BearerData;->priorityIndicatorSet:Z
+Lcom/android/internal/telephony/cdma/sms/BearerData;->userData:Lcom/android/internal/telephony/cdma/sms/UserData;
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->digitMode:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberMode:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberOfDigits:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberPlan:I
+Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->parse(Ljava/lang/String;)Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->bearerData:[B
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->serviceCategory:I
+Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->teleService:I
+Lcom/android/internal/telephony/cdma/sms/UserData;-><init>()V
+Lcom/android/internal/telephony/cdma/sms/UserData;->charToAscii:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncoding:I
+Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncodingSet:Z
+Lcom/android/internal/telephony/cdma/sms/UserData;->numFields:I
+Lcom/android/internal/telephony/cdma/sms/UserData;->payload:[B
+Lcom/android/internal/telephony/cdma/sms/UserData;->payloadStr:Ljava/lang/String;
+Lcom/android/internal/telephony/cdma/sms/UserData;->userDataHeader:Lcom/android/internal/telephony/SmsHeader;
+Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;-><init>()V
+Lcom/android/internal/telephony/cdma/SmsMessage;-><init>()V
+Lcom/android/internal/telephony/cdma/SmsMessage;->calculateLength(Ljava/lang/CharSequence;ZZ)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/cdma/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/cdma/SmsMessage;
+Lcom/android/internal/telephony/cdma/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/cdma/SmsMessage;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getIncomingSmsFingerprint()[B
+Lcom/android/internal/telephony/cdma/SmsMessage;->getMessageType()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getNextMessageId()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getNumOfVoicemails()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;Z)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;ZI)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;I[BZ)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;I)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/cdma/SmsMessage;->getTeleService()I
+Lcom/android/internal/telephony/cdma/SmsMessage;->isStatusReportMessage()Z
+Lcom/android/internal/telephony/cdma/SmsMessage;->mBearerData:Lcom/android/internal/telephony/cdma/sms/BearerData;
+Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;
+Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V
+Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/CommandException$Error;->GENERIC_FAILURE:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->PASSWORD_INCORRECT:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->RADIO_NOT_AVAILABLE:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->REQUEST_NOT_SUPPORTED:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->SIM_PUK2:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException$Error;->SMS_FAIL_RETRY:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException;-><init>(Lcom/android/internal/telephony/CommandException$Error;)V
+Lcom/android/internal/telephony/CommandException;->fromRilErrno(I)Lcom/android/internal/telephony/CommandException;
+Lcom/android/internal/telephony/CommandException;->getCommandError()Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandException;->mError:Lcom/android/internal/telephony/CommandException$Error;
+Lcom/android/internal/telephony/CommandsInterface;->acceptCall(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingCdmaSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingGsmSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->changeBarringPassword(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnRuim(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnSim(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->exitEmergencyCallbackMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getBasebandVersion(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getCdmaBroadcastConfig(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getCDMASubscription(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getDataCallList(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIccCardStatus(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIMEISV(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getIMSI(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getLastDataCallFailCause(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getLastPdpFailCause(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getNetworkSelectionMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getOperator(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getPDPContextList(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getPreferredNetworkType(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getSignalStrength(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getSmscAddress(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->getVoiceRegistrationState(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->handleCallSetupRequestFromSim(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->iccIO(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->iccIOForApp(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryCallForwardStatus(IILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryCallWaiting(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryFacilityLock(Ljava/lang/String;Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->queryTTYMode(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForCdmaOtaProvision(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForCellInfoList(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForImsNetworkStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForOffOrNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForOn(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForRadioStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->registerForRilConnected(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->reportSmsMemoryStatus(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->reportStkServiceIsRunning(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->requestIccSimAuthentication(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->requestShutdown(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendDtmf(CLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendEnvelope(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->sendTerminalResponse(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCallWaiting(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setCdmaBroadcastActivation(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setDataAllowed(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setEmergencyCallbackMode(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setFacilityLock(Ljava/lang/String;ZLjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeManual(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCallRing(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatCallSetUp(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatCcAlphaNotify(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatEvent(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatProactiveCmd(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnCatSessionEnd(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnIccSmsFull(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnNewGsmBroadcastSms(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnNITZTime(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSignalStrengthUpdate(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSmsOnSim(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSmsStatus(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setOnSuppServiceNotification(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/CommandsInterface;->setPhoneType(I)V
+Lcom/android/internal/telephony/CommandsInterface;->setPreferredNetworkType(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setRadioPower(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setTTYMode(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->setUiccSubscription(IIIILandroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->supplyIccPin(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->switchWaitingOrHoldingAndActive(Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForAvailable(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForCdmaOtaProvision(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForOffOrNotAvailable(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForOn(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForRilConnected(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->unregisterForVoiceRadioTechChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/CommandsInterface;->writeSmsToRuim(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/CommandsInterface;->writeSmsToSim(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Connection$PostDialState;->CANCELLED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->COMPLETE:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->NOT_STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->WAIT:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection$PostDialState;->WILD:Lcom/android/internal/telephony/Connection$PostDialState;
+Lcom/android/internal/telephony/Connection;-><init>(I)V
+Lcom/android/internal/telephony/Connection;->getAddress()Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->getCall()Lcom/android/internal/telephony/Call;
+Lcom/android/internal/telephony/Connection;->getConnectTime()J
+Lcom/android/internal/telephony/Connection;->getCreateTime()J
+Lcom/android/internal/telephony/Connection;->getDisconnectCause()I
+Lcom/android/internal/telephony/Connection;->getDisconnectTime()J
+Lcom/android/internal/telephony/Connection;->getDurationMillis()J
+Lcom/android/internal/telephony/Connection;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/Connection;->getUserData()Ljava/lang/Object;
+Lcom/android/internal/telephony/Connection;->hangup()V
+Lcom/android/internal/telephony/Connection;->isAlive()Z
+Lcom/android/internal/telephony/Connection;->isIncoming()Z
+Lcom/android/internal/telephony/Connection;->LOG_TAG:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mAddress:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mCnapName:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mCnapNamePresentation:I
+Lcom/android/internal/telephony/Connection;->mDialString:Ljava/lang/String;
+Lcom/android/internal/telephony/Connection;->mDuration:J
+Lcom/android/internal/telephony/Connection;->mIsIncoming:Z
+Lcom/android/internal/telephony/Connection;->mNumberPresentation:I
+Lcom/android/internal/telephony/Connection;->setVideoState(I)V
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getApnType()Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getReason()Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->getState()Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isConnectable()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isDisconnected()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isEnabled()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->isReady()Z
+Lcom/android/internal/telephony/dataconnection/ApnContext;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mApnType:Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCount:I
+Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCountLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/dataconnection/ApnContext;->setState(Lcom/android/internal/telephony/DctConstants$State;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;->mApnContext:Lcom/android/internal/telephony/dataconnection/ApnContext;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->clearSettings()V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->dumpToLog()V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->initConnection(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)Z
+Lcom/android/internal/telephony/dataconnection/DataConnection;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mApnContexts:Ljava/util/HashMap;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectParams:Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mId:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mInactiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:Landroid/net/LinkProperties;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
+Lcom/android/internal/telephony/dataconnection/DataConnection;->updateTcpBufferSizes(I)V
+Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
+Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause;
+Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(ZLjava/lang/String;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpConnection(ZLcom/android/internal/telephony/dataconnection/ApnContext;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->createAllApnList()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getActiveApnTypes()[Ljava/lang/String;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getOverallState()Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->getUiccRecords(I)Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isConnected()Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isDisconnected()Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->isOnlySingleDcAllowed(I)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAllApnSettings:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mApnContexts:Ljava/util/concurrent/ConcurrentHashMap;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAttached:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mAutoAttachOnCreation:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mDataConnectionTracker:Landroid/os/Handler;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mDisconnectPendingCount:I
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsPsRestricted:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsScreenOn:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollEnabled:Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollPeriod:I
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mPrioritySortedApnContexts:Ljava/util/PriorityQueue;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:Landroid/app/ProgressDialog;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
+Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyDataConnection(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyOffApnsOfAvailability(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onCleanUpAllConnections(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onSetUserDataEnabled(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->registerForAllDataDisconnected(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->resetPollStats()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->restartDataStallAlarm()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setInitialAttachApn()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setInternalDataEnabled(ZLandroid/os/Message;)Z
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setPreferredApn(I)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setRadio(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->setupDataOnConnectableApns(Ljava/lang/String;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->startDataStallAlarm(Z)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->startNetStatPoll()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->stopDataStallAlarm()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->stopNetStatPoll()V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->unregisterForAllDataDisconnected(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/dataconnection/DcTracker;->updateRecords()V
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->DORMANT:Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$Activity;->values()[Lcom/android/internal/telephony/DctConstants$Activity;
+Lcom/android/internal/telephony/DctConstants$State;->CONNECTED:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->CONNECTING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->DISCONNECTING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->SCANNING:Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State;
+Lcom/android/internal/telephony/DefaultPhoneNotifier;->mRegistry:Lcom/android/internal/telephony/ITelephonyRegistry;
+Lcom/android/internal/telephony/DriverCall$State;->ACTIVE:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->ALERTING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->DIALING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->HOLDING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->INCOMING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall$State;->WAITING:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/DriverCall;-><init>()V
+Lcom/android/internal/telephony/DriverCall;->index:I
+Lcom/android/internal/telephony/DriverCall;->isMT:Z
+Lcom/android/internal/telephony/DriverCall;->isVoice:Z
+Lcom/android/internal/telephony/DriverCall;->name:Ljava/lang/String;
+Lcom/android/internal/telephony/DriverCall;->number:Ljava/lang/String;
+Lcom/android/internal/telephony/DriverCall;->numberPresentation:I
+Lcom/android/internal/telephony/DriverCall;->state:Lcom/android/internal/telephony/DriverCall$State;
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z
+Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap;
+Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;-><init>(Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->getCLIRMode()I
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->getScString()Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isActivate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isDeactivate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isErasure()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isInterrogate()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isRegister()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallBarring(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallForwarding(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->isTemporaryModeCLIR()Z
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mDialingNumber:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSc:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSia:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSib:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSic:Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)Lcom/android/internal/telephony/gsm/GsmMmiCode;
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->processCode()V
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->siToServiceClass(Ljava/lang/String;)I
+Lcom/android/internal/telephony/gsm/GsmMmiCode;->sPatternSuppService:Ljava/util/regex/Pattern;
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;-><init>([BII)V
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageClear()Z
+Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageSet()Z
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->mGsmInboundSmsHandler:Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;
+Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/gsm/SimTlv;-><init>([BII)V
+Lcom/android/internal/telephony/gsm/SimTlv;->getData()[B
+Lcom/android/internal/telephony/gsm/SimTlv;->getTag()I
+Lcom/android/internal/telephony/gsm/SimTlv;->isValidObject()Z
+Lcom/android/internal/telephony/gsm/SimTlv;->mHasValidTlvObject:Z
+Lcom/android/internal/telephony/gsm/SimTlv;->nextObject()Z
+Lcom/android/internal/telephony/gsm/SmsCbHeader;-><init>([B)V
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getGeographicalScope()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getNumberOfPages()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getPageIndex()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getSerialNumber()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->getServiceCategory()I
+Lcom/android/internal/telephony/gsm/SmsCbHeader;->mMessageIdentifier:I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;-><init>([B)V
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getByte()I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserData()[B
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserDataUCS2(I)Ljava/lang/String;
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mCur:I
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mPdu:[B
+Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mUserDataSeptetPadding:I
+Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;-><init>()V
+Lcom/android/internal/telephony/gsm/SmsMessage;-><init>()V
+Lcom/android/internal/telephony/gsm/SmsMessage;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/gsm/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/gsm/SmsMessage;
+Lcom/android/internal/telephony/gsm/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/gsm/SmsMessage;
+Lcom/android/internal/telephony/gsm/SmsMessage;->encodeUCS2(Ljava/lang/String;[B)[B
+Lcom/android/internal/telephony/gsm/SmsMessage;->getStatus()I
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[B)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;
+Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPduHead(Ljava/lang/String;Ljava/lang/String;BZLcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;)Ljava/io/ByteArrayOutputStream;
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMWIClearMessage()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMwiDontStore()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isMWISetMessage()Z
+Lcom/android/internal/telephony/gsm/SmsMessage;->isStatusReportMessage()Z
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->loadEfFilesFromUsim()Ljava/util/ArrayList;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V
Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V
+Lcom/android/internal/telephony/GsmCdmaCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->clearDisconnected()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->dialThreeWay(Ljava/lang/String;)Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->disableDataCallInEmergencyCall(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->fakeHoldForegroundBeforeDial()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->getPhone()Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->handleEcmTimer(I)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mForegroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPendingMO:Lcom/android/internal/telephony/GsmCdmaConnection;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mRingingCall:Lcom/android/internal/telephony/GsmCdmaCall;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->mState:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage()Landroid/os/Message;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage(I)Landroid/os/Message;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->setMute(Z)V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->switchWaitingOrHoldingAndActive()V
+Lcom/android/internal/telephony/GsmCdmaCallTracker;->updatePhoneState()V
+Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->acquireWakeLock()V
+Lcom/android/internal/telephony/GsmCdmaConnection;->createWakeLock(Landroid/content/Context;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->disconnectCauseFromCode(I)I
+Lcom/android/internal/telephony/GsmCdmaConnection;->fetchDtmfToneDelay(Lcom/android/internal/telephony/GsmCdmaPhone;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->findNextPCharOrNonPOrNonWCharIndex(Ljava/lang/String;I)I
+Lcom/android/internal/telephony/GsmCdmaConnection;->findPOrWCharToAppend(Ljava/lang/String;II)C
+Lcom/android/internal/telephony/GsmCdmaConnection;->formatDialString(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaConnection;->getState()Lcom/android/internal/telephony/Call$State;
+Lcom/android/internal/telephony/GsmCdmaConnection;->isPause(C)Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->isWait(C)Z
+Lcom/android/internal/telephony/GsmCdmaConnection;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaConnection;->maskDialString(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaConnection;->mIndex:I
+Lcom/android/internal/telephony/GsmCdmaConnection;->mOwner:Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaConnection;->onConnectedInOrOut()V
+Lcom/android/internal/telephony/GsmCdmaConnection;->updateParent(Lcom/android/internal/telephony/GsmCdmaCall;Lcom/android/internal/telephony/GsmCdmaCall;)V
+Lcom/android/internal/telephony/GsmCdmaPhone$Cfu;-><init>(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->exitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/GsmCdmaPhone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getCdmaEriText()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getEsn()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getLine1Number()Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getPhoneType()I
+Lcom/android/internal/telephony/GsmCdmaPhone;->getServiceState()Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/GsmCdmaPhone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/GsmCdmaPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isCfEnable(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isEriFileLoaded()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isInCall()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isManualSelProhibitedInGlobalMode()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isPhoneTypeGsm()Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFAction(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFReason(I)Z
+Lcom/android/internal/telephony/GsmCdmaPhone;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->mCT:Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mEcmExitRespRegistrant:Landroid/os/Registrant;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mEriManager:Lcom/android/internal/telephony/cdma/EriManager;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mIccSmsInterfaceManager:Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mIsimUiccRecords:Lcom/android/internal/telephony/uicc/IsimUiccRecords;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mPendingMMIs:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/GsmCdmaPhone;->mSST:Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;->notifyPreciseCallStateChanged()V
+Lcom/android/internal/telephony/GsmCdmaPhone;->notifyServiceStateChanged(Landroid/telephony/ServiceState;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/GsmCdmaPhone;->syncClirSetting()V
Lcom/android/internal/telephony/ICarrierConfigLoader;->getConfigForSubId(ILjava/lang/String;)Landroid/os/PersistableBundle;
+Lcom/android/internal/telephony/IccCard;->getState()Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCard;->registerForNetworkLocked(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/IccCard;->supplyNetworkDepersonalization(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCard;->supplyPin(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCard;->supplyPuk(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->NOT_READY:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PERM_DISABLED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PIN_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->PUK_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->checkThread()V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->DBG:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mBaseHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mCurrentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mIs3gCard:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecords:Ljava/util/List;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecordSize:[I
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mSuccess:Z
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->updateEfForIccType(I)I
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->waitForResult(Ljava/util/concurrent/atomic/AtomicBoolean;)V
+Lcom/android/internal/telephony/IccProvider;-><init>()V
+Lcom/android/internal/telephony/IccProvider;->ADDRESS_BOOK_COLUMN_NAMES:[Ljava/lang/String;
+Lcom/android/internal/telephony/IccProvider;->DBG:Z
+Lcom/android/internal/telephony/IccProvider;->loadRecord(Lcom/android/internal/telephony/uicc/AdnRecord;Landroid/database/MatrixCursor;I)V
+Lcom/android/internal/telephony/IccProvider;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->copyMessageToIccEf(Ljava/lang/String;I[B[B)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableCdmaBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableGsmBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableCdmaBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableGsmBroadcastRange(II)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->enforceReceiveAndSend(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->filterDestAddress(Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getAllMessagesFromIccEf(Ljava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getImsSmsFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->getPremiumSmsPermission(Ljava/lang/String;)I
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->injectSmsPdu([BLjava/lang/String;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->isImsSmsSupported()Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mAppOps:Landroid/app/AppOpsManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mCellBroadcastRangeManager:Lcom/android/internal/telephony/IccSmsInterfaceManager$CellBroadcastRangeManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mHandler:Landroid/os/Handler;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSms:Ljava/util/List;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSuccess:Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredMultipartText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCdmaBroadcastConfig([Lcom/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo;)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCellBroadcastConfig([Lcom/android/internal/telephony/gsm/SmsBroadcastConfigInfo;)Z
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->setPremiumSmsPermission(Ljava/lang/String;I)V
+Lcom/android/internal/telephony/IccSmsInterfaceManager;->updateMessageOnIccEf(Ljava/lang/String;II[B)Z
+Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEfForSubscriber(II)Ljava/util/List;
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSize(I)[I
+Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I
+Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms;
+Lcom/android/internal/telephony/imsphone/ImsExternalCall;-><init>(Lcom/android/internal/telephony/Phone;Lcom/android/internal/telephony/imsphone/ImsExternalConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
+Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->rebuildCapabilities()V
+Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->setActive()V
+Lcom/android/internal/telephony/imsphone/ImsPhone$Cf;-><init>(Ljava/lang/String;ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getActionFromCFAction(I)I
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getBackgroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallForwardingOption(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallWaiting(Landroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getConditionFromCFReason(I)I
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getForegroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getRingingCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getServiceState()Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleEnterEmergencyCallbackMode()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleExitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isCfEnable(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isUtEnabled()Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFAction(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFReason(I)Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->isVolteEnabled()Z
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mCT:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mPendingMMIs:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->mSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyUnknownConnection(Lcom/android/internal/telephony/Connection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->onMMIDone(Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;Ljava/lang/Throwable;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallForwardingOption(IILjava/lang/String;IILandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallWaiting(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setImsRegistered(Z)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/imsphone/ImsPhone;->setServiceState(I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attach(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getConnections()Ljava/util/List;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->hangup()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->merge(Lcom/android/internal/telephony/imsphone/ImsPhoneCall;Lcom/android/internal/telephony/Call$State;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->onHangupLocal()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->addConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->clearDisconnected()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dial(Ljava/lang/String;ILandroid/os/Bundle;)Lcom/android/internal/telephony/Connection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dialPendingMO()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getUtInterface()Lcom/android/ims/ImsUtInterface;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->handleEcmTimer(I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mAllowEmergencyVideoCalls:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mConnections:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mForegroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mHandoverCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneId:I
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneStarted:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingMO:Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingUssd:Landroid/os/Message;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mRingingCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSwitchingFgAndBgCalls:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSyncHold:Ljava/lang/Object;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->removeConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->switchAfterConferenceSuccess()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->updatePhoneState()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->acquireWakeLock()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->createWakeLock(Landroid/content/Context;)V
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getOwner()Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->isMultiparty()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mDisconnected:Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mOwner:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mParent:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->onDisconnect()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getCLIRMode()I
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getDialingNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getErrorMessage(Landroid/os/AsyncResult;)Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getScString()Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isActivate()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isDeactivate()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isEmptyOrNull(Ljava/lang/CharSequence;)Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isErasure()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isRegister()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isSupportedOverImsPhone()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isTemporaryModeCLIR()Z
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/imsphone/ImsPhone;)Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->processCode()V
+Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->serviceClassToCFString(I)Ljava/lang/CharSequence;
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhere:Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhereArgs:[Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->deleteFromRawTable(Ljava/lang/String;[Ljava/lang/String;I)V
+Lcom/android/internal/telephony/InboundSmsHandler;->dispatchIntent(Landroid/content/Intent;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/UserHandle;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->dispatchNormalMessage(Lcom/android/internal/telephony/SmsMessageBase;)I
+Lcom/android/internal/telephony/InboundSmsHandler;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/InboundSmsHandler;->handleInjectSms(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->handleNewSms(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->handleSmsWhitelisting(Landroid/content/ComponentName;)Landroid/os/Bundle;
+Lcom/android/internal/telephony/InboundSmsHandler;->isSkipNotifyFlagSet(I)Z
+Lcom/android/internal/telephony/InboundSmsHandler;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/InboundSmsHandler;->mCellBroadcastHandler:Lcom/android/internal/telephony/CellBroadcastHandler;
+Lcom/android/internal/telephony/InboundSmsHandler;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/InboundSmsHandler;->mDeliveringState:Lcom/android/internal/telephony/InboundSmsHandler$DeliveringState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
+Lcom/android/internal/telephony/InboundSmsHandler;->mIdleState:Lcom/android/internal/telephony/InboundSmsHandler$IdleState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/InboundSmsHandler;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/InboundSmsHandler;->mUserManager:Landroid/os/UserManager;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWaitingState:Lcom/android/internal/telephony/InboundSmsHandler$WaitingState;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWakeLock:Landroid/os/PowerManager$WakeLock;
+Lcom/android/internal/telephony/InboundSmsHandler;->mWapPush:Lcom/android/internal/telephony/WapPushOverSms;
+Lcom/android/internal/telephony/InboundSmsHandler;->processMessagePart(Lcom/android/internal/telephony/InboundSmsTracker;)Z
+Lcom/android/internal/telephony/InboundSmsHandler;->showNewMessageNotification()V
+Lcom/android/internal/telephony/InboundSmsHandler;->writeInboxMessage(Landroid/content/Intent;)Landroid/net/Uri;
+Lcom/android/internal/telephony/InboundSmsTracker;->getFormat()Ljava/lang/String;
+Lcom/android/internal/telephony/InboundSmsTracker;->getIndexOffset()I
+Lcom/android/internal/telephony/IntRangeManager;->mRanges:Ljava/util/ArrayList;
Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
@@ -2060,16 +3272,808 @@
Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
Lcom/android/internal/telephony/IWapPushManager;->updatePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
+Lcom/android/internal/telephony/MccTable$MccEntry;->mIso:Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->countryCodeForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->defaultLanguageForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->defaultTimeZoneForMcc(I)Ljava/lang/String;
+Lcom/android/internal/telephony/MccTable;->entryForMcc(I)Lcom/android/internal/telephony/MccTable$MccEntry;
+Lcom/android/internal/telephony/MccTable;->getLocaleForLanguageCountry(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
+Lcom/android/internal/telephony/MccTable;->smallestDigitsMccForMnc(I)I
+Lcom/android/internal/telephony/MmiCode$State;->CANCELLED:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->COMPLETE:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->FAILED:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode$State;->PENDING:Lcom/android/internal/telephony/MmiCode$State;
+Lcom/android/internal/telephony/MmiCode;->getPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->dispose()V
+Lcom/android/internal/telephony/Phone;->exitEmergencyCallbackMode()V
+Lcom/android/internal/telephony/Phone;->getActiveApnTypes()[Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
+Lcom/android/internal/telephony/Phone;->getCellLocation()Landroid/telephony/CellLocation;
+Lcom/android/internal/telephony/Phone;->getContext()Landroid/content/Context;
+Lcom/android/internal/telephony/Phone;->getDataConnectionState()Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/Phone;->getIccCard()Lcom/android/internal/telephony/IccCard;
+Lcom/android/internal/telephony/Phone;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/Phone;->getIccSerialNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getIccSmsInterfaceManager()Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/Phone;->getImsPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->getIsimRecords()Lcom/android/internal/telephony/uicc/IsimRecords;
+Lcom/android/internal/telephony/Phone;->getMsisdn()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getNai()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getPhoneId()I
+Lcom/android/internal/telephony/Phone;->getPhoneName()Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getPhoneType()I
+Lcom/android/internal/telephony/Phone;->getServiceStateTracker()Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/Phone;->getSmscAddress(Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/Phone;->getSubId()I
+Lcom/android/internal/telephony/Phone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/Phone;->getUiccCard()Lcom/android/internal/telephony/uicc/UiccCard;
+Lcom/android/internal/telephony/Phone;->getVideoState(Lcom/android/internal/telephony/Call;)I
+Lcom/android/internal/telephony/Phone;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->invokeOemRilRequestStrings([Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->isCspPlmnEnabled()Z
+Lcom/android/internal/telephony/Phone;->isUtEnabled()Z
+Lcom/android/internal/telephony/Phone;->isVideoEnabled()Z
+Lcom/android/internal/telephony/Phone;->isVolteEnabled()Z
+Lcom/android/internal/telephony/Phone;->isWifiCallingEnabled()Z
+Lcom/android/internal/telephony/Phone;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/Phone;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/Phone;->mDcTracker:Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/Phone;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/Phone;->mImsPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/Phone;->mMmiRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/Phone;->mNotifier:Lcom/android/internal/telephony/PhoneNotifier;
+Lcom/android/internal/telephony/Phone;->mPhoneId:I
+Lcom/android/internal/telephony/Phone;->mSmsStorageMonitor:Lcom/android/internal/telephony/SmsStorageMonitor;
+Lcom/android/internal/telephony/Phone;->mUiccApplication:Ljava/util/concurrent/atomic/AtomicReference;
+Lcom/android/internal/telephony/Phone;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/Phone;->needsOtaServiceProvisioning()Z
+Lcom/android/internal/telephony/Phone;->notifyOtaspChanged(I)V
+Lcom/android/internal/telephony/Phone;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForEcmTimerReset(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForIncomingRing(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForMmiComplete(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForMmiInitiate(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForRingbackTone(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForServiceStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForSimRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->registerForUnknownConnection(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->selectNetworkManually(Lcom/android/internal/telephony/OperatorInfo;ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->setOnPostDialCharacter(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/Phone;->unregisterForDisconnect(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForEcmTimerReset(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForIncomingRing(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForMmiComplete(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForMmiInitiate(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForRingbackTone(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForServiceStateChanged(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForSimRecordsLoaded(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unregisterForUnknownConnection(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/Phone;->unsetOnEcbModeExitResponse(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->SUSPENDED:Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$DataState;->values()[Lcom/android/internal/telephony/PhoneConstants$DataState;
+Lcom/android/internal/telephony/PhoneConstants$State;->IDLE:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->OFFHOOK:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->RINGING:Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants$State;->values()[Lcom/android/internal/telephony/PhoneConstants$State;
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_ALLOWED:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I
+Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I
+Lcom/android/internal/telephony/PhoneFactory;->calculatePreferredNetworkType(Landroid/content/Context;I)I
+Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->getDefaultSubscription()I
+Lcom/android/internal/telephony/PhoneFactory;->getPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->getPhones()[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneFactory;->makeDefaultPhone(Landroid/content/Context;)V
+Lcom/android/internal/telephony/PhoneFactory;->sCommandsInterface:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/PhoneFactory;->sContext:Landroid/content/Context;
+Lcom/android/internal/telephony/PhoneFactory;->sMadeDefaults:Z
+Lcom/android/internal/telephony/PhoneFactory;->sPhoneNotifier:Lcom/android/internal/telephony/PhoneNotifier;
+Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;->NONE:Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;
+Lcom/android/internal/telephony/PhoneInternalInterface;->PREFERRED_NT_MODE:I
+Lcom/android/internal/telephony/PhoneNotifier;->notifyMessageWaitingChanged(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/PhoneNotifier;->notifySignalStrength(Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;-><init>(Landroid/content/Context;Landroid/os/Handler;)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->getSignalStrengthDbm()I
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mSignalStrength:Landroid/telephony/SignalStrength;
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mWants:I
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifyServiceState(I)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifySignalStrength(I)V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->registerIntent()V
+Lcom/android/internal/telephony/PhoneStateIntentReceiver;->unregisterIntent()V
+Lcom/android/internal/telephony/PhoneSubInfoController;->getDefaultSubscription()I
+Lcom/android/internal/telephony/PhoneSubInfoController;->getPhone(I)Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneSubInfoController;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/PhoneSubInfoController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/PhoneSubInfoController;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/PhoneSwitcher;->activate(I)V
+Lcom/android/internal/telephony/PhoneSwitcher;->deactivate(I)V
+Lcom/android/internal/telephony/PhoneSwitcher;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/PhoneSwitcher;->mMaxActivePhones:I
+Lcom/android/internal/telephony/PhoneSwitcher;->mNumPhones:I
+Lcom/android/internal/telephony/PhoneSwitcher;->mPhones:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/ProxyController;->completeRadioCapabilityTransaction()V
+Lcom/android/internal/telephony/ProxyController;->getInstance()Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/ProxyController;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ProxyController;->mOldRadioAccessFamily:[I
+Lcom/android/internal/telephony/ProxyController;->mRadioCapabilitySessionId:I
+Lcom/android/internal/telephony/ProxyController;->mSetRadioAccessFamilyStatus:[I
+Lcom/android/internal/telephony/ProxyController;->mUniqueIdGenerator:Ljava/util/concurrent/atomic/AtomicInteger;
+Lcom/android/internal/telephony/ProxyController;->registerForAllDataDisconnected(ILandroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/ProxyController;->sendRadioCapabilityRequest(IIIILjava/lang/String;II)V
+Lcom/android/internal/telephony/ProxyController;->sProxyController:Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/RadioCapability;->getRadioAccessFamily()I
+Lcom/android/internal/telephony/RetryManager;->configure(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/RetryManager;->getRetryTimer()I
+Lcom/android/internal/telephony/RetryManager;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/RetryManager;->mApnType:Ljava/lang/String;
+Lcom/android/internal/telephony/RetryManager;->mFailFastInterApnDelay:J
+Lcom/android/internal/telephony/RetryManager;->mInterApnDelay:J
+Lcom/android/internal/telephony/RetryManager;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;II)V
+Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;IILjava/lang/Integer;)V
+Lcom/android/internal/telephony/RIL;->acquireWakeLock(Lcom/android/internal/telephony/RILRequest;I)V
+Lcom/android/internal/telephony/RIL;->clearRequestList(IZ)V
+Lcom/android/internal/telephony/RIL;->clearWakeLock(I)Z
+Lcom/android/internal/telephony/RIL;->decrementWakeLock(Lcom/android/internal/telephony/RILRequest;)V
+Lcom/android/internal/telephony/RIL;->findAndRemoveRequestFromList(I)Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RIL;->getResponseForTimedOutRILRequest(Lcom/android/internal/telephony/RILRequest;)Ljava/lang/Object;
+Lcom/android/internal/telephony/RIL;->hangupForegroundResumeBackground(Landroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->hangupWaitingOrBackground(Landroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->makeStaticRadioCapability()Lcom/android/internal/telephony/RadioCapability;
+Lcom/android/internal/telephony/RIL;->mRequestList:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/RIL;->mTestingEmergencyCall:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/RIL;->mWakeLock:Landroid/os/PowerManager$WakeLock;
+Lcom/android/internal/telephony/RIL;->notifyRegistrantsCdmaInfoRec(Lcom/android/internal/telephony/cdma/CdmaInformationRecords;)V
+Lcom/android/internal/telephony/RIL;->notifyRegistrantsRilConnectionChanged(I)V
+Lcom/android/internal/telephony/RIL;->requestToString(I)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->responseToString(I)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->retToString(ILjava/lang/Object;)Ljava/lang/String;
+Lcom/android/internal/telephony/RIL;->riljLog(Ljava/lang/String;)V
+Lcom/android/internal/telephony/RIL;->setRadioPower(ZLandroid/os/Message;)V
+Lcom/android/internal/telephony/RIL;->unsljLog(I)V
+Lcom/android/internal/telephony/RIL;->unsljLogMore(ILjava/lang/String;)V
+Lcom/android/internal/telephony/RIL;->unsljLogRet(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RIL;->unsljLogvRet(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I
+Lcom/android/internal/telephony/RILRequest;->mRequest:I
+Lcom/android/internal/telephony/RILRequest;->mResult:Landroid/os/Message;
+Lcom/android/internal/telephony/RILRequest;->mSerial:I
+Lcom/android/internal/telephony/RILRequest;->obtain(ILandroid/os/Message;)Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RILRequest;->onError(ILjava/lang/Object;)V
+Lcom/android/internal/telephony/RILRequest;->release()V
+Lcom/android/internal/telephony/RILRequest;->serialString()Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->fixUnknownMcc(Ljava/lang/String;I)Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->getCurrentDataConnectionState()I
+Lcom/android/internal/telephony/ServiceStateTracker;->getDesiredPowerState()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->getPhoneId()I
+Lcom/android/internal/telephony/ServiceStateTracker;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->isConcurrentVoiceAndDataAllowed()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isGprsConsistent(II)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isImsRegistered()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isInHomeSidNid(II)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->isInvalidOperatorNumeric(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/ServiceStateTracker;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->mAttachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCr:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurDataSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurPlmn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowPlmn:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowSpn:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mCurSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOffRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOnRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDefaultRoamingIndicator:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mDesiredPowerState:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mDetachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mDeviceShuttingDown:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mEmergencyOnly:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/ServiceStateTracker;->mIntentReceiver:Landroid/content/BroadcastReceiver;
+Lcom/android/internal/telephony/ServiceStateTracker;->mIsSubscriptionFromRuim:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mMaxDataCalls:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNetworkAttachedRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewMaxDataCalls:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewReasonDataDenied:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mNewSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/ServiceStateTracker;->mOnSubscriptionsChangedListener:Lcom/android/internal/telephony/ServiceStateTracker$SstSubscriptionsChangedListener;
+Lcom/android/internal/telephony/ServiceStateTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/ServiceStateTracker;->mPreferredNetworkType:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mReasonDataDenied:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mReportedGprsNoReg:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mRoamingIndicator:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mSignalStrength:Landroid/telephony/SignalStrength;
+Lcom/android/internal/telephony/ServiceStateTracker;->mSpnUpdatePending:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mSS:Landroid/telephony/ServiceState;
+Lcom/android/internal/telephony/ServiceStateTracker;->mStartedGprsRegCheck:Z
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubId:I
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionController:Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
+Lcom/android/internal/telephony/ServiceStateTracker;->mUiccApplcation:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/ServiceStateTracker;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOffRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOnRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/ServiceStateTracker;->notifyDataRegStateRilRadioTechnologyChanged()V
+Lcom/android/internal/telephony/ServiceStateTracker;->notifySignalStrength()Z
+Lcom/android/internal/telephony/ServiceStateTracker;->pollState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->powerOffRadioSafely(Lcom/android/internal/telephony/dataconnection/DcTracker;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->reRegisterNetwork(Landroid/os/Message;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->resetServiceStateInIwlanMode()V
+Lcom/android/internal/telephony/ServiceStateTracker;->setOperatorIdd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->setRoamingType(Landroid/telephony/ServiceState;)V
+Lcom/android/internal/telephony/ServiceStateTracker;->setSignalStrengthDefaultValues()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateOtaspState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updatePhoneObject()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateRoamingState()V
+Lcom/android/internal/telephony/ServiceStateTracker;->updateSpnDisplay()V
+Lcom/android/internal/telephony/ServiceStateTracker;->useDataRegStateForDataOnlyDevices()V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V
+Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V
+Lcom/android/internal/telephony/sip/SipPhone;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/sip/SipPhone;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/sip/SipPhone;->mBackgroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
+Lcom/android/internal/telephony/sip/SipPhone;->mForegroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->DBG:Z
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCDMA:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCommon:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableGSM:Landroid/util/SparseIntArray;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->translate(Ljava/lang/CharSequence;)Ljava/lang/String;
+Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->useCdmaFormatForMoSms()Z
+Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;->mApplicationName:Ljava/lang/String;
+Lcom/android/internal/telephony/SmsApplication;->configurePreferredActivity(Landroid/content/pm/PackageManager;Landroid/content/ComponentName;I)V
+Lcom/android/internal/telephony/SmsApplication;->getApplicationCollection(Landroid/content/Context;)Ljava/util/Collection;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultMmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultRespondViaMessageApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getDefaultSmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName;
+Lcom/android/internal/telephony/SmsApplication;->getSmsApplicationData(Ljava/lang/String;Landroid/content/Context;)Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;
+Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z
+Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V
+Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z
+Lcom/android/internal/telephony/SmsBroadcastUndelivered;-><init>(Landroid/content/Context;Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;)V
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mNegativeButton:Landroid/widget/Button;
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mPositiveButton:Landroid/widget/Button;
+Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mRememberUndoInstruction:Landroid/widget/TextView;
+Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;->sendSmsByCarrierApp(Ljava/lang/String;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;)V
+Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->isMultipart()Z
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mAppInfo:Landroid/content/pm/PackageInfo;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mData:Ljava/util/HashMap;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDeliveryIntent:Landroid/app/PendingIntent;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDestAddress:Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageRef:I
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageUri:Landroid/net/Uri;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mPersistMessage:Z
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mSentIntent:Landroid/app/PendingIntent;
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mTimestamp:J
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onFailed(Landroid/content/Context;II)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onSent(Landroid/content/Context;)V
+Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->updateSentMessageStatus(Landroid/content/Context;I)V
+Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
+Lcom/android/internal/telephony/SMSDispatcher;->checkCallerIsPhoneOrCarrierApp()V
+Lcom/android/internal/telephony/SMSDispatcher;->deliveryPendingList:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/SMSDispatcher;->dispose()V
+Lcom/android/internal/telephony/SMSDispatcher;->getCarrierAppPackageName()Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher;->getMultipartMessageText(Ljava/util/ArrayList;)Ljava/lang/String;
+Lcom/android/internal/telephony/SMSDispatcher;->getNextConcatenatedRef()I
+Lcom/android/internal/telephony/SMSDispatcher;->getSubId()I
+Lcom/android/internal/telephony/SMSDispatcher;->handleConfirmShortCode(ZLcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/SMSDispatcher;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SMSDispatcher;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/SMSDispatcher;->mResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/telephony/SMSDispatcher;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/android/internal/telephony/SMSDispatcher;->processSendSmsResponse(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;II)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendData(Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendMultipartSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
+Lcom/android/internal/telephony/SMSDispatcher;->sendSubmitPdu(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
+Lcom/android/internal/telephony/SmsResponse;-><init>(ILjava/lang/String;I)V
+Lcom/android/internal/telephony/SmsResponse;->mAckPdu:Ljava/lang/String;
+Lcom/android/internal/telephony/SmsResponse;->mErrorCode:I
+Lcom/android/internal/telephony/SmsResponse;->mMessageRef:I
+Lcom/android/internal/telephony/SmsStorageMonitor;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/SmsUsageMonitor;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/telephony/SmsUsageMonitor;->check(Ljava/lang/String;I)Z
+Lcom/android/internal/telephony/SubscriptionController;->broadcastDefaultDataSubIdChanged(I)V
+Lcom/android/internal/telephony/SubscriptionController;->colorArr:[I
+Lcom/android/internal/telephony/SubscriptionController;->enforceModifyPhoneState(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubInfoCount(Ljava/lang/String;)I
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfo(ILjava/lang/String;)Landroid/telephony/SubscriptionInfo;
+Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfoList(Ljava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultDataSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultSmsSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDefaultVoiceSubId()I
+Lcom/android/internal/telephony/SubscriptionController;->getDummySubIds(I)[I
+Lcom/android/internal/telephony/SubscriptionController;->getInstance()Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/SubscriptionController;->getPhoneId(I)I
+Lcom/android/internal/telephony/SubscriptionController;->getSubId(I)[I
+Lcom/android/internal/telephony/SubscriptionController;->getSubIdUsingPhoneId(I)I
+Lcom/android/internal/telephony/SubscriptionController;->getSubInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/util/List;
+Lcom/android/internal/telephony/SubscriptionController;->getSubInfoRecord(Landroid/database/Cursor;)Landroid/telephony/SubscriptionInfo;
+Lcom/android/internal/telephony/SubscriptionController;->isActiveSubId(I)Z
+Lcom/android/internal/telephony/SubscriptionController;->isSubInfoReady()Z
+Lcom/android/internal/telephony/SubscriptionController;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->logdl(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SubscriptionController;->mDefaultPhoneId:I
+Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z
+Lcom/android/internal/telephony/SubscriptionController;->updateAllDataConnectionTrackers()V
+Lcom/android/internal/telephony/SubscriptionController;->validateSubId(I)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->broadcastSimStateChanged(ILjava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->isAllIccIdQueryDone()Z
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->logd(Ljava/lang/String;)V
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
+Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
+Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
+Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z
+Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V
+Lcom/android/internal/telephony/test/SimulatedCommands;->simulatedCallState:Lcom/android/internal/telephony/test/SimulatedGsmCallState;
+Lcom/android/internal/telephony/test/SimulatedCommands;->unimplemented(Landroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->getInstance()Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;
+Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->conference()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->onChld(CC)Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseActiveAcceptHeldOrWaiting()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z
+Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(II[B)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecord;-><init>([B)V
+Lcom/android/internal/telephony/uicc/AdnRecord;->buildAdnString(I)[B
+Lcom/android/internal/telephony/uicc/AdnRecord;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/telephony/uicc/AdnRecord;->getEmails()[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->getNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->isEmpty()Z
+Lcom/android/internal/telephony/uicc/AdnRecord;->mAlphaTag:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mEfid:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->mEmails:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mExtRecord:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->mNumber:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecord;->mRecordNumber:I
+Lcom/android/internal/telephony/uicc/AdnRecord;->setEmails([Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->extensionEfForEf(I)I
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->getRecordsIfLoaded(I)Ljava/util/ArrayList;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mAdnLikeWaiters:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUserWriteResponse:Landroid/util/SparseArray;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUsimPhoneBookManager:Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->reset()V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->sendErrorResponse(Landroid/os/Message;Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/AdnRecordCache;->updateAdnByIndex(ILcom/android/internal/telephony/uicc/AdnRecord;ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;-><init>(Lcom/android/internal/telephony/uicc/IccFileHandler;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->getEFPath(I)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->loadFromEF(IIILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/AdnRecordLoader;->updateEF(Lcom/android/internal/telephony/uicc/AdnRecord;IIILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_DETECTED:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PIN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_READY:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_SUBSCRIPTION_PERSO:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_CSIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_ISIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_RUIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_SIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_USIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->AppTypeFromRILInt(I)Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->app_type:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ABSENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ERROR:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_PRESENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->isCardPresent()Z
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_DISABLED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_PERM_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mApplications:[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mCdmaSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mGsmUmtsSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mImsSubscriptionAppIndex:I
+Lcom/android/internal/telephony/uicc/IccCardStatus;->mUniversalPinState:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;-><init>(IILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->mRecordSize:I
+Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->results:Ljava/util/ArrayList;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFPath(I)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(IILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(ILjava/lang/String;ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFTransparent(ILandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mAid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(II[BLjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(ILjava/lang/String;I[BLjava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFTransparent(I[BLandroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(IILjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(II[B)V
+Lcom/android/internal/telephony/uicc/IccIoResult;->payload:[B
+Lcom/android/internal/telephony/uicc/IccIoResult;->success()Z
+Lcom/android/internal/telephony/uicc/IccIoResult;->sw1:I
+Lcom/android/internal/telephony/uicc/IccIoResult;->sw2:I
+Lcom/android/internal/telephony/uicc/IccRecords;->auth_rsp:Lcom/android/internal/telephony/uicc/IccIoResult;
+Lcom/android/internal/telephony/uicc/IccRecords;->getGid1()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIccId()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIccSimChallengeResponse(ILjava/lang/String;)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getIMSI()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getMsisdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getRecordsLoaded()Z
+Lcom/android/internal/telephony/uicc/IccRecords;->getServiceProviderName()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->getUsimServiceTable()Lcom/android/internal/telephony/uicc/UsimServiceTable;
+Lcom/android/internal/telephony/uicc/IccRecords;->handleRefresh(Lcom/android/internal/telephony/uicc/IccRefreshResponse;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/uicc/IccRecords;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/IccRecords;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/IccRecords;->mDestroyed:Ljava/util/concurrent/atomic/AtomicBoolean;
+Lcom/android/internal/telephony/uicc/IccRecords;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/IccRecords;->mGid1:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mIccId:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mImsi:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mIsVoiceMailFixed:Z
+Lcom/android/internal/telephony/uicc/IccRecords;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/IccRecords;->mMncLength:I
+Lcom/android/internal/telephony/uicc/IccRecords;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsEventsRegistrants:Landroid/os/RegistrantList;
+Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsToLoad:I
+Lcom/android/internal/telephony/uicc/IccRecords;->mSpn:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/android/internal/telephony/uicc/IccRecords;->mVoiceMailNum:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForNetworkSelectionModeAutomatic(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForNewSms(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsEvents(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->setMsisdnNumber(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNetworkSelectionModeAutomatic(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNewSms(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsEvents(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsLoaded(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->aid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->efId:I
+Lcom/android/internal/telephony/uicc/IccRefreshResponse;->refreshResult:I
+Lcom/android/internal/telephony/uicc/IccServiceTable;->getTag()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccServiceTable;->mServiceTable:[B
+Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String;
Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdByteToInt(B)I
+Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->gsmBcdByteToInt(B)I
+Lcom/android/internal/telephony/uicc/IccUtils;->hexCharToInt(C)I
+Lcom/android/internal/telephony/uicc/IccUtils;->hexStringToBytes(Ljava/lang/String;)[B
+Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap;
+Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimDomain()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpi()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpu()[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->auth_rsp:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->fetchIsimRecords()V
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->isimTlvToString([B)Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimDomain:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpi:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpu:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimIst:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimPcscf:[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/RuimRecords;->adjstMinDigits(I)I
+Lcom/android/internal/telephony/uicc/RuimRecords;->fetchRuimRecords()V
+Lcom/android/internal/telephony/uicc/RuimRecords;->getAssetLanguages(Landroid/content/Context;)[Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getCsimSpnDisplayCondition()Z
+Lcom/android/internal/telephony/uicc/RuimRecords;->getMdn()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getMdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->getRUIMOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/RuimRecords;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/RuimRecords;->mEFli:[B
+Lcom/android/internal/telephony/uicc/RuimRecords;->mEFpl:[B
+Lcom/android/internal/telephony/uicc/RuimRecords;->mMin:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->mNai:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/RuimRecords;->onGetCSimEprlDone(Landroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->INIT:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_3GPP:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_SHORT_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
+Lcom/android/internal/telephony/uicc/SIMRecords;->fetchSimRecords()V
+Lcom/android/internal/telephony/uicc/SIMRecords;->getExtFromEf(I)I
+Lcom/android/internal/telephony/uicc/SIMRecords;->getMsisdnNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->getOperatorNumeric()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->getSpnFsm(ZLandroid/os/AsyncResult;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->getVoiceMailNumber()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/SIMRecords;->isCphsMailboxEnabled()Z
+Lcom/android/internal/telephony/uicc/SIMRecords;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->logv(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCff:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCfis:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCPHS_MWI:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfLi:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfMWIS:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mEfPl:[B
+Lcom/android/internal/telephony/uicc/SIMRecords;->mSpnDisplayCondition:I
+Lcom/android/internal/telephony/uicc/SIMRecords;->mUsimServiceTable:Lcom/android/internal/telephony/uicc/UsimServiceTable;
+Lcom/android/internal/telephony/uicc/SIMRecords;->mVmConfig:Lcom/android/internal/telephony/uicc/VoiceMailConstants;
+Lcom/android/internal/telephony/uicc/SIMRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplication(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationByType(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationIndex(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccCard;->getCardState()Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/UiccCard;->getCarrierPackageNamesForIntent(Landroid/content/pm/PackageManager;Landroid/content/Intent;)Ljava/util/List;
+Lcom/android/internal/telephony/uicc/UiccCard;->getIccId()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCard;->getNumApplications()I
+Lcom/android/internal/telephony/uicc/UiccCard;->getOperatorBrandOverride()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCard;->isApplicationOnIcc(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;)Z
+Lcom/android/internal/telephony/uicc/UiccCard;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCard;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
+Lcom/android/internal/telephony/uicc/UiccCard;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccCard;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/UiccCard;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccCard;->mPhoneId:I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->dispose()V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAid()Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAuthContext()I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccRecords()Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPersoSubState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPhoneId()I
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPin1State()Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->getType()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->loge(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAid:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppType:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mCi:Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mDestroyed:Z
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPersoSubState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPin1State:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->registerForReady(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->unregisterForReady(Landroid/os/Handler;)V
+Lcom/android/internal/telephony/uicc/UiccCardApplication;->update(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;)V
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->length:Ljava/lang/Integer;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->value:Ljava/lang/String;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mLoadedCallback:Landroid/os/Message;
+Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mState:Ljava/util/concurrent/atomic/AtomicInteger;
+Lcom/android/internal/telephony/uicc/UiccController;->getIccFileHandler(II)Lcom/android/internal/telephony/uicc/IccFileHandler;
+Lcom/android/internal/telephony/uicc/UiccController;->getIccRecords(II)Lcom/android/internal/telephony/uicc/IccRecords;
+Lcom/android/internal/telephony/uicc/UiccController;->getInstance()Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccController;->getUiccCard(I)Lcom/android/internal/telephony/uicc/UiccCard;
+Lcom/android/internal/telephony/uicc/UiccController;->getUiccCardApplication(II)Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccController;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/uicc/UiccController;->mCis:[Lcom/android/internal/telephony/CommandsInterface;
+Lcom/android/internal/telephony/uicc/UiccController;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/uicc/UiccController;->mInstance:Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccController;->mLock:Ljava/lang/Object;
+Lcom/android/internal/telephony/uicc/UiccController;->registerForIccChanged(Landroid/os/Handler;ILjava/lang/Object;)V
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->ALLOWED_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CFI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CSG_DISPLAY_CONTROL:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->FDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MBDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MSISDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MWI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_PLMN_LIST:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->PLMN_NETWORK_NAME:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_OVER_IP:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_SERVICE_PARAMS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_STORAGE:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SPN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
+Lcom/android/internal/telephony/uicc/UsimServiceTable;->isAvailable(Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;)Z
+Lcom/android/internal/telephony/uicc/VoiceMailConstants;-><init>()V
+Lcom/android/internal/telephony/UiccPhoneBookController;-><init>([Lcom/android/internal/telephony/Phone;)V
+Lcom/android/internal/telephony/UiccPhoneBookController;->getDefaultSubscription()I
+Lcom/android/internal/telephony/UiccPhoneBookController;->getIccPhoneBookInterfaceManager(I)Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
+Lcom/android/internal/telephony/UiccPhoneBookController;->mPhone:[Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/UiccSmsController;->copyMessageToIccEfForSubscriber(ILjava/lang/String;I[B[B)Z
+Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastForSubscriber(III)Z
+Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastRangeForSubscriber(IIII)Z
+Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastForSubscriber(III)Z
+Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastRangeForSubscriber(IIII)Z
+Lcom/android/internal/telephony/UiccSmsController;->getAllMessagesFromIccEfForSubscriber(ILjava/lang/String;)Ljava/util/List;
+Lcom/android/internal/telephony/UiccSmsController;->getIccSmsInterfaceManager(I)Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/UiccSmsController;->getImsSmsFormatForSubscriber(I)Ljava/lang/String;
+Lcom/android/internal/telephony/UiccSmsController;->getPreferredSmsSubscription()I
+Lcom/android/internal/telephony/UiccSmsController;->isImsSmsSupportedForSubscriber(I)Z
+Lcom/android/internal/telephony/UiccSmsController;->sendDataForSubscriber(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
+Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntent(Landroid/app/PendingIntent;I)V
+Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntents(Ljava/util/List;I)V
+Lcom/android/internal/telephony/UiccSmsController;->updateMessageOnIccEfForSubscriber(ILjava/lang/String;II[B)Z
+Lcom/android/internal/telephony/UUSInfo;->getDcs()I
+Lcom/android/internal/telephony/UUSInfo;->getType()I
+Lcom/android/internal/telephony/UUSInfo;->getUserData()[B
+Lcom/android/internal/telephony/WakeLockStateMachine;->log(Ljava/lang/String;)V
+Lcom/android/internal/telephony/WakeLockStateMachine;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/WakeLockStateMachine;->mIdleState:Lcom/android/internal/telephony/WakeLockStateMachine$IdleState;
+Lcom/android/internal/telephony/WakeLockStateMachine;->mPhone:Lcom/android/internal/telephony/Phone;
+Lcom/android/internal/telephony/WapPushOverSms;->dispatchWapPdu([BLandroid/content/BroadcastReceiver;Lcom/android/internal/telephony/InboundSmsHandler;)I
+Lcom/android/internal/telephony/WapPushOverSms;->getDeliveryOrReadReportThreadId(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)J
+Lcom/android/internal/telephony/WapPushOverSms;->isDuplicateNotification(Landroid/content/Context;Lcom/google/android/mms/pdu/NotificationInd;)Z
+Lcom/android/internal/telephony/WapPushOverSms;->isWapPushForMms([BLcom/android/internal/telephony/InboundSmsHandler;)Z
+Lcom/android/internal/telephony/WapPushOverSms;->mContext:Landroid/content/Context;
+Lcom/android/internal/telephony/WapPushOverSms;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
+Lcom/android/internal/telephony/WapPushOverSms;->mWapPushManager:Lcom/android/internal/telephony/IWapPushManager;
+Lcom/android/internal/telephony/WspTypeDecoder;-><init>([B)V
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeContentType(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeIntegerValue(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeShortInteger(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeTextString(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeUintvarInteger(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeValueLength(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->decodeXWapApplicationId(I)Z
+Lcom/android/internal/telephony/WspTypeDecoder;->getContentParameters()Ljava/util/HashMap;
+Lcom/android/internal/telephony/WspTypeDecoder;->getDecodedDataLength()I
+Lcom/android/internal/telephony/WspTypeDecoder;->getValue32()J
+Lcom/android/internal/telephony/WspTypeDecoder;->getValueString()Ljava/lang/String;
+Lcom/android/internal/telephony/WspTypeDecoder;->mWspData:[B
+Lcom/android/internal/telephony/WspTypeDecoder;->seekXWapApplicationId(II)Z
Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/util/ArrayUtils;->appendElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I
+Lcom/android/internal/util/ArrayUtils;->contains([II)Z
+Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->emptyArray(Ljava/lang/Class;)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I
+Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedArray(Ljava/lang/Class;I)[Ljava/lang/Object;
+Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I
+Lcom/android/internal/util/ArrayUtils;->removeElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/BitwiseInputStream;-><init>([B)V
+Lcom/android/internal/util/BitwiseInputStream;->available()I
+Lcom/android/internal/util/BitwiseInputStream;->read(I)I
+Lcom/android/internal/util/BitwiseInputStream;->readByteArray(I)[B
+Lcom/android/internal/util/BitwiseInputStream;->skip(I)V
+Lcom/android/internal/util/BitwiseOutputStream;-><init>(I)V
+Lcom/android/internal/util/BitwiseOutputStream;->toByteArray()[B
+Lcom/android/internal/util/BitwiseOutputStream;->write(II)V
+Lcom/android/internal/util/BitwiseOutputStream;->writeByteArray(I[B)V
+Lcom/android/internal/util/CharSequences;->compareToIgnoreCase(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)I
+Lcom/android/internal/util/CharSequences;->equals(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Z
+Lcom/android/internal/util/FastMath;->round(F)I
+Lcom/android/internal/util/FastXmlSerializer;-><init>()V
+Lcom/android/internal/util/GrowingArrayUtils;->append([III)[I
+Lcom/android/internal/util/GrowingArrayUtils;->append([Ljava/lang/Object;ILjava/lang/Object;)[Ljava/lang/Object;
+Lcom/android/internal/util/HexDump;->hexStringToByteArray(Ljava/lang/String;)[B
+Lcom/android/internal/util/HexDump;->toHexString(I)Ljava/lang/String;
+Lcom/android/internal/util/HexDump;->toHexString([B)Ljava/lang/String;
+Lcom/android/internal/util/HexDump;->toHexString([BII)Ljava/lang/String;
Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String;
+Lcom/android/internal/util/IState;->getName()Ljava/lang/String;
+Lcom/android/internal/util/MemInfoReader;-><init>()V
+Lcom/android/internal/util/MemInfoReader;->getCachedSize()J
+Lcom/android/internal/util/MemInfoReader;->getFreeSize()J
+Lcom/android/internal/util/MemInfoReader;->getRawInfo()[J
+Lcom/android/internal/util/MemInfoReader;->getTotalSize()J
+Lcom/android/internal/util/MemInfoReader;->readMemInfo()V
+Lcom/android/internal/util/Preconditions;->checkArgument(Z)V
+Lcom/android/internal/util/Preconditions;->checkArgument(ZLjava/lang/Object;)V
+Lcom/android/internal/util/Preconditions;->checkArgumentInRange(IIILjava/lang/String;)I
+Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/android/internal/util/Preconditions;->checkState(Z)V
+Lcom/android/internal/util/Preconditions;->checkState(ZLjava/lang/String;)V
+Lcom/android/internal/util/State;-><init>()V
+Lcom/android/internal/util/State;->enter()V
+Lcom/android/internal/util/State;->exit()V
+Lcom/android/internal/util/State;->getName()Ljava/lang/String;
+Lcom/android/internal/util/State;->processMessage(Landroid/os/Message;)Z
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;)V
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Handler;)V
+Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Looper;)V
+Lcom/android/internal/util/StateMachine;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V
+Lcom/android/internal/util/StateMachine;->obtainMessage(III)Landroid/os/Message;
+Lcom/android/internal/util/StateMachine;->obtainMessage(IIILjava/lang/Object;)Landroid/os/Message;
+Lcom/android/internal/util/StateMachine;->sendMessage(I)V
+Lcom/android/internal/util/StateMachine;->sendMessage(II)V
+Lcom/android/internal/util/StateMachine;->sendMessage(IIILjava/lang/Object;)V
+Lcom/android/internal/util/StateMachine;->sendMessage(ILjava/lang/Object;)V
+Lcom/android/internal/util/StateMachine;->sendMessage(Landroid/os/Message;)V
+Lcom/android/internal/view/ActionBarPolicy;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/ActionBarPolicy;->get(Landroid/content/Context;)Lcom/android/internal/view/ActionBarPolicy;
+Lcom/android/internal/view/ActionBarPolicy;->getEmbeddedMenuWidthLimit()I
+Lcom/android/internal/view/ActionBarPolicy;->getMaxActionButtons()I
+Lcom/android/internal/view/ActionBarPolicy;->getStackedTabMaxWidth()I
+Lcom/android/internal/view/ActionBarPolicy;->getTabContainerHeight()I
+Lcom/android/internal/view/ActionBarPolicy;->hasEmbeddedTabs()Z
+Lcom/android/internal/view/ActionBarPolicy;->mContext:Landroid/content/Context;
+Lcom/android/internal/view/ActionBarPolicy;->showsOverflowMenuButton()Z
Lcom/android/internal/view/BaseIWindow;-><init>()V
Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession;
+Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->dispose()V
+Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->getInstance()Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;
+Lcom/android/internal/view/menu/ActionMenu;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/menu/ActionMenuItem;-><init>(Landroid/content/Context;IIIILjava/lang/CharSequence;)V
+Lcom/android/internal/view/menu/ContextMenuBuilder;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/view/menu/IconMenuItemView;->getTextAppropriateLayoutParams()Lcom/android/internal/view/menu/IconMenuView$LayoutParams;
+Lcom/android/internal/view/menu/IconMenuItemView;->setIconMenuView(Lcom/android/internal/view/menu/IconMenuView;)V
+Lcom/android/internal/view/menu/IconMenuItemView;->setItemInvoker(Lcom/android/internal/view/menu/MenuBuilder$ItemInvoker;)V
+Lcom/android/internal/view/menu/IconMenuView$SavedState;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/view/menu/IconMenuView;->createMoreItemView()Lcom/android/internal/view/menu/IconMenuItemView;
+Lcom/android/internal/view/menu/IconMenuView;->getNumActualItemsShown()I
+Lcom/android/internal/view/menu/IconMenuView;->mItemBackground:Landroid/graphics/drawable/Drawable;
+Lcom/android/internal/view/menu/IconMenuView;->mMaxItems:I
+Lcom/android/internal/view/menu/IconMenuView;->mMenu:Lcom/android/internal/view/menu/MenuBuilder;
+Lcom/android/internal/view/menu/MenuDialogHelper;-><init>(Lcom/android/internal/view/menu/MenuBuilder;)V
+Lcom/android/internal/view/menu/MenuDialogHelper;->dismiss()V
+Lcom/android/internal/view/menu/MenuDialogHelper;->show(Landroid/os/IBinder;)V
+Lcom/android/internal/view/WindowManagerPolicyThread;->getLooper()Landroid/os/Looper;
+Lcom/android/internal/widget/AbsActionBarView;->dismissPopupMenus()V
+Lcom/android/internal/widget/ActionBarContextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/ActionBarOverlayLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/ActionBarOverlayLayout;->setWindowCallback(Landroid/view/Window$Callback;)V
+Lcom/android/internal/widget/EditableInputConnection;-><init>(Landroid/widget/TextView;)V
Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings;
Lcom/android/internal/widget/ILockSettings;->getBoolean(Ljava/lang/String;ZI)Z
Lcom/android/internal/widget/ILockSettings;->getLong(Ljava/lang/String;JI)J
@@ -2088,17 +4092,109 @@
Lcom/android/internal/widget/IRemoteViewsFactory;->hasStableIds()Z
Lcom/android/internal/widget/IRemoteViewsFactory;->isCreated()Z
Lcom/android/internal/widget/IRemoteViewsFactory;->onDataSetChanged()V
+Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;->setDefaultTouchRecepient(Landroid/view/View;)V
+Lcom/android/internal/widget/LockPatternChecker;->checkPassword(Lcom/android/internal/widget/LockPatternUtils;Ljava/lang/String;ILcom/android/internal/widget/LockPatternChecker$OnCheckCallback;)Landroid/os/AsyncTask;
+Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;-><init>(I)V
+Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;->getTimeoutMs()I
+Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V
+Lcom/android/internal/widget/LockPatternUtils;->checkPassword(Ljava/lang/String;I)Z
+Lcom/android/internal/widget/LockPatternUtils;->getActivePasswordQuality(I)I
+Lcom/android/internal/widget/LockPatternUtils;->getDevicePolicyManager()Landroid/app/admin/DevicePolicyManager;
+Lcom/android/internal/widget/LockPatternUtils;->getKeyguardStoredPasswordQuality(I)I
+Lcom/android/internal/widget/LockPatternUtils;->getLockSettings()Lcom/android/internal/widget/ILockSettings;
+Lcom/android/internal/widget/LockPatternUtils;->getOwnerInfo(I)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->getPowerButtonInstantlyLocks(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->getString(Ljava/lang/String;I)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->isDeviceEncryptionEnabled()Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockPasswordEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockPatternEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isLockScreenDisabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isSecure(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->isTactileFeedbackEnabled()Z
+Lcom/android/internal/widget/LockPatternUtils;->isVisiblePatternEnabled(I)Z
+Lcom/android/internal/widget/LockPatternUtils;->mContentResolver:Landroid/content/ContentResolver;
+Lcom/android/internal/widget/LockPatternUtils;->mContext:Landroid/content/Context;
+Lcom/android/internal/widget/LockPatternUtils;->patternToHash(Ljava/util/List;)[B
+Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String;
+Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V
+Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V
+Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V
+Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J
+Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V
+Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V
+Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfoEnabled(ZI)V
+Lcom/android/internal/widget/LockPatternUtils;->setString(Ljava/lang/String;Ljava/lang/String;I)V
+Lcom/android/internal/widget/LockPatternView$Cell;->column:I
+Lcom/android/internal/widget/LockPatternView$Cell;->row:I
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Animate:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Correct:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$DisplayMode;->Wrong:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcel;)V
+Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcelable;Ljava/lang/String;IZZZ)V
+Lcom/android/internal/widget/LockPatternView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/LockPatternView;->clearPattern()V
+Lcom/android/internal/widget/LockPatternView;->disableInput()V
+Lcom/android/internal/widget/LockPatternView;->enableInput()V
+Lcom/android/internal/widget/LockPatternView;->getCellStates()[[Lcom/android/internal/widget/LockPatternView$CellState;
+Lcom/android/internal/widget/LockPatternView;->mInStealthMode:Z
+Lcom/android/internal/widget/LockPatternView;->mPaint:Landroid/graphics/Paint;
+Lcom/android/internal/widget/LockPatternView;->mPathPaint:Landroid/graphics/Paint;
+Lcom/android/internal/widget/LockPatternView;->mPattern:Ljava/util/ArrayList;
+Lcom/android/internal/widget/LockPatternView;->mPatternDisplayMode:Lcom/android/internal/widget/LockPatternView$DisplayMode;
+Lcom/android/internal/widget/LockPatternView;->mPatternInProgress:Z
+Lcom/android/internal/widget/LockPatternView;->mSquareHeight:F
+Lcom/android/internal/widget/LockPatternView;->mSquareWidth:F
+Lcom/android/internal/widget/LockPatternView;->notifyPatternDetected()V
+Lcom/android/internal/widget/LockPatternView;->setDisplayMode(Lcom/android/internal/widget/LockPatternView$DisplayMode;)V
+Lcom/android/internal/widget/LockPatternView;->setInStealthMode(Z)V
+Lcom/android/internal/widget/LockPatternView;->setOnPatternListener(Lcom/android/internal/widget/LockPatternView$OnPatternListener;)V
+Lcom/android/internal/widget/LockPatternView;->setTactileFeedbackEnabled(Z)V
+Lcom/android/internal/widget/PointerLocationView$PointerState;-><init>()V
+Lcom/android/internal/widget/PointerLocationView$PointerState;->mCurDown:Z
+Lcom/android/internal/widget/PointerLocationView;->mCurDown:Z
+Lcom/android/internal/widget/PointerLocationView;->mCurNumPointers:I
+Lcom/android/internal/widget/PointerLocationView;->mMaxNumPointers:I
+Lcom/android/internal/widget/PointerLocationView;->mPointers:Ljava/util/ArrayList;
+Lcom/android/internal/widget/PointerLocationView;->mPrintCoords:Z
+Lcom/android/internal/widget/PreferenceImageView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+Lcom/android/internal/widget/RecyclerView$RecycledViewPool$ScrapData;->mScrapHeap:Ljava/util/ArrayList;
Lcom/android/internal/widget/ScrollBarUtils;->getThumbLength(IIII)I
+Lcom/android/internal/widget/SlidingTab$Slider;->tab:Landroid/widget/ImageView;
+Lcom/android/internal/widget/SlidingTab$Slider;->text:Landroid/widget/TextView;
+Lcom/android/internal/widget/SlidingTab;->mAnimationDoneListener:Landroid/view/animation/Animation$AnimationListener;
+Lcom/android/internal/widget/SlidingTab;->mLeftSlider:Lcom/android/internal/widget/SlidingTab$Slider;
+Lcom/android/internal/widget/SlidingTab;->mRightSlider:Lcom/android/internal/widget/SlidingTab$Slider;
+Lcom/android/internal/widget/SlidingTab;->onAnimationDone()V
+Lcom/android/internal/widget/SlidingTab;->resetView()V
+Lcom/android/internal/widget/SlidingTab;->setHoldAfterTrigger(ZZ)V
+Lcom/android/internal/widget/SlidingTab;->setLeftHintText(I)V
+Lcom/android/internal/widget/SlidingTab;->setLeftTabResources(IIII)V
+Lcom/android/internal/widget/SlidingTab;->setOnTriggerListener(Lcom/android/internal/widget/SlidingTab$OnTriggerListener;)V
+Lcom/android/internal/widget/SlidingTab;->setRightHintText(I)V
+Lcom/android/internal/widget/SlidingTab;->setRightTabResources(IIII)V
+Lcom/android/internal/widget/TextViewInputDisabler;-><init>(Landroid/widget/TextView;)V
+Lcom/android/internal/widget/TextViewInputDisabler;->setInputEnabled(Z)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrolled(IFI)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrollStateChanged(I)V
+Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageSelected(I)V
+Lcom/android/internal/widget/ViewPager;->getCurrentItem()I
Lcom/android/okhttp/Connection;->getSocket()Ljava/net/Socket;
Lcom/android/okhttp/ConnectionPool;->connections:Ljava/util/Deque;
Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J
Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I
Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/okhttp/HttpHandler;-><init>()V
+Lcom/android/okhttp/HttpsHandler;-><init>()V
Lcom/android/okhttp/HttpUrl$Builder;->build()Lcom/android/okhttp/HttpUrl;
Lcom/android/okhttp/HttpUrl;->encodedPath()Ljava/lang/String;
Lcom/android/okhttp/HttpUrl;->newBuilder()Lcom/android/okhttp/HttpUrl$Builder;
Lcom/android/okhttp/HttpUrl;->parse(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl;
Lcom/android/okhttp/HttpUrl;->query()Ljava/lang/String;
+Lcom/android/okhttp/internal/http/HeaderParser;->skipUntil(Ljava/lang/String;ILjava/lang/String;)I
+Lcom/android/okhttp/internal/http/HeaderParser;->skipWhitespace(Ljava/lang/String;I)I
+Lcom/android/okhttp/internal/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String;
+Lcom/android/okhttp/internal/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date;
Lcom/android/okhttp/internal/http/HttpEngine;->getConnection()Lcom/android/okhttp/Connection;
Lcom/android/okhttp/internal/http/HttpEngine;->hasResponse()Z
Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream;
@@ -2111,6 +4207,29 @@
Lcom/android/okhttp/internal/http/HttpEngine;->userResponse:Lcom/android/okhttp/Response;
Lcom/android/okhttp/internal/http/HttpEngine;->writingRequestHeaders()V
Lcom/android/okhttp/internal/http/RouteSelector;->hasNext()Z
+Lcom/android/okhttp/internal/huc/HttpsURLConnectionImpl;->delegate:Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;
+Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->client:Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->httpEngine:Lcom/android/okhttp/internal/http/HttpEngine;
+Lcom/android/okhttp/internal/Internal;-><init>()V
+Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Internal;->apply(Lcom/android/okhttp/ConnectionSpec;Ljavax/net/ssl/SSLSocket;Z)V
+Lcom/android/okhttp/internal/Internal;->callEngineGetStreamAllocation(Lcom/android/okhttp/Call;)Lcom/android/okhttp/internal/http/StreamAllocation;
+Lcom/android/okhttp/internal/Internal;->callEnqueue(Lcom/android/okhttp/Call;Lcom/android/okhttp/Callback;Z)V
+Lcom/android/okhttp/internal/Internal;->connectionBecameIdle(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)Z
+Lcom/android/okhttp/internal/Internal;->get(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/Address;Lcom/android/okhttp/internal/http/StreamAllocation;)Lcom/android/okhttp/internal/io/RealConnection;
+Lcom/android/okhttp/internal/Internal;->getHttpUrlChecked(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl;
+Lcom/android/okhttp/internal/Internal;->instance:Lcom/android/okhttp/internal/Internal;
+Lcom/android/okhttp/internal/Internal;->internalCache(Lcom/android/okhttp/OkHttpClient;)Lcom/android/okhttp/internal/InternalCache;
+Lcom/android/okhttp/internal/Internal;->put(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)V
+Lcom/android/okhttp/internal/Internal;->routeDatabase(Lcom/android/okhttp/ConnectionPool;)Lcom/android/okhttp/internal/RouteDatabase;
+Lcom/android/okhttp/internal/Internal;->setCache(Lcom/android/okhttp/OkHttpClient;Lcom/android/okhttp/internal/InternalCache;)V
+Lcom/android/okhttp/internal/Platform;->get()Lcom/android/okhttp/internal/Platform;
+Lcom/android/okhttp/internal/Platform;->logW(Ljava/lang/String;)V
+Lcom/android/okhttp/internal/Util;->closeAll(Ljava/io/Closeable;Ljava/io/Closeable;)V
+Lcom/android/okhttp/internal/Util;->closeQuietly(Ljava/io/Closeable;)V
+Lcom/android/okhttp/internal/Util;->EMPTY_BYTE_ARRAY:[B
+Lcom/android/okhttp/internal/Util;->UTF_8:Ljava/nio/charset/Charset;
Lcom/android/okhttp/OkHttpClient;-><init>()V
Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool;
Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List;
@@ -2131,11 +4250,62 @@
Lcom/android/okhttp/Response;->message:Ljava/lang/String;
Lcom/android/okhttp/Response;->networkResponse:Lcom/android/okhttp/Response;
Lcom/android/okhttp/Response;->protocol:Lcom/android/okhttp/Protocol;
+Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;-><init>()V
+Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;->add(Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>(Ljava/io/InputStream;)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/ASN1InputStream;->readObject()Lcom/android/org/bouncycastle/asn1/ASN1Primitive;
+Lcom/android/org/bouncycastle/asn1/ASN1Integer;-><init>(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/asn1/DERBitString;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/DEREncodableVector;-><init>()V
+Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(J)V
+Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/asn1/DERNull;->INSTANCE:Lcom/android/org/bouncycastle/asn1/DERNull;
+Lcom/android/org/bouncycastle/asn1/DERObjectIdentifier;-><init>(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/asn1/DEROctetString;-><init>([B)V
+Lcom/android/org/bouncycastle/asn1/DEROutputStream;-><init>(Ljava/io/OutputStream;)V
+Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>()V
+Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V
+Lcom/android/org/bouncycastle/asn1/DERSet;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V
+Lcom/android/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers;->sha256WithRSAEncryption:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;)V
+Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V
+Lcom/android/org/bouncycastle/asn1/x509/Certificate;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/Certificate;
+Lcom/android/org/bouncycastle/asn1/x509/DigestInfo;-><init>(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;[B)V
+Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;
+Lcom/android/org/bouncycastle/asn1/x509/Time;-><init>(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;-><init>()V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->generateTBSCertificate()Lcom/android/org/bouncycastle/asn1/x509/TBSCertificate;
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setEndDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setIssuer(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSerialNumber(Lcom/android/org/bouncycastle/asn1/ASN1Integer;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSignature(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setStartDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubject(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubjectPublicKeyInfo(Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1Sequence;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->CN:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getOIDs()Ljava/util/Vector;
+Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getValues()Ljava/util/Vector;
+Lcom/android/org/bouncycastle/asn1/x9/X9ObjectIdentifiers;->ecdsa_with_SHA256:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;
+Lcom/android/org/bouncycastle/jce/provider/BouncyCastleProvider;-><init>()V
+Lcom/android/org/bouncycastle/jce/provider/X509CertificateObject;-><init>(Lcom/android/org/bouncycastle/asn1/x509/Certificate;)V
+Lcom/android/org/bouncycastle/jce/X509Principal;-><init>([B)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;-><init>()V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->generate(Ljava/security/PrivateKey;)Ljava/security/cert/X509Certificate;
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Ljavax/security/auth/x500/X500Principal;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotAfter(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotBefore(Ljava/util/Date;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setPublicKey(Ljava/security/PublicKey;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSerialNumber(Ljava/math/BigInteger;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSignatureAlgorithm(Ljava/lang/String;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V
+Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Ljavax/security/auth/x500/X500Principal;)V
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocol()Ljava/lang/String;
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocols()[Ljava/lang/String;
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getChannelId()[B
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getHandshakeApplicationProtocol()Ljava/lang/String;
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getHostname()Ljava/lang/String;
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getHostnameOrIP()Ljava/lang/String;
Lcom/android/org/conscrypt/AbstractConscryptSocket;->getNpnSelectedProtocol()[B
@@ -2150,14 +4320,73 @@
Lcom/android/org/conscrypt/AbstractConscryptSocket;->setNpnProtocols([B)V
Lcom/android/org/conscrypt/AbstractConscryptSocket;->setSoWriteTimeout(I)V
Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V
+Lcom/android/org/conscrypt/ClientSessionContext;->getSession(Ljava/lang/String;I)Lcom/android/org/conscrypt/NativeSslSession;
+Lcom/android/org/conscrypt/ClientSessionContext;->setPersistentCache(Lcom/android/org/conscrypt/SSLClientSessionCache;)V
Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V
Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V
+Lcom/android/org/conscrypt/FileClientSessionCache$Impl;->getSessionData(Ljava/lang/String;I)[B
+Lcom/android/org/conscrypt/FileClientSessionCache;->usingDirectory(Ljava/io/File;)Lcom/android/org/conscrypt/SSLClientSessionCache;
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_pack_X509([J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_unpack_X509_bio(J)[J
+Lcom/android/org/conscrypt/NativeCrypto;->ASN1_TIME_to_Calendar(JLjava/util/Calendar;)V
+Lcom/android/org/conscrypt/NativeCrypto;->BIO_free_all(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_InputStream(Lcom/android/org/conscrypt/OpenSSLBIOInputStream;Z)J
+Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_OutputStream(Ljava/io/OutputStream;)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_PKCS7_bio(JI)[J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_SSL_SESSION([B)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509([B)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_bio(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_CRL_bio(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_clear_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_new_by_curve_name(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EC_POINT_clear_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_CTX_new()J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_iv_length(J)I
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_cipherbyname(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_digestbyname(Ljava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_create()J
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_destroy(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_size(J)I
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_new_RSA([B[B[B[B[B[B[B[B)J
+Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_ext_oids(JI)[Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_revocationDate(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_PKCS7([J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_SSL_SESSION(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->i2d_X509_REVOKED(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_PKCS7(JI)[J
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509_CRL(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->RAND_bytes([B)V
+Lcom/android/org/conscrypt/NativeCrypto;->RSA_generate_key_ex(I[B)J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_CTX_new()J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_cipher(J)Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_free(J)V
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_time(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_version(J)Ljava/lang/String;
+Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_session_id(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_dup(J)J
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext(JLjava/lang/String;)J
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext_oid(JLjava/lang/String;)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_serialNumber(J)[B
+Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_print(JJ)V
+Lcom/android/org/conscrypt/NativeCrypto;->X509_supported_extension(J)I
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;-><init>(Ljava/io/InputStream;Z)V
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->getBioContext()J
+Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->release()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl$TLSv12;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLContextImpl;->engineGetClientSessionContext()Lcom/android/org/conscrypt/ClientSessionContext;
+Lcom/android/org/conscrypt/OpenSSLContextImpl;->getPreferred()Lcom/android/org/conscrypt/OpenSSLContextImpl;
Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V
Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
+Lcom/android/org/conscrypt/OpenSSLKeyHolder;->getOpenSSLKey()Lcom/android/org/conscrypt/OpenSSLKey;
Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;->sslParameters:Lcom/android/org/conscrypt/SSLParametersImpl;
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2175,32 +4404,83 @@
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
+Lcom/android/org/conscrypt/SSLParametersImpl;->getDefault()Lcom/android/org/conscrypt/SSLParametersImpl;
+Lcom/android/org/conscrypt/SSLParametersImpl;->getDefaultX509TrustManager()Ljavax/net/ssl/X509TrustManager;
+Lcom/android/org/conscrypt/SSLParametersImpl;->getX509TrustManager()Ljavax/net/ssl/X509TrustManager;
+Lcom/android/org/conscrypt/SSLParametersImpl;->setEnabledProtocols([Ljava/lang/String;)V
+Lcom/android/org/conscrypt/SSLParametersImpl;->x509TrustManager:Ljavax/net/ssl/X509TrustManager;
Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>()V
Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List;
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
+Lcom/android/org/conscrypt/X509PublicKey;-><init>(Ljava/lang/String;[B)V
+Lcom/android/server/net/BaseNetworkObserver;-><init>()V
+Lcom/android/server/net/NetlinkTracker;-><init>(Ljava/lang/String;Lcom/android/server/net/NetlinkTracker$Callback;)V
+Lcom/android/server/net/NetlinkTracker;->clearLinkProperties()V
+Lcom/android/server/net/NetlinkTracker;->getLinkProperties()Landroid/net/LinkProperties;
+Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V
+Lcom/android/server/ResettableTimeout;->mLock:Landroid/os/ConditionVariable;
+Lcom/android/server/ResettableTimeout;->mOffAt:J
+Lcom/google/android/collect/Lists;->newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList;
+Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet;
+Lcom/google/android/collect/Sets;->newHashSet()Ljava/util/HashSet;
+Lcom/google/android/collect/Sets;->newHashSet([Ljava/lang/Object;)Ljava/util/HashSet;
+Lcom/google/android/collect/Sets;->newSortedSet()Ljava/util/SortedSet;
+Lcom/google/android/gles_jni/EGLImpl;-><init>()V
+Lcom/google/android/gles_jni/GLImpl;-><init>()V
Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z
+Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z
Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
+Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V
Lcom/google/android/mms/MmsException;-><init>()V
Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
+Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V
+Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V
+Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B
+Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I
Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
+Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J
Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I
+Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V
Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I
Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
+Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B
+Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V
+Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V
+Lcom/google/android/mms/pdu/GenericPdu;-><init>()V
+Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
+Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders;
+Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders;
Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
@@ -2210,15 +4490,31 @@
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;-><init>()V
+Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I
Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
+Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I
Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
+Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V
Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V
+Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V
+Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V
Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
+Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V
+Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V
Lcom/google/android/mms/pdu/PduBody;-><init>()V
Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
@@ -2227,62 +4523,1114 @@
Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I
Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
+Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart;
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker;
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V
+Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V
+Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I
Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I
+Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V
+Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V
+Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V
+Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V
+Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V
+Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V
+Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V
+Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V
+Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V
Lcom/google/android/mms/pdu/PduComposer;->make()[B
+Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream;
+Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders;
+Lcom/google/android/mms/pdu/PduComposer;->mPosition:I
+Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver;
+Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack;
+Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduHeaders;-><init>()V
+Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
+Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J
+Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I
+Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B
+Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
+Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V
+Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V
+Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z
+Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V
+Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I
+Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V
Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B
+Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z
+Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I
+Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B
Lcom/google/android/mms/pdu/PduPart;-><init>()V
Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
Lcom/google/android/mms/pdu/PduPart;->getCharset()I
+Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentId()[B
Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
+Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B
Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
Lcom/google/android/mms/pdu/PduPart;->getData()[B
+Lcom/google/android/mms/pdu/PduPart;->getDataLength()I
Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
Lcom/google/android/mms/pdu/PduPart;->getName()[B
Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
+Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V
Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
+Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V
Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
Lcom/google/android/mms/pdu/PduPart;->setData([B)V
Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
+Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V
+Lcom/google/android/mms/pdu/PduPart;->setName([B)V
+Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I
+Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B
Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
+Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer;
+Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String;
Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V
+Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver;
+Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context;
+Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap;
Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager;
+Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap;
+Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache;
Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
+Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
+Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
+Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B
+Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
+Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I
Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
+Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B
Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
+Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V
+Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I
Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B
Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I
+Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I
+Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue;
Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
+Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V
+Lcom/google/android/mms/pdu/SendConf;-><init>()V
+Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
Lcom/google/android/mms/pdu/SendReq;-><init>()V
+Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
+Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
+Lcom/google/android/mms/pdu/SendReq;->getContentType()[B
+Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I
+Lcom/google/android/mms/pdu/SendReq;->getExpiry()J
+Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B
+Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J
+Lcom/google/android/mms/pdu/SendReq;->getReadReport()I
Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
+Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V
Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
+Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V
+Lcom/google/android/mms/util/AbstractCache;-><init>()V
Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
+Lcom/google/android/mms/util/AbstractCache;->purgeAll()V
+Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z
+Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z
+Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String;
+Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I
+Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B
+Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession;
+Lcom/google/android/mms/util/PduCache;-><init>()V
Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
Lcom/google/android/mms/util/PduCache;->purgeAll()V
+Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V
+Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I
Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
+Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J
+Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V
+Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
+Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
+Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z
+Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->ACRONYM:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->FLICKR:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->FORMAT:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->GOOGLE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->HTML:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->LINK:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->MUSIC:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->PHOTO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->SMILEY:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/google/android/util/AbstractMessageParser$Token$Type;->YOUTUBE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type;
+Lcom/sun/nio/file/ExtendedWatchEventModifier;->FILE_TREE:Lcom/sun/nio/file/ExtendedWatchEventModifier;
+Lgov/nist/core/Debug;->printStackTrace(Ljava/lang/Exception;)V
+Lgov/nist/core/GenericObject;-><init>()V
+Lgov/nist/core/GenericObject;->dbgPrint()V
+Lgov/nist/core/GenericObject;->debugDump(I)Ljava/lang/String;
+Lgov/nist/core/GenericObject;->encode()Ljava/lang/String;
+Lgov/nist/core/GenericObject;->getMatcher()Lgov/nist/core/Match;
+Lgov/nist/core/GenericObject;->indentation:I
+Lgov/nist/core/GenericObject;->isMySubclass(Ljava/lang/Class;)Z
+Lgov/nist/core/GenericObject;->match(Ljava/lang/Object;)Z
+Lgov/nist/core/GenericObject;->matchExpression:Lgov/nist/core/Match;
+Lgov/nist/core/GenericObject;->merge(Ljava/lang/Object;)V
+Lgov/nist/core/GenericObject;->sprint(Ljava/lang/String;)V
+Lgov/nist/core/GenericObject;->stringRepresentation:Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;-><init>()V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/Class;)V
+Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;)V
+Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;Z)V
+Lgov/nist/core/GenericObjectList;->debugDump(I)Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;->first()Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->getIndentation()Ljava/lang/String;
+Lgov/nist/core/GenericObjectList;->indentation:I
+Lgov/nist/core/GenericObjectList;->isMySubclass(Ljava/lang/Class;)Z
+Lgov/nist/core/GenericObjectList;->match(Ljava/lang/Object;)Z
+Lgov/nist/core/GenericObjectList;->myClass:Ljava/lang/Class;
+Lgov/nist/core/GenericObjectList;->next()Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->next(Ljava/util/ListIterator;)Lgov/nist/core/GenericObject;
+Lgov/nist/core/GenericObjectList;->setMyClass(Ljava/lang/Class;)V
+Lgov/nist/core/GenericObjectList;->stringRep:Ljava/lang/String;
+Lgov/nist/core/Host;-><init>()V
+Lgov/nist/core/Host;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/Host;->encode()Ljava/lang/String;
+Lgov/nist/core/Host;->getAddress()Ljava/lang/String;
+Lgov/nist/core/Host;->getHostname()Ljava/lang/String;
+Lgov/nist/core/Host;->isIPv6Reference(Ljava/lang/String;)Z
+Lgov/nist/core/Host;->setAddress(Ljava/lang/String;)V
+Lgov/nist/core/Host;->setHostname(Ljava/lang/String;)V
+Lgov/nist/core/HostNameParser;-><init>(Lgov/nist/core/LexerCore;)V
+Lgov/nist/core/HostNameParser;-><init>(Ljava/lang/String;)V
+Lgov/nist/core/HostNameParser;->host()Lgov/nist/core/Host;
+Lgov/nist/core/HostNameParser;->hostPort(Z)Lgov/nist/core/HostPort;
+Lgov/nist/core/HostPort;-><init>()V
+Lgov/nist/core/HostPort;->encode()Ljava/lang/String;
+Lgov/nist/core/HostPort;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/HostPort;->getHost()Lgov/nist/core/Host;
+Lgov/nist/core/HostPort;->getInetAddress()Ljava/net/InetAddress;
+Lgov/nist/core/HostPort;->getPort()I
+Lgov/nist/core/HostPort;->hasPort()Z
+Lgov/nist/core/HostPort;->removePort()V
+Lgov/nist/core/HostPort;->setHost(Lgov/nist/core/Host;)V
+Lgov/nist/core/HostPort;->setPort(I)V
+Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/Exception;)V
+Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;->byteStringNoSemicolon()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->byteStringNoSlash()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->charAsString(I)Ljava/lang/String;
+Lgov/nist/core/LexerCore;->comment()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->createParseException()Ljava/text/ParseException;
+Lgov/nist/core/LexerCore;->currentLexer:Ljava/util/Hashtable;
+Lgov/nist/core/LexerCore;->getBuffer()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getNextId()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getNextToken()Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->getPtr()I
+Lgov/nist/core/LexerCore;->getRest()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->getString(C)Ljava/lang/String;
+Lgov/nist/core/LexerCore;->isTokenChar(C)Z
+Lgov/nist/core/LexerCore;->lexerTables:Ljava/util/Hashtable;
+Lgov/nist/core/LexerCore;->markInputPosition()I
+Lgov/nist/core/LexerCore;->match(I)Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->number()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->peekNextToken()Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->peekNextToken(I)[Lgov/nist/core/Token;
+Lgov/nist/core/LexerCore;->quotedString()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->rewindInputPosition(I)V
+Lgov/nist/core/LexerCore;->selectLexer(Ljava/lang/String;)V
+Lgov/nist/core/LexerCore;->SPorHT()V
+Lgov/nist/core/LexerCore;->startsId()Z
+Lgov/nist/core/LexerCore;->ttoken()Ljava/lang/String;
+Lgov/nist/core/LexerCore;->ttokenSafe()Ljava/lang/String;
+Lgov/nist/core/Match;->match(Ljava/lang/String;)Z
+Lgov/nist/core/NameValue;-><init>()V
+Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;)V
+Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;Z)V
+Lgov/nist/core/NameValue;->encode()Ljava/lang/String;
+Lgov/nist/core/NameValue;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/NameValue;->getName()Ljava/lang/String;
+Lgov/nist/core/NameValue;->getValueAsObject()Ljava/lang/Object;
+Lgov/nist/core/NameValue;->setName(Ljava/lang/String;)V
+Lgov/nist/core/NameValue;->setQuotedValue()V
+Lgov/nist/core/NameValue;->setSeparator(Ljava/lang/String;)V
+Lgov/nist/core/NameValue;->setValueAsObject(Ljava/lang/Object;)V
+Lgov/nist/core/NameValueList;-><init>()V
+Lgov/nist/core/NameValueList;-><init>(Z)V
+Lgov/nist/core/NameValueList;->delete(Ljava/lang/String;)Z
+Lgov/nist/core/NameValueList;->encode()Ljava/lang/String;
+Lgov/nist/core/NameValueList;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer;
+Lgov/nist/core/NameValueList;->getNames()Ljava/util/Iterator;
+Lgov/nist/core/NameValueList;->getNameValue(Ljava/lang/String;)Lgov/nist/core/NameValue;
+Lgov/nist/core/NameValueList;->getParameter(Ljava/lang/String;)Ljava/lang/String;
+Lgov/nist/core/NameValueList;->getValue(Ljava/lang/String;)Ljava/lang/Object;
+Lgov/nist/core/NameValueList;->hasNameValue(Ljava/lang/String;)Z
+Lgov/nist/core/NameValueList;->iterator()Ljava/util/Iterator;
+Lgov/nist/core/NameValueList;->set(Lgov/nist/core/NameValue;)V
+Lgov/nist/core/NameValueList;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lgov/nist/core/NameValueList;->setSeparator(Ljava/lang/String;)V
+Lgov/nist/core/net/DefaultNetworkLayer;->SINGLETON:Lgov/nist/core/net/DefaultNetworkLayer;
+Lgov/nist/core/net/NetworkLayer;->createDatagramSocket()Ljava/net/DatagramSocket;
+Lgov/nist/core/net/NetworkLayer;->createDatagramSocket(ILjava/net/InetAddress;)Ljava/net/DatagramSocket;
+Lgov/nist/core/net/NetworkLayer;->createServerSocket(IILjava/net/InetAddress;)Ljava/net/ServerSocket;
+Lgov/nist/core/net/NetworkLayer;->createSocket(Ljava/net/InetAddress;I)Ljava/net/Socket;
+Lgov/nist/core/net/NetworkLayer;->createSSLServerSocket(IILjava/net/InetAddress;)Ljavax/net/ssl/SSLServerSocket;
+Lgov/nist/core/net/NetworkLayer;->createSSLSocket(Ljava/net/InetAddress;I)Ljavax/net/ssl/SSLSocket;
+Lgov/nist/core/ParserCore;-><init>()V
+Lgov/nist/core/ParserCore;->lexer:Lgov/nist/core/LexerCore;
+Lgov/nist/core/StringTokenizer;->ptr:I
+Lgov/nist/core/ThreadAuditor$ThreadHandle;->getPingIntervalInMillisecs()J
+Lgov/nist/core/ThreadAuditor$ThreadHandle;->ping()V
+Lgov/nist/core/ThreadAuditor;-><init>()V
+Lgov/nist/core/ThreadAuditor;->addCurrentThread()Lgov/nist/core/ThreadAuditor$ThreadHandle;
+Lgov/nist/core/ThreadAuditor;->getPingIntervalInMillisecs()J
+Lgov/nist/core/ThreadAuditor;->isEnabled()Z
+Lgov/nist/core/ThreadAuditor;->setPingIntervalInMillisecs(J)V
+Lgov/nist/core/Token;-><init>()V
+Lgov/nist/core/Token;->getTokenType()I
+Lgov/nist/core/Token;->getTokenValue()Ljava/lang/String;
+Lgov/nist/javax/sip/address/GenericURI;-><init>()V
+Lgov/nist/javax/sip/address/GenericURI;->encode()Ljava/lang/String;
+Lgov/nist/javax/sip/address/GenericURI;->getScheme()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getHost()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getParameter(Ljava/lang/String;)Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->getPort()I
+Lgov/nist/javax/sip/address/SipUri;->getUser()Ljava/lang/String;
+Lgov/nist/javax/sip/address/SipUri;->removeParameter(Ljava/lang/String;)V
+Lgov/nist/javax/sip/address/SipUri;->setParameter(Ljava/lang/String;Ljava/lang/String;)V
+Lgov/nist/javax/sip/address/SipUri;->setUserParam(Ljava/lang/String;)V
+Lgov/nist/javax/sip/parser/URLParser;-><init>(Ljava/lang/String;)V
+Lgov/nist/javax/sip/parser/URLParser;->sipURL(Z)Lgov/nist/javax/sip/address/SipUri;
+Ljava/lang/DexCache;->dexFile:J
+Ljava/lang/invoke/SerializedLambda;-><init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
+Ljava/lang/invoke/SerializedLambda;->getCapturedArg(I)Ljava/lang/Object;
+Ljava/lang/invoke/SerializedLambda;->getCapturedArgCount()I
+Ljava/lang/invoke/SerializedLambda;->getCapturingClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodName()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodSignature()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplClass()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplMethodKind()I
+Ljava/lang/invoke/SerializedLambda;->getImplMethodName()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getImplMethodSignature()Ljava/lang/String;
+Ljava/lang/invoke/SerializedLambda;->getInstantiatedMethodType()Ljava/lang/String;
+Ljava/lang/UNIXProcess;->pid:I
+Ljava/net/AddressCache$AddressCacheEntry;-><init>(Ljava/lang/Object;)V
+Ljava/net/AddressCache$AddressCacheEntry;->expiryNanos:J
+Ljava/net/AddressCache$AddressCacheEntry;->value:Ljava/lang/Object;
+Ljava/net/AddressCache$AddressCacheKey;->mHostname:Ljava/lang/String;
+Ljava/net/AddressCache;->cache:Llibcore/util/BasicLruCache;
+Ljava/net/Inet6AddressImpl;->addressCache:Ljava/net/AddressCache;
+Ljava/net/PlainSocketImpl;-><init>()V
+Ljava/nio/DirectByteBuffer;->cleaner()Lsun/misc/Cleaner;
+Ljava/nio/file/FileTreeWalker;->followLinks:Z
+Ljava/nio/file/FileTreeWalker;->linkOptions:[Ljava/nio/file/LinkOption;
+Ljava/nio/file/FileTreeWalker;->maxDepth:I
+Ljava/util/zip/ZipFile$ZipEntryIterator;->nextElement()Ljava/util/zip/ZipEntry;
+Ljunit/framework/TestCase;->fName:Ljava/lang/String;
+Ljunit/framework/TestSuite;->isPublicTestMethod(Ljava/lang/reflect/Method;)Z
+Ljunit/framework/TestSuite;->isTestMethod(Ljava/lang/reflect/Method;)Z
+Llibcore/icu/DateIntervalFormat;->formatDateRange(JJILjava/lang/String;)Ljava/lang/String;
+Llibcore/icu/ICU;->CACHED_PATTERNS:Llibcore/util/BasicLruCache;
+Llibcore/icu/ICU;->getBestDateTimePattern(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String;
+Llibcore/icu/ICU;->getBestDateTimePatternNative(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Llibcore/icu/ICU;->getDateFormatOrder(Ljava/lang/String;)[C
+Llibcore/icu/LocaleData;->firstDayOfWeek:Ljava/lang/Integer;
+Llibcore/icu/LocaleData;->get(Ljava/util/Locale;)Llibcore/icu/LocaleData;
+Llibcore/icu/LocaleData;->longStandAloneWeekdayNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->mapInvalidAndNullLocales(Ljava/util/Locale;)Ljava/util/Locale;
+Llibcore/icu/LocaleData;->minimalDaysInFirstWeek:Ljava/lang/Integer;
+Llibcore/icu/LocaleData;->shortMonthNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->shortStandAloneMonthNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->shortStandAloneWeekdayNames:[Ljava/lang/String;
+Llibcore/icu/LocaleData;->timeFormat_Hm:Ljava/lang/String;
+Llibcore/icu/LocaleData;->timeFormat_hm:Ljava/lang/String;
+Llibcore/icu/LocaleData;->today:Ljava/lang/String;
+Llibcore/icu/LocaleData;->tomorrow:Ljava/lang/String;
+Llibcore/icu/LocaleData;->zeroDigit:C
+Llibcore/icu/TimeZoneNames;->forLocale(Ljava/util/Locale;)[Ljava/lang/String;
+Llibcore/io/AsynchronousCloseMonitor;->signalBlockedThreads(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;-><init>(Llibcore/io/Os;)V
+Llibcore/io/BlockGuardOs;->chmod(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->chown(Ljava/lang/String;II)V
+Llibcore/io/BlockGuardOs;->close(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;->fchmod(Ljava/io/FileDescriptor;I)V
+Llibcore/io/BlockGuardOs;->fchown(Ljava/io/FileDescriptor;II)V
+Llibcore/io/BlockGuardOs;->fdatasync(Ljava/io/FileDescriptor;)V
+Llibcore/io/BlockGuardOs;->fstat(Ljava/io/FileDescriptor;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->fstatvfs(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs;
+Llibcore/io/BlockGuardOs;->lchown(Ljava/lang/String;II)V
+Llibcore/io/BlockGuardOs;->link(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->lseek(Ljava/io/FileDescriptor;JI)J
+Llibcore/io/BlockGuardOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->mkdir(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->mkfifo(Ljava/lang/String;I)V
+Llibcore/io/BlockGuardOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor;
+Llibcore/io/BlockGuardOs;->posix_fallocate(Ljava/io/FileDescriptor;JJ)V
+Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I
+Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;[BIIJ)I
+Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I
+Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;[BIIJ)I
+Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I
+Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;[BII)I
+Llibcore/io/BlockGuardOs;->readlink(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/BlockGuardOs;->readv(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I
+Llibcore/io/BlockGuardOs;->realpath(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/BlockGuardOs;->remove(Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->rename(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/BlockGuardOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs;
+Llibcore/io/BlockGuardOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I
+Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;[BII)I
+Llibcore/io/BlockGuardOs;->writev(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I
+Llibcore/io/BufferIterator;->readByte()B
+Llibcore/io/BufferIterator;->readByteArray([BII)V
+Llibcore/io/BufferIterator;->readInt()I
+Llibcore/io/BufferIterator;->readIntArray([III)V
+Llibcore/io/BufferIterator;->seek(I)V
+Llibcore/io/BufferIterator;->skip(I)V
+Llibcore/io/DropBox;->addText(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;-><init>(Llibcore/io/Os;)V
+Llibcore/io/ForwardingOs;->access(Ljava/lang/String;I)Z
+Llibcore/io/ForwardingOs;->chmod(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->chown(Ljava/lang/String;II)V
+Llibcore/io/ForwardingOs;->getenv(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/ForwardingOs;->lchown(Ljava/lang/String;II)V
+Llibcore/io/ForwardingOs;->link(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/ForwardingOs;->mkdir(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->mkfifo(Ljava/lang/String;I)V
+Llibcore/io/ForwardingOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor;
+Llibcore/io/ForwardingOs;->os:Llibcore/io/Os;
+Llibcore/io/ForwardingOs;->readlink(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/ForwardingOs;->remove(Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->removexattr(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->rename(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V
+Llibcore/io/ForwardingOs;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V
+Llibcore/io/ForwardingOs;->setxattr(Ljava/lang/String;Ljava/lang/String;[BI)V
+Llibcore/io/ForwardingOs;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/ForwardingOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs;
+Llibcore/io/ForwardingOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V
+Llibcore/io/ForwardingOs;->sysconf(I)J
+Llibcore/io/ForwardingOs;->unlink(Ljava/lang/String;)V
+Llibcore/io/IoBridge;->isConnected(Ljava/io/FileDescriptor;Ljava/net/InetAddress;III)Z
+Llibcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V
+Llibcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V
+Llibcore/io/IoUtils;->closeQuietly(Ljava/net/Socket;)V
+Llibcore/io/IoUtils;->readFileAsByteArray(Ljava/lang/String;)[B
+Llibcore/io/IoUtils;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V
+Llibcore/io/MemoryMappedFile;->bigEndianIterator()Llibcore/io/BufferIterator;
+Llibcore/io/MemoryMappedFile;->mmapRO(Ljava/lang/String;)Llibcore/io/MemoryMappedFile;
+Llibcore/io/Os;->chmod(Ljava/lang/String;I)V
+Llibcore/io/Os;->close(Ljava/io/FileDescriptor;)V
+Llibcore/io/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V
+Llibcore/io/Os;->gai_strerror(I)Ljava/lang/String;
+Llibcore/io/Os;->remove(Ljava/lang/String;)V
+Llibcore/io/Os;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V
+Llibcore/io/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V
+Llibcore/io/Os;->stat(Ljava/lang/String;)Landroid/system/StructStat;
+Llibcore/io/Os;->strerror(I)Ljava/lang/String;
+Llibcore/io/Os;->sysconf(I)J
+Llibcore/io/Streams;->readAsciiLine(Ljava/io/InputStream;)Ljava/lang/String;
+Llibcore/io/Streams;->readFully(Ljava/io/InputStream;)[B
+Llibcore/io/Streams;->readFully(Ljava/io/InputStream;[B)V
+Llibcore/io/Streams;->readSingleByte(Ljava/io/InputStream;)I
+Llibcore/io/Streams;->skipAll(Ljava/io/InputStream;)V
+Llibcore/io/Streams;->writeSingleByte(Ljava/io/OutputStream;I)V
+Llibcore/net/event/NetworkEventDispatcher;->addListener(Llibcore/net/event/NetworkEventListener;)V
+Llibcore/net/event/NetworkEventDispatcher;->getInstance()Llibcore/net/event/NetworkEventDispatcher;
+Llibcore/net/event/NetworkEventListener;-><init>()V
+Llibcore/net/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String;
+Llibcore/net/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date;
+Llibcore/net/MimeUtils;->guessExtensionFromMimeType(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/net/MimeUtils;->guessMimeTypeFromExtension(Ljava/lang/String;)Ljava/lang/String;
+Llibcore/net/NetworkSecurityPolicy;->isCleartextTrafficPermitted()Z
+Llibcore/util/BasicLruCache;-><init>(I)V
+Llibcore/util/BasicLruCache;->evictAll()V
+Llibcore/util/BasicLruCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Llibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+Llibcore/util/EmptyArray;->BYTE:[B
+Llibcore/util/EmptyArray;->INT:[I
+Llibcore/util/EmptyArray;->OBJECT:[Ljava/lang/Object;
+Llibcore/util/ZoneInfoDB$TzData;-><init>()V
+Lorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V
+Lorg/apache/harmony/dalvik/ddmc/ChunkHandler;->CHUNK_ORDER:Ljava/nio/ByteOrder;
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;->broadcast(I)V
+Lorg/apache/harmony/dalvik/ddmc/DdmServer;->sendChunk(Lorg/apache/harmony/dalvik/ddmc/Chunk;)V
+Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;->getThreadStats()[B
+Lorg/apache/harmony/xml/dom/ElementImpl;->localName:Ljava/lang/String;
+Lorg/apache/harmony/xml/ExpatAttributes;-><init>()V
+Lorg/apache/harmony/xml/ExpatParser$EntityParser;->depth:I
+Lorg/apache/harmony/xml/ExpatParser;-><init>(Ljava/lang/String;Lorg/apache/harmony/xml/ExpatReader;ZLjava/lang/String;Ljava/lang/String;)V
+Lorg/apache/harmony/xml/ExpatParser;->append([BII)V
+Lorg/apache/harmony/xml/ExpatParser;->append([CII)V
+Lorg/apache/harmony/xml/ExpatParser;->attributes:Lorg/apache/harmony/xml/ExpatAttributes;
+Lorg/apache/harmony/xml/ExpatParser;->cloneAttributes()Lorg/xml/sax/Attributes;
+Lorg/apache/harmony/xml/ExpatParser;->finish()V
+Lorg/apache/harmony/xml/ExpatParser;->xmlReader:Lorg/apache/harmony/xml/ExpatReader;
+Lorg/apache/harmony/xml/ExpatReader;-><init>()V
+Lorg/apache/harmony/xml/ExpatReader;->contentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xalan/extensions/ExpressionContext;->getContextNode()Lorg/w3c/dom/Node;
+Lorg/apache/xalan/extensions/ExpressionContext;->getErrorListener()Ljavax/xml/transform/ErrorListener;
+Lorg/apache/xalan/extensions/ExpressionContext;->getVariableOrParam(Lorg/apache/xml/utils/QName;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xalan/extensions/ExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/extensions/ExtensionHandler;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xalan/extensions/ExtensionHandler;->callFunction(Ljava/lang/String;Ljava/util/Vector;Ljava/lang/Object;Lorg/apache/xalan/extensions/ExpressionContext;)Ljava/lang/Object;
+Lorg/apache/xalan/extensions/ExtensionHandler;->getClassForName(Ljava/lang/String;)Ljava/lang/Class;
+Lorg/apache/xalan/extensions/ObjectFactory$ConfigurationError;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V
+Lorg/apache/xalan/extensions/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xalan/extensions/ObjectFactory;->findProviderClass(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Class;
+Lorg/apache/xalan/processor/TransformerFactoryImpl;-><init>()V
+Lorg/apache/xalan/res/XSLMessages;->createMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xalan/res/XSLTErrorResources;-><init>()V
+Lorg/apache/xalan/serialize/SerializerUtils;->outputResultTreeFragment(Lorg/apache/xml/serializer/SerializationHandler;Lorg/apache/xpath/objects/XObject;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xalan/templates/AVT;->evaluate(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Ljava/lang/String;
+Lorg/apache/xalan/templates/ElemElement;->execute(Lorg/apache/xalan/transformer/TransformerImpl;)V
+Lorg/apache/xalan/templates/ElemExsltFunction;->execute(Lorg/apache/xalan/transformer/TransformerImpl;[Lorg/apache/xpath/objects/XObject;)V
+Lorg/apache/xalan/templates/ElemExtensionCall;->getAttribute(Ljava/lang/String;Lorg/w3c/dom/Node;Lorg/apache/xalan/transformer/TransformerImpl;)Ljava/lang/String;
+Lorg/apache/xalan/templates/ElemLiteralResult;->getLiteralResultAttribute(Ljava/lang/String;)Lorg/apache/xalan/templates/AVT;
+Lorg/apache/xalan/templates/ElemTemplate;->getMatch()Lorg/apache/xpath/XPath;
+Lorg/apache/xalan/templates/ElemTemplate;->getName()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getFirstChildElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getNextSiblingElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getParentElem()Lorg/apache/xalan/templates/ElemTemplateElement;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getStylesheetRoot()Lorg/apache/xalan/templates/StylesheetRoot;
+Lorg/apache/xalan/templates/ElemTemplateElement;->getXSLToken()I
+Lorg/apache/xalan/templates/ElemTextLiteral;->getChars()[C
+Lorg/apache/xalan/templates/KeyDeclaration;->getName()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/templates/KeyDeclaration;->getUse()Lorg/apache/xpath/XPath;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRootRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultTextRule()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/templates/StylesheetRoot;->getTemplateComposed(Lorg/apache/xml/utils/QName;)Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/transformer/ClonerToResultTree;->cloneToResultTree(IILorg/apache/xml/dtm/DTM;Lorg/apache/xml/serializer/SerializationHandler;Z)V
+Lorg/apache/xalan/transformer/DecimalToRoman;-><init>(JLjava/lang/String;JLjava/lang/String;)V
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_postLetter:Ljava/lang/String;
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_postValue:J
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_preLetter:Ljava/lang/String;
+Lorg/apache/xalan/transformer/DecimalToRoman;->m_preValue:J
+Lorg/apache/xalan/transformer/MsgMgr;->error(Ljavax/xml/transform/SourceLocator;Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;Ljava/lang/String;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->createSerializationHandler(Ljavax/xml/transform/Result;Lorg/apache/xalan/templates/OutputProperties;)Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/QName;Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Z)V
+Lorg/apache/xalan/transformer/TransformerImpl;->getCountersTable()Lorg/apache/xalan/transformer/CountersTable;
+Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElements()Lorg/apache/xml/utils/ObjectStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElementsCount()I
+Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedNode()I
+Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedTemplate()Lorg/apache/xalan/templates/ElemTemplate;
+Lorg/apache/xalan/transformer/TransformerImpl;->getMode()Lorg/apache/xml/utils/QName;
+Lorg/apache/xalan/transformer/TransformerImpl;->getMsgMgr()Lorg/apache/xalan/transformer/MsgMgr;
+Lorg/apache/xalan/transformer/TransformerImpl;->getOutputFormat()Lorg/apache/xalan/templates/OutputProperties;
+Lorg/apache/xalan/transformer/TransformerImpl;->getResultTreeHandler()Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->getSerializationHandler()Lorg/apache/xml/serializer/SerializationHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_attrSetStack:Ljava/util/Stack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchedNodes:Lorg/apache/xml/utils/NodeVector;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchTemplates:Ljava/util/Stack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateElements:Lorg/apache/xml/utils/ObjectStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateRuleIsNull:Lorg/apache/xml/utils/BoolStack;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_inputContentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_outputTarget:Ljavax/xml/transform/Result;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_stringWriterObjectPool:Lorg/apache/xml/utils/ObjectPool;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_urlOfSource:Ljava/lang/String;
+Lorg/apache/xalan/transformer/TransformerImpl;->m_xcontext:Lorg/apache/xpath/XPathContext;
+Lorg/apache/xalan/transformer/TransformerImpl;->popCurrentFuncResult()Ljava/lang/Object;
+Lorg/apache/xalan/transformer/TransformerImpl;->pushCurrentFuncResult(Ljava/lang/Object;)V
+Lorg/apache/xalan/transformer/TransformerImpl;->pushElemTemplateElement(Lorg/apache/xalan/templates/ElemTemplateElement;)V
+Lorg/apache/xalan/Version;->getVersion()Ljava/lang/String;
+Lorg/apache/xalan/xslt/EnvironmentCheck;-><init>()V
+Lorg/apache/xalan/xslt/EnvironmentCheck;->appendEnvironmentReport(Lorg/w3c/dom/Node;Lorg/w3c/dom/Document;Ljava/util/Hashtable;)V
+Lorg/apache/xalan/xslt/EnvironmentCheck;->getEnvironmentHash()Ljava/util/Hashtable;
+Lorg/apache/xalan/xslt/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xalan/xslt/ObjectFactory;->newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Object;
+Lorg/apache/xml/dtm/Axis;->getNames(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/Axis;->isReverse(I)Z
+Lorg/apache/xml/dtm/DTM;->getDocument()I
+Lorg/apache/xml/dtm/DTM;->getDocumentRoot(I)I
+Lorg/apache/xml/dtm/DTM;->getFirstChild(I)I
+Lorg/apache/xml/dtm/DTM;->getNextSibling(I)I
+Lorg/apache/xml/dtm/DTM;->getNode(I)Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/DTM;->getNodeName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/DTM;->getNodeType(I)S
+Lorg/apache/xml/dtm/DTM;->getParent(I)I
+Lorg/apache/xml/dtm/DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xml/dtm/DTM;->getStringValue(I)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/dtm/DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xml/dtm/DTMAxisIterator;->cloneIterator()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMAxisIterator;->getLast()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->getNodeByPosition(I)I
+Lorg/apache/xml/dtm/DTMAxisIterator;->getPosition()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->gotoMark()V
+Lorg/apache/xml/dtm/DTMAxisIterator;->isReverse()Z
+Lorg/apache/xml/dtm/DTMAxisIterator;->next()I
+Lorg/apache/xml/dtm/DTMAxisIterator;->reset()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMAxisIterator;->setMark()V
+Lorg/apache/xml/dtm/DTMAxisIterator;->setRestartable(Z)V
+Lorg/apache/xml/dtm/DTMAxisIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/DTMException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/DTMFilter;->acceptNode(II)S
+Lorg/apache/xml/dtm/DTMIterator;->cloneWithReset()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xml/dtm/DTMIterator;->getCurrentPos()I
+Lorg/apache/xml/dtm/DTMIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/DTMIterator;->nextNode()I
+Lorg/apache/xml/dtm/DTMIterator;->runTo(I)V
+Lorg/apache/xml/dtm/DTMIterator;->setCurrentPos(I)V
+Lorg/apache/xml/dtm/DTMIterator;->setRoot(ILjava/lang/Object;)V
+Lorg/apache/xml/dtm/DTMIterator;->setShouldCacheNodes(Z)V
+Lorg/apache/xml/dtm/DTMManager;->getDTM(Ljavax/xml/transform/Source;ZLorg/apache/xml/dtm/DTMWSFilter;ZZ)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/DTMManager;->getXMLStringFactory()Lorg/apache/xml/utils/XMLStringFactory;
+Lorg/apache/xml/dtm/DTMManager;->release(Lorg/apache/xml/dtm/DTM;Z)Z
+Lorg/apache/xml/dtm/ref/CoroutineManager;-><init>()V
+Lorg/apache/xml/dtm/ref/CoroutineManager;->co_joinCoroutineSet(I)I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->includeSelf()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->reset()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->resetPosition()Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->returnNode(I)I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->setRestartable(Z)V
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_includeSelf:Z
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_isRestartable:Z
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_last:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_markedNode:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_position:I
+Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_startNode:I
+Lorg/apache/xml/dtm/ref/DTMAxisIterNodeList;-><init>(Lorg/apache/xml/dtm/DTM;Lorg/apache/xml/dtm/DTMAxisIterator;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendChild(IZZ)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendTextChild(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->declareNamespaceInContext(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRegistration()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRelease()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->ensureSizeOfIndex(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->error(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findGTE([IIII)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findInSortedSuballocatedIntVector(Lorg/apache/xml/utils/SuballocatedIntVector;I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findNamespaceContext(I)Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocument()I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentAllDeclarationsProcessed()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentBaseURI()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentEncoding(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentRoot(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentStandalone(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentSystemIdentifier(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentVersion(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDTMIDs()Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstChild(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstNamespaceNode(IZ)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLastChild(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLevel(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLocalNameFromExpandedNameID(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceFromExpandedNameID(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceType(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextAttribute(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextNamespaceNode(IIZ)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextSibling(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNode(I)Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeHandle(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeIdent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeType(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getOwnerDocument(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getParent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getPreviousSibling(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getShouldStripWhitespace()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunk(II[I)[C
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunkCount(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->hasChildNodes(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->indexNode(II)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isCharacterElementContentWhitespace(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isDocumentAllDeclarationsProcessed(I)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isNodeAfter(II)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isSupported(Ljava/lang/String;Ljava/lang/String;)Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeHandle(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeIdentity(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_expandedNameTable:Lorg/apache/xml/dtm/ref/ExpandedNameTable;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_exptype:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_firstch:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_nextsib:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_parent:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_prevsib:Lorg/apache/xml/utils/SuballocatedIntVector;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_size:I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_wsfilter:Lorg/apache/xml/dtm/DTMWSFilter;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_xstrf:Lorg/apache/xml/utils/XMLStringFactory;
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->popShouldStripWhitespace()V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->pushShouldStripWhitespace(Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setDocumentBaseURI(Ljava/lang/String;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setFeature(Ljava/lang/String;Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setShouldStripWhitespace(Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->supportsPreStripping()Z
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_exptype(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_firstch(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_level(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_nextsib(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_parent(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_prevsib(I)I
+Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_type(I)S
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;->_currentNode:I
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->next()I
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NthDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;Z)V
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getAxisIterator(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getTypedAxisIterator(II)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/DTMDefaultBaseTraversers;->getAxisTraverser(I)Lorg/apache/xml/dtm/DTMAxisTraverser;
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;I)V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;II)V
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getFirstFreeDTMID()I
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getXMLReader(Ljavax/xml/transform/Source;)Lorg/xml/sax/XMLReader;
+Lorg/apache/xml/dtm/ref/DTMManagerDefault;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getDTMIterator()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getRoot()Lorg/w3c/dom/Node;
+Lorg/apache/xml/dtm/ref/DTMNodeList;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;-><init>(Lorg/apache/xml/dtm/DTM;I)V
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTM()Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTMNodeNumber()I
+Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getStringValue()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMStringPool;-><init>()V
+Lorg/apache/xml/dtm/ref/DTMStringPool;->indexToString(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/DTMStringPool;->m_intToString:Ljava/util/Vector;
+Lorg/apache/xml/dtm/ref/DTMStringPool;->removeAllElements()V
+Lorg/apache/xml/dtm/ref/DTMStringPool;->stringToIndex(Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;IZ)I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getLocalName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getSize()I
+Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getType(I)S
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->deliverMoreNodes(Z)Ljava/lang/Object;
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setContentHandler(Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setLexicalHandler(Lorg/xml/sax/ext/LexicalHandler;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->startParse(Lorg/xml/sax/InputSource;)V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;-><init>()V
+Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;->setXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->next()I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$DescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;->setNodeType(I)Lorg/apache/xml/dtm/DTMAxisIterator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedSingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;ZIZZZ)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttribute(IILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttributes(ILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyElement(IILorg/apache/xml/serializer/SerializationHandler;)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyNS(ILorg/apache/xml/serializer/SerializationHandler;Z)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyTextNode(ILorg/apache/xml/serializer/SerializationHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->dispatchCharactersEvents(ILorg/xml/sax/ContentHandler;Z)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getFirstAttribute(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getIdForNamespace(Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getLocalName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeName(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeNameX(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeValue(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue(I)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValueX(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->m_buildIdIndex:Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2Type(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_firstch2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_nextsib2(I)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->dispatchToEvents(ILorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getAttributeNode(ILjava/lang/String;Ljava/lang/String;)I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getContentHandler()Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDeclHandler()Lorg/xml/sax/ext/DeclHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationPublicIdentifier()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationSystemIdentifier()Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDTDHandler()Lorg/xml/sax/DTDHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getEntityResolver()Lorg/xml/sax/EntityResolver;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getErrorHandler()Lorg/xml/sax/ErrorHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getLexicalHandler()Lorg/xml/sax/ext/LexicalHandler;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNamespaceURI(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNumberOfNodes()I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getPrefix(I)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getUnparsedEntityURI(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->isAttributeSpecified(I)Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_idAttributes:Ljava/util/Hashtable;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_parents:Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_previous:I
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->needsTwoThreads()Z
+Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->setProperty(Ljava/lang/String;Ljava/lang/Object;)V
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getContextClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileExists(Ljava/io/File;)Z
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileInputStream(Ljava/io/File;)Ljava/io/FileInputStream;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getInstance()Lorg/apache/xml/dtm/ref/SecuritySupport;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getLastModified(Ljava/io/File;)J
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getParentClassLoader(Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getResourceAsStream(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/io/InputStream;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemClassLoader()Ljava/lang/ClassLoader;
+Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemProperty(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/res/XMLErrorResources;-><init>()V
+Lorg/apache/xml/res/XMLMessages;->createXMLMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xml/serializer/CharInfo$CharKey;-><init>(C)V
+Lorg/apache/xml/serializer/CharInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Z)V
+Lorg/apache/xml/serializer/CharInfo;->get(I)Z
+Lorg/apache/xml/serializer/CharInfo;->getCharInfo(Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/CharInfo;
+Lorg/apache/xml/serializer/CharInfo;->set(I)V
+Lorg/apache/xml/serializer/dom3/LSSerializerImpl;-><init>()V
+Lorg/apache/xml/serializer/DOMSerializer;->serialize(Lorg/w3c/dom/Node;)V
+Lorg/apache/xml/serializer/ElemContext;->m_elementName:Ljava/lang/String;
+Lorg/apache/xml/serializer/ElemContext;->m_elementURI:Ljava/lang/String;
+Lorg/apache/xml/serializer/ElemContext;->m_startTagOpen:Z
+Lorg/apache/xml/serializer/ElemContext;->push(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/ElemContext;
+Lorg/apache/xml/serializer/ElemDesc;->isAttrFlagSet(Ljava/lang/String;I)Z
+Lorg/apache/xml/serializer/Encodings;->convertMime2JavaEncoding(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/Encodings;->getMimeEncoding(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/Encodings;->getWriter(Ljava/io/OutputStream;Ljava/lang/String;)Ljava/io/Writer;
+Lorg/apache/xml/serializer/NamespaceMappings;-><init>()V
+Lorg/apache/xml/serializer/NamespaceMappings;->generateNextPrefix()Ljava/lang/String;
+Lorg/apache/xml/serializer/NamespaceMappings;->lookupNamespace(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/NamespaceMappings;->lookupPrefix(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/OutputPropertiesFactory;->getDefaultMethodProperties(Ljava/lang/String;)Ljava/util/Properties;
+Lorg/apache/xml/serializer/OutputPropertyUtils;->getBooleanProperty(Ljava/lang/String;Ljava/util/Properties;)Z
+Lorg/apache/xml/serializer/OutputPropertyUtils;->getIntProperty(Ljava/lang/String;Ljava/util/Properties;)I
+Lorg/apache/xml/serializer/SerializationHandler;->close()V
+Lorg/apache/xml/serializer/SerializationHandler;->flushPending()V
+Lorg/apache/xml/serializer/SerializationHandler;->setEscaping(Z)Z
+Lorg/apache/xml/serializer/SerializationHandler;->setIndentAmount(I)V
+Lorg/apache/xml/serializer/SerializationHandler;->setNamespaceMappings(Lorg/apache/xml/serializer/NamespaceMappings;)V
+Lorg/apache/xml/serializer/Serializer;->asContentHandler()Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/serializer/Serializer;->asDOMSerializer()Lorg/apache/xml/serializer/DOMSerializer;
+Lorg/apache/xml/serializer/Serializer;->getOutputFormat()Ljava/util/Properties;
+Lorg/apache/xml/serializer/Serializer;->getOutputStream()Ljava/io/OutputStream;
+Lorg/apache/xml/serializer/Serializer;->getWriter()Ljava/io/Writer;
+Lorg/apache/xml/serializer/Serializer;->reset()Z
+Lorg/apache/xml/serializer/Serializer;->setOutputFormat(Ljava/util/Properties;)V
+Lorg/apache/xml/serializer/Serializer;->setOutputStream(Ljava/io/OutputStream;)V
+Lorg/apache/xml/serializer/Serializer;->setWriter(Ljava/io/Writer;)V
+Lorg/apache/xml/serializer/SerializerBase;->fireCharEvent([CII)V
+Lorg/apache/xml/serializer/SerializerBase;->fireCommentEvent([CII)V
+Lorg/apache/xml/serializer/SerializerBase;->fireEndDoc()V
+Lorg/apache/xml/serializer/SerializerBase;->fireEndElem(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->fireEscapingEvent(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->getDoctypePublic()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getDoctypeSystem()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getEncoding()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getPrefixPart(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->getVersion()Ljava/lang/String;
+Lorg/apache/xml/serializer/SerializerBase;->m_attributes:Lorg/apache/xml/serializer/AttributesImplSerializer;
+Lorg/apache/xml/serializer/SerializerBase;->m_charsBuff:[C
+Lorg/apache/xml/serializer/SerializerBase;->m_elemContext:Lorg/apache/xml/serializer/ElemContext;
+Lorg/apache/xml/serializer/SerializerBase;->m_needToCallStartDocument:Z
+Lorg/apache/xml/serializer/SerializerBase;->m_tracer:Lorg/apache/xml/serializer/SerializerTrace;
+Lorg/apache/xml/serializer/SerializerBase;->setDoctypePublic(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setDoctypeSystem(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setIndent(Z)V
+Lorg/apache/xml/serializer/SerializerBase;->setMediaType(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setOmitXMLDeclaration(Z)V
+Lorg/apache/xml/serializer/SerializerBase;->setStandalone(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setStandaloneInternal(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerBase;->setVersion(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/SerializerFactory;->getSerializer(Ljava/util/Properties;)Lorg/apache/xml/serializer/Serializer;
+Lorg/apache/xml/serializer/SerializerTraceWriter;-><init>(Ljava/io/Writer;Lorg/apache/xml/serializer/SerializerTrace;)V
+Lorg/apache/xml/serializer/ToHTMLStream;-><init>()V
+Lorg/apache/xml/serializer/ToHTMLStream;->getElemDesc(Ljava/lang/String;)Lorg/apache/xml/serializer/ElemDesc;
+Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToSAXHandler;->m_lexHandler:Lorg/xml/sax/ext/LexicalHandler;
+Lorg/apache/xml/serializer/ToSAXHandler;->m_saxHandler:Lorg/xml/sax/ContentHandler;
+Lorg/apache/xml/serializer/ToSAXHandler;->reset()Z
+Lorg/apache/xml/serializer/ToSAXHandler;->startDocumentInternal()V
+Lorg/apache/xml/serializer/ToSAXHandler;->startElement(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToStream;->setCdataSectionElements(Ljava/lang/String;Ljava/util/Properties;)V
+Lorg/apache/xml/serializer/ToStream;->setEncoding(Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToStream;->setIndentAmount(I)V
+Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToTextStream;-><init>()V
+Lorg/apache/xml/serializer/ToUnknownStream;-><init>()V
+Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V
+Lorg/apache/xml/serializer/ToXMLStream;-><init>()V
+Lorg/apache/xml/serializer/WriterToASCI;-><init>(Ljava/io/OutputStream;)V
+Lorg/apache/xml/serializer/WriterToUTF8Buffered;-><init>(Ljava/io/OutputStream;)V
+Lorg/apache/xml/utils/DefaultErrorHandler;-><init>()V
+Lorg/apache/xml/utils/DefaultErrorHandler;->printLocation(Ljava/io/PrintWriter;Ljava/lang/Throwable;)V
+Lorg/apache/xml/utils/DOMHelper;->isNodeAfter(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z
+Lorg/apache/xml/utils/DOMHelper;->isNodeTheSame(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z
+Lorg/apache/xml/utils/FastStringBuffer;->append(Ljava/lang/String;)V
+Lorg/apache/xml/utils/FastStringBuffer;->getString(II)Ljava/lang/String;
+Lorg/apache/xml/utils/FastStringBuffer;->length()I
+Lorg/apache/xml/utils/IntStack;->peek()I
+Lorg/apache/xml/utils/ObjectVector;->elementAt(I)Ljava/lang/Object;
+Lorg/apache/xml/utils/ObjectVector;->size()I
+Lorg/apache/xml/utils/PrefixResolverDefault;-><init>(Lorg/w3c/dom/Node;)V
+Lorg/apache/xml/utils/PrefixResolverDefault;->getNamespaceForPrefix(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/QName;->getLocalName()Ljava/lang/String;
+Lorg/apache/xml/utils/SAXSourceLocator;-><init>(Lorg/xml/sax/SAXParseException;)V
+Lorg/apache/xml/utils/StringBufferPool;->free(Lorg/apache/xml/utils/FastStringBuffer;)V
+Lorg/apache/xml/utils/StringBufferPool;->get()Lorg/apache/xml/utils/FastStringBuffer;
+Lorg/apache/xml/utils/StringVector;->elementAt(I)Ljava/lang/String;
+Lorg/apache/xml/utils/StringVector;->size()I
+Lorg/apache/xml/utils/StylesheetPIHandler;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/StylesheetPIHandler;->getAssociatedStylesheet()Ljavax/xml/transform/Source;
+Lorg/apache/xml/utils/StylesheetPIHandler;->setBaseId(Ljava/lang/String;)V
+Lorg/apache/xml/utils/StylesheetPIHandler;->setURIResolver(Ljavax/xml/transform/URIResolver;)V
+Lorg/apache/xml/utils/SuballocatedIntVector;-><init>(I)V
+Lorg/apache/xml/utils/SuballocatedIntVector;->elementAt(I)I
+Lorg/apache/xml/utils/SuballocatedIntVector;->setElementAt(II)V
+Lorg/apache/xml/utils/SuballocatedIntVector;->size()I
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURIFromRelative(Ljava/lang/String;)Ljava/lang/String;
+Lorg/apache/xml/utils/SystemIDResolver;->isAbsoluteURI(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/URI$MalformedURIException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;)V
+Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->getFragment()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getHost()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getPath()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getPort()I
+Lorg/apache/xml/utils/URI;->getQueryString()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getScheme()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->getUserinfo()Ljava/lang/String;
+Lorg/apache/xml/utils/URI;->setFragment(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setHost(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setPort(I)V
+Lorg/apache/xml/utils/URI;->setScheme(Ljava/lang/String;)V
+Lorg/apache/xml/utils/URI;->setUserinfo(Ljava/lang/String;)V
+Lorg/apache/xml/utils/WrappedRuntimeException;-><init>(Ljava/lang/Exception;)V
+Lorg/apache/xml/utils/WrappedRuntimeException;->getException()Ljava/lang/Exception;
+Lorg/apache/xml/utils/XML11Char;->isXML11ValidNCName(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/XML11Char;->isXML11ValidQName(Ljava/lang/String;)Z
+Lorg/apache/xml/utils/XMLReaderManager;->getInstance()Lorg/apache/xml/utils/XMLReaderManager;
+Lorg/apache/xml/utils/XMLReaderManager;->getXMLReader()Lorg/xml/sax/XMLReader;
+Lorg/apache/xml/utils/XMLReaderManager;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V
+Lorg/apache/xml/utils/XMLString;->dispatchCharactersEvents(Lorg/xml/sax/ContentHandler;)V
+Lorg/apache/xml/utils/XMLString;->equals(Lorg/apache/xml/utils/XMLString;)Z
+Lorg/apache/xml/utils/XMLString;->fixWhiteSpace(ZZZ)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/utils/XMLStringDefault;-><init>(Ljava/lang/String;)V
+Lorg/apache/xml/utils/XMLStringFactory;-><init>()V
+Lorg/apache/xml/utils/XMLStringFactory;->emptystr()Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xml/utils/XMLStringFactory;->newstr(Ljava/lang/String;)Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xpath/axes/ChildTestIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisTraverser;)V
+Lorg/apache/xpath/axes/DescendantIterator;-><init>()V
+Lorg/apache/xpath/axes/LocPathIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xpath/axes/LocPathIterator;->getPrefixResolver()Lorg/apache/xml/utils/PrefixResolver;
+Lorg/apache/xpath/axes/LocPathIterator;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/axes/NodeSequence;->getContainedIter()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/axes/NodeSequence;->nextNode()I
+Lorg/apache/xpath/axes/OneStepIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisIterator;I)V
+Lorg/apache/xpath/CachedXPathAPI;-><init>()V
+Lorg/apache/xpath/CachedXPathAPI;-><init>(Lorg/apache/xpath/CachedXPathAPI;)V
+Lorg/apache/xpath/CachedXPathAPI;->eval(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/CachedXPathAPI;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/compiler/FunctionTable;-><init>()V
+Lorg/apache/xpath/compiler/FunctionTable;->installFunction(Ljava/lang/String;Ljava/lang/Class;)I
+Lorg/apache/xpath/Expression;->assertion(ZLjava/lang/String;)V
+Lorg/apache/xpath/Expression;->error(Lorg/apache/xpath/XPathContext;Ljava/lang/String;[Ljava/lang/Object;)V
+Lorg/apache/xpath/Expression;->exprGetParent()Lorg/apache/xpath/ExpressionNode;
+Lorg/apache/xpath/ExpressionNode;->exprGetParent()Lorg/apache/xpath/ExpressionNode;
+Lorg/apache/xpath/functions/FuncCurrent;-><init>()V
+Lorg/apache/xpath/functions/FuncExtFunction;->getFunctionName()Ljava/lang/String;
+Lorg/apache/xpath/functions/FuncExtFunction;->getMethodKey()Ljava/lang/Object;
+Lorg/apache/xpath/functions/Function;-><init>()V
+Lorg/apache/xpath/functions/WrongNumberArgsException;-><init>(Ljava/lang/String;)V
+Lorg/apache/xpath/NodeSet;-><init>()V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/NodeList;)V
+Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/traversal/NodeIterator;)V
+Lorg/apache/xpath/NodeSet;->addElement(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;->addNode(Lorg/w3c/dom/Node;)V
+Lorg/apache/xpath/NodeSet;->contains(Lorg/w3c/dom/Node;)Z
+Lorg/apache/xpath/NodeSet;->elementAt(I)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/NodeSet;->setShouldCacheNodes(Z)V
+Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/NodeList;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/traversal/NodeIterator;Lorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/NodeSetDTM;->addNode(I)V
+Lorg/apache/xpath/NodeSetDTM;->detach()V
+Lorg/apache/xpath/NodeSetDTM;->getLength()I
+Lorg/apache/xpath/NodeSetDTM;->item(I)I
+Lorg/apache/xpath/objects/XBoolean;-><init>(Z)V
+Lorg/apache/xpath/objects/XBoolean;->bool()Z
+Lorg/apache/xpath/objects/XBoolean;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XBooleanStatic;-><init>(Z)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(ILorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMManager;)V
+Lorg/apache/xpath/objects/XNodeSet;->iterRaw()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XNodeSet;->mutableNodeset()Lorg/apache/xpath/NodeSetDTM;
+Lorg/apache/xpath/objects/XNodeSet;->nodelist()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XNumber;-><init>(D)V
+Lorg/apache/xpath/objects/XNumber;->num()D
+Lorg/apache/xpath/objects/XNumber;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->bool()Z
+Lorg/apache/xpath/objects/XObject;->create(Ljava/lang/Object;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/objects/XObject;->getType()I
+Lorg/apache/xpath/objects/XObject;->getTypeString()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->iter()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XObject;->nodelist()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XObject;->nodeset()Lorg/w3c/dom/traversal/NodeIterator;
+Lorg/apache/xpath/objects/XObject;->num()D
+Lorg/apache/xpath/objects/XObject;->object()Ljava/lang/Object;
+Lorg/apache/xpath/objects/XObject;->str()Ljava/lang/String;
+Lorg/apache/xpath/objects/XObject;->xstr()Lorg/apache/xml/utils/XMLString;
+Lorg/apache/xpath/objects/XRTreeFrag;-><init>(ILorg/apache/xpath/XPathContext;)V
+Lorg/apache/xpath/objects/XRTreeFrag;->asNodeIterator()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/objects/XRTreeFrag;->convertToNodeset()Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/objects/XString;-><init>(Ljava/lang/String;)V
+Lorg/apache/xpath/objects/XString;->num()D
+Lorg/apache/xpath/patterns/NodeTest;->setWhatToShow(I)V
+Lorg/apache/xpath/res/XPATHErrorResources;-><init>()V
+Lorg/apache/xpath/res/XPATHMessages;->createXPATHMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
+Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;I)V
+Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;ILjavax/xml/transform/ErrorListener;)V
+Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject;
+Lorg/apache/xpath/XPath;->getPatternString()Ljava/lang/String;
+Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList;
+Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
+Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext;
+Lorg/apache/xpath/XPathContext;-><init>()V
+Lorg/apache/xpath/XPathContext;-><init>(Ljava/lang/Object;)V
+Lorg/apache/xpath/XPathContext;->getAxesIteratorStackStacks()Ljava/util/Stack;
+Lorg/apache/xpath/XPathContext;->getContextNodeList()Lorg/apache/xml/dtm/DTMIterator;
+Lorg/apache/xpath/XPathContext;->getContextNodeListsStack()Ljava/util/Stack;
+Lorg/apache/xpath/XPathContext;->getCurrentExpressionNodeStack()Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xpath/XPathContext;->getCurrentNode()I
+Lorg/apache/xpath/XPathContext;->getCurrentNodeStack()Lorg/apache/xml/utils/IntStack;
+Lorg/apache/xpath/XPathContext;->getDTM(I)Lorg/apache/xml/dtm/DTM;
+Lorg/apache/xpath/XPathContext;->getDTMHandleFromNode(Lorg/w3c/dom/Node;)I
+Lorg/apache/xpath/XPathContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext;->getExpressionContext()Lorg/apache/xalan/extensions/ExpressionContext;
+Lorg/apache/xpath/XPathContext;->getNamespaceContext()Lorg/apache/xml/utils/PrefixResolver;
+Lorg/apache/xpath/XPathContext;->getOwnerObject()Ljava/lang/Object;
+Lorg/apache/xpath/XPathContext;->getSAXLocator()Ljavax/xml/transform/SourceLocator;
+Lorg/apache/xpath/XPathContext;->getVarStack()Lorg/apache/xpath/VariableStack;
+Lorg/apache/xpath/XPathContext;->m_dtmManager:Lorg/apache/xml/dtm/DTMManager;
+Lorg/apache/xpath/XPathContext;->popContextNodeList()V
+Lorg/apache/xpath/XPathContext;->popCurrentNode()V
+Lorg/apache/xpath/XPathContext;->pushContextNodeList(Lorg/apache/xml/dtm/DTMIterator;)V
+Lorg/apache/xpath/XPathContext;->pushCurrentNode(I)V
+Lorg/apache/xpath/XPathContext;->reset()V
+Lorg/apache/xpath/XPathContext;->setAxesIteratorStackStacks(Ljava/util/Stack;)V
+Lorg/apache/xpath/XPathContext;->setContextNodeListsStack(Ljava/util/Stack;)V
+Lorg/apache/xpath/XPathContext;->setCurrentExpressionNodeStack(Lorg/apache/xml/utils/IntStack;)V
+Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V
+Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V
+Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader;
+Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V
+Lorg/ccil/cowan/tagsoup/Element;->anonymize()V
+Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z
+Lorg/ccil/cowan/tagsoup/Element;->clean()V
+Lorg/ccil/cowan/tagsoup/Element;->flags()I
+Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z
+Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V
+Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
@@ -2292,10 +5640,500 @@
Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
+Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V
Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V
+Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;
Lorg/ccil/cowan/tagsoup/Parser;-><init>()V
+Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z
+Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z
+Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z
+Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C
+Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;
+Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z
+Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z
+Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I
+Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->pop()V
+Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V
+Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V
+Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z
+Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector;
+Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler;
+Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z
+Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap;
+Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler;
+Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner;
+Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
+Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element;
+Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z
+Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V
+Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V
+Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V
+Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V
+Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V
+Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I
+Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V
Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V
+Lorg/xml/sax/helpers/NamespaceSupport$Context;-><init>(Lorg/xml/sax/helpers/NamespaceSupport;)V
+Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;-><init>(Lorg/xml/sax/helpers/ParserAdapter;)V
+Lsun/misc/ASCIICaseInsensitiveComparator;->CASE_INSENSITIVE_ORDER:Ljava/util/Comparator;
+Lsun/misc/ASCIICaseInsensitiveComparator;->lowerCaseHashCode(Ljava/lang/String;)I
+Lsun/misc/BASE64Decoder;-><init>()V
+Lsun/misc/BASE64Decoder;->pem_convert_array:[B
+Lsun/misc/BASE64Encoder;-><init>()V
+Lsun/misc/BASE64Encoder;->pem_array:[C
+Lsun/misc/CEFormatException;-><init>(Ljava/lang/String;)V
+Lsun/misc/CEStreamExhausted;-><init>()V
+Lsun/misc/CharacterDecoder;-><init>()V
+Lsun/misc/CharacterEncoder;-><init>()V
+Lsun/misc/CharacterEncoder;->encodeBuffer([B)Ljava/lang/String;
+Lsun/misc/CharacterEncoder;->encodeBufferPrefix(Ljava/io/OutputStream;)V
+Lsun/misc/CharacterEncoder;->pStream:Ljava/io/PrintStream;
+Lsun/misc/Cleaner;->create(Ljava/lang/Object;Ljava/lang/Runnable;)Lsun/misc/Cleaner;
+Lsun/misc/FloatingDecimal;->$assertionsDisabled:Z
+Lsun/misc/FloatingDecimal;->getHexDigit(Ljava/lang/String;I)I
+Lsun/misc/FloatingDecimal;->stripLeadingZeros(Ljava/lang/String;)Ljava/lang/String;
+Lsun/misc/FormattedFloatingDecimal$Form;->COMPATIBLE:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal$Form;->DECIMAL_FLOAT:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal$Form;->SCIENTIFIC:Lsun/misc/FormattedFloatingDecimal$Form;
+Lsun/misc/FormattedFloatingDecimal;->$assertionsDisabled:Z
+Lsun/misc/FpUtils;->$assertionsDisabled:Z
+Lsun/misc/FpUtils;->rawCopySign(DD)D
+Lsun/misc/HexDumpEncoder;-><init>()V
+Lsun/misc/HexDumpEncoder;->currentByte:I
+Lsun/misc/HexDumpEncoder;->offset:I
+Lsun/misc/HexDumpEncoder;->thisLine:[B
+Lsun/misc/HexDumpEncoder;->thisLineLength:I
+Lsun/misc/IOUtils;->readFully(Ljava/io/InputStream;IZ)[B
+Lsun/misc/JarIndex;-><init>([Ljava/lang/String;)V
+Lsun/misc/JarIndex;->write(Ljava/io/OutputStream;)V
+Lsun/misc/MessageUtils;-><init>()V
+Lsun/misc/MetaIndex;->forJar(Ljava/io/File;)Lsun/misc/MetaIndex;
+Lsun/misc/MetaIndex;->registerDirectory(Ljava/io/File;)V
+Lsun/misc/VM;->maxDirectMemory()J
+Lsun/net/ftp/FtpClient;-><init>()V
+Lsun/net/util/IPAddressUtil;->isIPv4LiteralAddress(Ljava/lang/String;)Z
+Lsun/net/util/IPAddressUtil;->isIPv6LiteralAddress(Ljava/lang/String;)Z
+Lsun/net/www/MessageHeader;-><init>()V
+Lsun/net/www/MessageHeader;-><init>(Ljava/io/InputStream;)V
+Lsun/net/www/MessageHeader;->add(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/MessageHeader;->findValue(Ljava/lang/String;)Ljava/lang/String;
+Lsun/net/www/MessageHeader;->prepend(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/MessageHeader;->print(Ljava/io/PrintStream;)V
+Lsun/net/www/MessageHeader;->set(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/net/www/ParseUtil;->decode(Ljava/lang/String;)Ljava/lang/String;
+Lsun/net/www/ParseUtil;->encodePath(Ljava/lang/String;Z)Ljava/lang/String;
+Lsun/net/www/ParseUtil;->fileToEncodedURL(Ljava/io/File;)Ljava/net/URL;
+Lsun/net/www/URLConnection;-><init>(Ljava/net/URL;)V
+Lsun/net/www/URLConnection;->setProperties(Lsun/net/www/MessageHeader;)V
+Lsun/nio/ch/DirectBuffer;->address()J
+Lsun/nio/ch/FileChannelImpl;->unmap0(JJ)I
+Lsun/nio/ch/SelectorImpl;->publicSelectedKeys:Ljava/util/Set;
+Lsun/nio/ch/SelectorImpl;->selectedKeys:Ljava/util/Set;
+Lsun/nio/cs/HistoricallyNamedCharset;->historicalName()Ljava/lang/String;
+Lsun/nio/cs/ThreadLocalCoders;->decoderFor(Ljava/lang/Object;)Ljava/nio/charset/CharsetDecoder;
+Lsun/nio/fs/BasicFileAttributesHolder;->get()Ljava/nio/file/attribute/BasicFileAttributes;
+Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/Class;)V
+Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/String;)V
+Lsun/reflect/misc/ReflectUtil;->isPackageAccessible(Ljava/lang/Class;)Z
+Lsun/reflect/misc/ReflectUtil;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z
+Lsun/reflect/Reflection;->ensureMemberAccess(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;I)V
+Lsun/reflect/Reflection;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z
+Lsun/security/action/GetBooleanAction;-><init>(Ljava/lang/String;)V
+Lsun/security/action/GetIntegerAction;-><init>(Ljava/lang/String;I)V
+Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;)V
+Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/jca/GetInstance$Instance;->impl:Ljava/lang/Object;
+Lsun/security/jca/GetInstance$Instance;->provider:Ljava/security/Provider;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/security/Provider;)Lsun/security/jca/GetInstance$Instance;
+Lsun/security/jca/JCAUtil;->getSecureRandom()Ljava/security/SecureRandom;
+Lsun/security/jca/ProviderConfig;->argument:Ljava/lang/String;
+Lsun/security/jca/ProviderConfig;->CL_STRING:[Ljava/lang/Class;
+Lsun/security/jca/ProviderConfig;->disableLoad()V
+Lsun/security/jca/ProviderConfig;->hasArgument()Z
+Lsun/security/jca/ProviderList;->getService(Ljava/lang/String;Ljava/lang/String;)Ljava/security/Provider$Service;
+Lsun/security/jca/Providers;->getProviderList()Lsun/security/jca/ProviderList;
+Lsun/security/jca/Providers;->startJarVerification()Ljava/lang/Object;
+Lsun/security/jca/Providers;->stopJarVerification(Ljava/lang/Object;)V
+Lsun/security/pkcs/ContentInfo;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V
+Lsun/security/pkcs/ContentInfo;-><init>([B)V
+Lsun/security/pkcs/ContentInfo;->DATA_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/ContentInfo;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/pkcs/ContentInfo;->getData()[B
+Lsun/security/pkcs/ParsingException;-><init>(Ljava/lang/String;)V
+Lsun/security/pkcs/PKCS7;-><init>([B)V
+Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Ljava/security/cert/X509CRL;[Lsun/security/pkcs/SignerInfo;)V
+Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Lsun/security/pkcs/SignerInfo;)V
+Lsun/security/pkcs/PKCS7;->encodeSignedData(Ljava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS7;->getCertificates()[Ljava/security/cert/X509Certificate;
+Lsun/security/pkcs/PKCS7;->getContentInfo()Lsun/security/pkcs/ContentInfo;
+Lsun/security/pkcs/PKCS7;->getSignerInfos()[Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS7;->verify(Lsun/security/pkcs/SignerInfo;[B)Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS7;->verify([B)[Lsun/security/pkcs/SignerInfo;
+Lsun/security/pkcs/PKCS8Key;-><init>()V
+Lsun/security/pkcs/PKCS8Key;->algid:Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/PKCS8Key;->encodedKey:[B
+Lsun/security/pkcs/PKCS8Key;->key:[B
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/lang/Object;)V
+Lsun/security/pkcs/PKCS9Attribute;->CONTENT_TYPE_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->derEncode(Ljava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS9Attribute;->EMAIL_ADDRESS_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->getValue()Ljava/lang/Object;
+Lsun/security/pkcs/PKCS9Attribute;->MESSAGE_DIGEST_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attribute;->SIGNING_TIME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;Z)V
+Lsun/security/pkcs/PKCS9Attributes;-><init>([Lsun/security/pkcs/PKCS9Attribute;)V
+Lsun/security/pkcs/PKCS9Attributes;->encode(BLjava/io/OutputStream;)V
+Lsun/security/pkcs/PKCS9Attributes;->getAttribute(Ljava/lang/String;)Lsun/security/pkcs/PKCS9Attribute;
+Lsun/security/pkcs/PKCS9Attributes;->getAttributeValue(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Object;
+Lsun/security/pkcs/PKCS9Attributes;->getDerEncoding()[B
+Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/PKCS9Attributes;Lsun/security/x509/AlgorithmId;[BLsun/security/pkcs/PKCS9Attributes;)V
+Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/x509/AlgorithmId;[B)V
+Lsun/security/pkcs/SignerInfo;->getCertificate(Lsun/security/pkcs/PKCS7;)Ljava/security/cert/X509Certificate;
+Lsun/security/pkcs/SignerInfo;->getCertificateChain(Lsun/security/pkcs/PKCS7;)Ljava/util/ArrayList;
+Lsun/security/pkcs/SignerInfo;->getDigestAlgorithmId()Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/SignerInfo;->getDigestEncryptionAlgorithmId()Lsun/security/x509/AlgorithmId;
+Lsun/security/pkcs/SignerInfo;->getEncryptedDigest()[B
+Lsun/security/provider/certpath/X509CertificatePair;->clearCache()V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;)V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V
+Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/util/List;)V
+Lsun/security/provider/certpath/X509CertPath;->certs:Ljava/util/List;
+Lsun/security/provider/certpath/X509CertPath;->getEncodingsStatic()Ljava/util/Iterator;
+Lsun/security/provider/X509Factory;->addToCache(Lsun/security/util/Cache;[BLjava/lang/Object;)V
+Lsun/security/provider/X509Factory;->certCache:Lsun/security/util/Cache;
+Lsun/security/provider/X509Factory;->crlCache:Lsun/security/util/Cache;
+Lsun/security/provider/X509Factory;->getFromCache(Lsun/security/util/Cache;[B)Ljava/lang/Object;
+Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509Certificate;)Lsun/security/x509/X509CertImpl;
+Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509CRL;)Lsun/security/x509/X509CRLImpl;
+Lsun/security/timestamp/TimestampToken;-><init>([B)V
+Lsun/security/timestamp/TimestampToken;->getDate()Ljava/util/Date;
+Lsun/security/timestamp/TimestampToken;->getHashAlgorithm()Lsun/security/x509/AlgorithmId;
+Lsun/security/timestamp/TimestampToken;->getHashedMessage()[B
+Lsun/security/timestamp/TimestampToken;->getNonce()Ljava/math/BigInteger;
+Lsun/security/util/BitArray;-><init>(I[B)V
+Lsun/security/util/BitArray;->toByteArray()[B
+Lsun/security/util/Cache;-><init>()V
+Lsun/security/util/Cache;->clear()V
+Lsun/security/util/Cache;->get(Ljava/lang/Object;)Ljava/lang/Object;
+Lsun/security/util/Cache;->newHardMemoryCache(I)Lsun/security/util/Cache;
+Lsun/security/util/Cache;->put(Ljava/lang/Object;Ljava/lang/Object;)V
+Lsun/security/util/Debug;->getInstance(Ljava/lang/String;)Lsun/security/util/Debug;
+Lsun/security/util/Debug;->println()V
+Lsun/security/util/Debug;->println(Ljava/lang/String;)V
+Lsun/security/util/Debug;->toHexString(Ljava/math/BigInteger;)Ljava/lang/String;
+Lsun/security/util/DerIndefLenConverter;-><init>()V
+Lsun/security/util/DerIndefLenConverter;->convert([B)[B
+Lsun/security/util/DerIndefLenConverter;->data:[B
+Lsun/security/util/DerIndefLenConverter;->dataPos:I
+Lsun/security/util/DerIndefLenConverter;->dataSize:I
+Lsun/security/util/DerIndefLenConverter;->isIndefinite(I)Z
+Lsun/security/util/DerIndefLenConverter;->newData:[B
+Lsun/security/util/DerIndefLenConverter;->numOfTotalLenBytes:I
+Lsun/security/util/DerIndefLenConverter;->parseLength()I
+Lsun/security/util/DerIndefLenConverter;->parseTag()V
+Lsun/security/util/DerIndefLenConverter;->parseValue(I)V
+Lsun/security/util/DerIndefLenConverter;->writeLengthAndValue()V
+Lsun/security/util/DerIndefLenConverter;->writeTag()V
+Lsun/security/util/DerInputStream;-><init>([B)V
+Lsun/security/util/DerInputStream;->available()I
+Lsun/security/util/DerInputStream;->getBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerInputStream;->getBitString()[B
+Lsun/security/util/DerInputStream;->getDerValue()Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getInteger()I
+Lsun/security/util/DerInputStream;->getOctetString()[B
+Lsun/security/util/DerInputStream;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/DerInputStream;->getSequence(I)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getSet(I)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getSet(IZ)[Lsun/security/util/DerValue;
+Lsun/security/util/DerInputStream;->getUTCTime()Ljava/util/Date;
+Lsun/security/util/DerInputStream;->getUTF8String()Ljava/lang/String;
+Lsun/security/util/DerInputStream;->mark(I)V
+Lsun/security/util/DerInputStream;->peekByte()I
+Lsun/security/util/DerInputStream;->reset()V
+Lsun/security/util/DerInputStream;->subStream(IZ)Lsun/security/util/DerInputStream;
+Lsun/security/util/DerInputStream;->tag:B
+Lsun/security/util/DerOutputStream;-><init>()V
+Lsun/security/util/DerOutputStream;-><init>(I)V
+Lsun/security/util/DerOutputStream;->putBitString([B)V
+Lsun/security/util/DerOutputStream;->putBoolean(Z)V
+Lsun/security/util/DerOutputStream;->putDerValue(Lsun/security/util/DerValue;)V
+Lsun/security/util/DerOutputStream;->putIA5String(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->putInteger(I)V
+Lsun/security/util/DerOutputStream;->putInteger(Ljava/math/BigInteger;)V
+Lsun/security/util/DerOutputStream;->putNull()V
+Lsun/security/util/DerOutputStream;->putOctetString([B)V
+Lsun/security/util/DerOutputStream;->putOID(Lsun/security/util/ObjectIdentifier;)V
+Lsun/security/util/DerOutputStream;->putOrderedSetOf(B[Lsun/security/util/DerEncoder;)V
+Lsun/security/util/DerOutputStream;->putPrintableString(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->putSequence([Lsun/security/util/DerValue;)V
+Lsun/security/util/DerOutputStream;->putUTCTime(Ljava/util/Date;)V
+Lsun/security/util/DerOutputStream;->putUTF8String(Ljava/lang/String;)V
+Lsun/security/util/DerOutputStream;->write(BLsun/security/util/DerOutputStream;)V
+Lsun/security/util/DerOutputStream;->write(B[B)V
+Lsun/security/util/DerValue;-><init>(B[B)V
+Lsun/security/util/DerValue;-><init>(Ljava/io/InputStream;)V
+Lsun/security/util/DerValue;-><init>(Ljava/lang/String;)V
+Lsun/security/util/DerValue;-><init>([B)V
+Lsun/security/util/DerValue;-><init>([BII)V
+Lsun/security/util/DerValue;->buffer:Lsun/security/util/DerInputBuffer;
+Lsun/security/util/DerValue;->createTag(BZB)B
+Lsun/security/util/DerValue;->data:Lsun/security/util/DerInputStream;
+Lsun/security/util/DerValue;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/util/DerValue;->getAsString()Ljava/lang/String;
+Lsun/security/util/DerValue;->getBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerValue;->getBitString()[B
+Lsun/security/util/DerValue;->getData()Lsun/security/util/DerInputStream;
+Lsun/security/util/DerValue;->getDataBytes()[B
+Lsun/security/util/DerValue;->getOctetString()[B
+Lsun/security/util/DerValue;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/DerValue;->getPositiveBigInteger()Ljava/math/BigInteger;
+Lsun/security/util/DerValue;->getUnalignedBitString()Lsun/security/util/BitArray;
+Lsun/security/util/DerValue;->isConstructed()Z
+Lsun/security/util/DerValue;->isContextSpecific()Z
+Lsun/security/util/DerValue;->isContextSpecific(B)Z
+Lsun/security/util/DerValue;->isPrintableStringChar(C)Z
+Lsun/security/util/DerValue;->resetTag(B)V
+Lsun/security/util/DerValue;->tag:B
+Lsun/security/util/DerValue;->toByteArray()[B
+Lsun/security/util/DerValue;->toDerInputStream()Lsun/security/util/DerInputStream;
+Lsun/security/util/ManifestDigester$Entry;->digest(Ljava/security/MessageDigest;)[B
+Lsun/security/util/ManifestDigester$Entry;->digestWorkaround(Ljava/security/MessageDigest;)[B
+Lsun/security/util/ManifestDigester;-><init>([B)V
+Lsun/security/util/ManifestDigester;->get(Ljava/lang/String;Z)Lsun/security/util/ManifestDigester$Entry;
+Lsun/security/util/ManifestDigester;->manifestDigest(Ljava/security/MessageDigest;)[B
+Lsun/security/util/MemoryCache$HardCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;J)V
+Lsun/security/util/MemoryCache$SoftCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;JLjava/lang/ref/ReferenceQueue;)V
+Lsun/security/util/ObjectIdentifier;-><init>(Ljava/lang/String;)V
+Lsun/security/util/ObjectIdentifier;-><init>([I)V
+Lsun/security/util/ObjectIdentifier;->equals(Lsun/security/util/ObjectIdentifier;)Z
+Lsun/security/util/ObjectIdentifier;->newInternal([I)Lsun/security/util/ObjectIdentifier;
+Lsun/security/util/PropertyExpander;->expand(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/util/ResourcesMgr;->getString(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/util/SecurityConstants;->CREATE_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->GET_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->MODIFY_THREADGROUP_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SecurityConstants;->MODIFY_THREAD_PERMISSION:Ljava/lang/RuntimePermission;
+Lsun/security/util/SignatureFileVerifier;->isBlockOrSF(Ljava/lang/String;)Z
+Lsun/security/x509/AccessDescription;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/AccessDescription;->getAccessLocation()Lsun/security/x509/GeneralName;
+Lsun/security/x509/AccessDescription;->getAccessMethod()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;-><init>()V
+Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;)V
+Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/security/AlgorithmParameters;)V
+Lsun/security/x509/AlgorithmId;->derEncode(Ljava/io/OutputStream;)V
+Lsun/security/x509/AlgorithmId;->DSA_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->EC_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->encode()[B
+Lsun/security/x509/AlgorithmId;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/AlgorithmId;->equals(Lsun/security/x509/AlgorithmId;)Z
+Lsun/security/x509/AlgorithmId;->getAlgorithmId(Ljava/lang/String;)Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/AlgorithmId;->getDigAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/x509/AlgorithmId;->getEncAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String;
+Lsun/security/x509/AlgorithmId;->getEncodedParams()[B
+Lsun/security/x509/AlgorithmId;->getOID()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->getParameters()Ljava/security/AlgorithmParameters;
+Lsun/security/x509/AlgorithmId;->MD2_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->MD5_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->params:Lsun/security/util/DerValue;
+Lsun/security/x509/AlgorithmId;->parse(Lsun/security/util/DerValue;)Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/AlgorithmId;->RSAEncryption_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->sha1WithRSAEncryption_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA256_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA384_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA512_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AlgorithmId;->SHA_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AttributeNameEnumeration;-><init>()V
+Lsun/security/x509/AVA;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V
+Lsun/security/x509/AVA;->getDerValue()Lsun/security/util/DerValue;
+Lsun/security/x509/AVA;->getObjectIdentifier()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVA;->getValueString()Ljava/lang/String;
+Lsun/security/x509/AVA;->toRFC2253CanonicalString()Ljava/lang/String;
+Lsun/security/x509/AVAComparator;->INSTANCE:Ljava/util/Comparator;
+Lsun/security/x509/AVAKeyword;->getOID(Ljava/lang/String;ILjava/util/Map;)Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVAKeyword;->isCompliant(I)Z
+Lsun/security/x509/AVAKeyword;->keyword:Ljava/lang/String;
+Lsun/security/x509/AVAKeyword;->keywordMap:Ljava/util/Map;
+Lsun/security/x509/AVAKeyword;->oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/AVAKeyword;->oidMap:Ljava/util/Map;
+Lsun/security/x509/CertificateAlgorithmId;-><init>(Lsun/security/x509/AlgorithmId;)V
+Lsun/security/x509/CertificateExtensions;-><init>()V
+Lsun/security/x509/CertificateExtensions;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/CertificateExtensions;->encode(Ljava/io/OutputStream;Z)V
+Lsun/security/x509/CertificateExtensions;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/CertificateExtensions;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/x509/CertificateIssuerName;-><init>(Lsun/security/x509/X500Name;)V
+Lsun/security/x509/CertificateSerialNumber;-><init>(I)V
+Lsun/security/x509/CertificateSerialNumber;-><init>(Ljava/math/BigInteger;)V
+Lsun/security/x509/CertificateSubjectName;-><init>(Lsun/security/x509/X500Name;)V
+Lsun/security/x509/CertificateSubjectName;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/CertificateValidity;-><init>(Ljava/util/Date;Ljava/util/Date;)V
+Lsun/security/x509/CertificateVersion;-><init>(I)V
+Lsun/security/x509/CertificateX509Key;-><init>(Ljava/security/PublicKey;)V
+Lsun/security/x509/CRLDistributionPointsExtension;->encodeThis()V
+Lsun/security/x509/CRLNumberExtension;-><init>(Ljava/lang/Boolean;Ljava/lang/Object;)V
+Lsun/security/x509/CRLNumberExtension;->encodeThis()V
+Lsun/security/x509/CRLNumberExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/Extension;-><init>(Lsun/security/x509/Extension;)V
+Lsun/security/x509/Extension;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/Extension;->getExtensionId()Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/GeneralName;-><init>(Lsun/security/x509/GeneralNameInterface;)V
+Lsun/security/x509/GeneralName;->getName()Lsun/security/x509/GeneralNameInterface;
+Lsun/security/x509/GeneralName;->getType()I
+Lsun/security/x509/GeneralNames;-><init>()V
+Lsun/security/x509/GeneralNames;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/GeneralNames;->add(Lsun/security/x509/GeneralName;)Lsun/security/x509/GeneralNames;
+Lsun/security/x509/GeneralNames;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/GeneralNames;->isEmpty()Z
+Lsun/security/x509/KeyIdentifier;-><init>(Ljava/security/PublicKey;)V
+Lsun/security/x509/KeyIdentifier;->getIdentifier()[B
+Lsun/security/x509/KeyIdentifier;->octetString:[B
+Lsun/security/x509/KeyUsageExtension;-><init>([Z)V
+Lsun/security/x509/KeyUsageExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/NetscapeCertTypeExtension;-><init>([B)V
+Lsun/security/x509/NetscapeCertTypeExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/OIDMap$OIDInfo;->clazz:Ljava/lang/Class;
+Lsun/security/x509/OIDMap;->getClass(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Class;
+Lsun/security/x509/OIDMap;->nameMap:Ljava/util/Map;
+Lsun/security/x509/OIDMap;->oidMap:Ljava/util/Map;
+Lsun/security/x509/PKIXExtensions;->CertificateIssuer_Id:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/SerialNumber;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/SubjectAlternativeNameExtension;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/SubjectKeyIdentifierExtension;-><init>([B)V
+Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/UniqueIdentity;->encode(Lsun/security/util/DerOutputStream;B)V
+Lsun/security/x509/URIName;->getName()Ljava/lang/String;
+Lsun/security/x509/URIName;->getScheme()Ljava/lang/String;
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerInputStream;)V
+Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X500Name;-><init>([B)V
+Lsun/security/x509/X500Name;->allAvas()Ljava/util/List;
+Lsun/security/x509/X500Name;->asX500Name(Ljavax/security/auth/x500/X500Principal;)Lsun/security/x509/X500Name;
+Lsun/security/x509/X500Name;->asX500Principal()Ljavax/security/auth/x500/X500Principal;
+Lsun/security/x509/X500Name;->commonName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->countryName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->DNQUALIFIER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->DOMAIN_COMPONENT_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->encode(Lsun/security/util/DerOutputStream;)V
+Lsun/security/x509/X500Name;->GENERATIONQUALIFIER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->getCommonName()Ljava/lang/String;
+Lsun/security/x509/X500Name;->GIVENNAME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->INITIALS_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->ipAddress_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->isEmpty()Z
+Lsun/security/x509/X500Name;->localityName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->orgName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->orgUnitName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->SERIALNUMBER_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->stateName_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->streetAddress_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->SURNAME_OID:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->title_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X500Name;->userid_oid:Lsun/security/util/ObjectIdentifier;
+Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/x509/X509CertInfo;)V
+Lsun/security/x509/X509CertImpl;-><init>([B)V
+Lsun/security/x509/X509CertImpl;->algId:Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/X509CertImpl;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/X509CertImpl;->getEncodedInternal()[B
+Lsun/security/x509/X509CertImpl;->parse(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CertImpl;->readOnly:Z
+Lsun/security/x509/X509CertImpl;->sign(Ljava/security/PrivateKey;Ljava/lang/String;)V
+Lsun/security/x509/X509CertImpl;->signature:[B
+Lsun/security/x509/X509CertImpl;->signedCert:[B
+Lsun/security/x509/X509CertInfo;-><init>()V
+Lsun/security/x509/X509CertInfo;-><init>([B)V
+Lsun/security/x509/X509CertInfo;->get(Ljava/lang/String;)Ljava/lang/Object;
+Lsun/security/x509/X509CertInfo;->set(Ljava/lang/String;Ljava/lang/Object;)V
+Lsun/security/x509/X509CRLEntryImpl;->getExtension(Lsun/security/util/ObjectIdentifier;)Lsun/security/x509/Extension;
+Lsun/security/x509/X509CRLImpl;-><init>(Ljava/io/InputStream;)V
+Lsun/security/x509/X509CRLImpl;-><init>(Lsun/security/util/DerValue;)V
+Lsun/security/x509/X509CRLImpl;-><init>([B)V
+Lsun/security/x509/X509CRLImpl;->getEncodedInternal()[B
+Lsun/security/x509/X509Key;-><init>()V
+Lsun/security/x509/X509Key;->algid:Lsun/security/x509/AlgorithmId;
+Lsun/security/x509/X509Key;->encodedKey:[B
+Lsun/security/x509/X509Key;->key:[B
+Lsun/security/x509/X509Key;->parse(Lsun/security/util/DerValue;)Ljava/security/PublicKey;
+Lsun/security/x509/X509Key;->unusedBits:I
+Lsun/util/calendar/AbstractCalendar;->getDayOfWeekDateOnOrBefore(JI)J
+Lsun/util/calendar/AbstractCalendar;->getTimeOfDayValue(Lsun/util/calendar/CalendarDate;)J
+Lsun/util/calendar/BaseCalendar$Date;->getNormalizedYear()I
+Lsun/util/calendar/BaseCalendar$Date;->setNormalizedYear(I)V
+Lsun/util/calendar/CalendarDate;->getDayOfMonth()I
+Lsun/util/calendar/CalendarDate;->getMonth()I
+Lsun/util/calendar/CalendarDate;->getTimeOfDay()J
+Lsun/util/calendar/CalendarDate;->getYear()I
+Lsun/util/calendar/CalendarDate;->setDate(III)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setDayOfMonth(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setHours(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setMillis(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setMinutes(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarDate;->setSeconds(I)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarSystem;->forName(Ljava/lang/String;)Lsun/util/calendar/CalendarSystem;
+Lsun/util/calendar/CalendarSystem;->getGregorianCalendar()Lsun/util/calendar/Gregorian;
+Lsun/util/calendar/CalendarSystem;->getTime(Lsun/util/calendar/CalendarDate;)J
+Lsun/util/calendar/CalendarSystem;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/CalendarSystem;->validate(Lsun/util/calendar/CalendarDate;)Z
+Lsun/util/calendar/CalendarUtils;->floorDivide(II)I
+Lsun/util/calendar/CalendarUtils;->floorDivide(JJ)J
+Lsun/util/calendar/CalendarUtils;->mod(II)I
+Lsun/util/calendar/CalendarUtils;->mod(JJ)J
+Lsun/util/calendar/Era;-><init>(Ljava/lang/String;Ljava/lang/String;JZ)V
+Lsun/util/calendar/Era;->getAbbreviation()Ljava/lang/String;
+Lsun/util/calendar/Era;->getName()Ljava/lang/String;
+Lsun/util/calendar/Era;->getSinceDate()Lsun/util/calendar/CalendarDate;
+Lsun/util/calendar/ImmutableGregorianDate;->unsupported()V
+Lsun/util/calendar/LocalGregorianCalendar$Date;->getNormalizedYear()I
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setEra(Lsun/util/calendar/Era;)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setNormalizedYear(I)V
+Lsun/util/calendar/LocalGregorianCalendar$Date;->setYear(I)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/LocalGregorianCalendar$Date;
+Lsun/util/calendar/LocalGregorianCalendar;->normalize(Lsun/util/calendar/CalendarDate;)Z
+Lsun/util/calendar/LocalGregorianCalendar;->validate(Lsun/util/calendar/CalendarDate;)Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a666819..86ed267 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -120,6 +120,8 @@
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.autofill.AutofillPopupWindow;
import android.view.autofill.IAutofillWindowPresenter;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IntelligenceManager;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -821,6 +823,10 @@
/** The autofill manager. Always access via {@link #getAutofillManager()}. */
@Nullable private AutofillManager mAutofillManager;
+ /** The screen observation manager. Always access via {@link #getIntelligenceManager()}. */
+ @Nullable private IntelligenceManager mIntelligenceManager;
+
+
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
@@ -994,7 +1000,7 @@
}
/**
- * (Create and) return the autofill manager
+ * (Creates, sets and) returns the autofill manager
*
* @return The autofill manager
*/
@@ -1006,6 +1012,43 @@
return mAutofillManager;
}
+ /**
+ * (Creates, sets, and ) returns the intelligence manager
+ *
+ * @return The intelligence manager
+ */
+ @NonNull private IntelligenceManager getIntelligenceManager() {
+ if (mIntelligenceManager == null) {
+ mIntelligenceManager = getSystemService(IntelligenceManager.class);
+ }
+ return mIntelligenceManager;
+ }
+
+ private void notifyIntelligenceManagerIfNeeded(@ContentCaptureEvent.EventType int event) {
+ final IntelligenceManager im = getIntelligenceManager();
+ if (im == null || !im.isContentCaptureEnabled()) {
+ return;
+ }
+ switch (event) {
+ case ContentCaptureEvent.TYPE_ACTIVITY_CREATED:
+ //TODO(b/111276913): decide whether the InteractionSessionId should be
+ // saved / restored in the activity bundle.
+ im.onActivityCreated(mToken, getComponentName());
+ break;
+ case ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED:
+ im.onActivityDestroyed();
+ break;
+ case ContentCaptureEvent.TYPE_ACTIVITY_STARTED:
+ case ContentCaptureEvent.TYPE_ACTIVITY_RESUMED:
+ case ContentCaptureEvent.TYPE_ACTIVITY_PAUSED:
+ case ContentCaptureEvent.TYPE_ACTIVITY_STOPPED:
+ im.onActivityLifecycleEvent(event);
+ break;
+ default:
+ Log.w(TAG, "notifyIntelligenceManagerIfNeeded(): invalid type " + event);
+ }
+ }
+
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
@@ -1081,6 +1124,8 @@
}
mRestoredFromBundle = savedInstanceState != null;
mCalled = true;
+
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_CREATED);
}
/**
@@ -1314,6 +1359,7 @@
if (mAutoFillResetNeeded) {
getAutofillManager().onVisibleForAutofill();
}
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STARTED);
}
/**
@@ -1396,6 +1442,7 @@
}
}
}
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_RESUMED);
mCalled = true;
}
@@ -1789,6 +1836,7 @@
mAutoFillIgnoreFirstResumePause = false;
}
}
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_PAUSED);
mCalled = true;
}
@@ -1977,6 +2025,7 @@
getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL,
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STOPPED);
}
}
@@ -2047,6 +2096,9 @@
}
getApplication().dispatchActivityDestroyed(this);
+
+ notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED);
+
}
/**
@@ -6403,9 +6455,16 @@
void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
@NonNull PrintWriter writer, @Nullable String[] args) {
- if (args != null && args.length > 0 && args[0].equals("--autofill")) {
- dumpAutofillManager(prefix, writer);
- return;
+ if (args != null && args.length > 0) {
+ // Handle special cases
+ switch (args[0]) {
+ case "--autofill":
+ dumpAutofillManager(prefix, writer);
+ return;
+ case "--intelligence":
+ dumpIntelligenceManager(prefix, writer);
+ return;
+ }
}
writer.print(prefix); writer.print("Local Activity ");
writer.print(Integer.toHexString(System.identityHashCode(this)));
@@ -6435,6 +6494,7 @@
mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
dumpAutofillManager(prefix, writer);
+ dumpIntelligenceManager(prefix, writer);
ResourcesManager.getInstance().dump(prefix, writer);
}
@@ -6450,6 +6510,15 @@
}
}
+ void dumpIntelligenceManager(String prefix, PrintWriter writer) {
+ final IntelligenceManager im = getIntelligenceManager();
+ if (im != null) {
+ im.dump(prefix, writer);
+ } else {
+ writer.print(prefix); writer.println("No IntelligenceManager");
+ }
+ }
+
/**
* Bit indicating that this activity is "immersive" and should not be
* interrupted by notifications if possible.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7df8de0..1e2244e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1612,6 +1612,20 @@
}
/**
+ * Retrieve the default mode for the app op.
+ *
+ * @param appOp The app op name
+ *
+ * @return the default mode for the app op
+ *
+ * @hide
+ */
+ @SystemApi
+ public static int opToDefaultMode(@NonNull String appOp) {
+ return opToDefaultMode(strOpToOp(appOp));
+ }
+
+ /**
* Retrieve the human readable mode.
* @hide
*/
@@ -2483,26 +2497,6 @@
}
}
- /**
- * Resets given app op in its default mode for app ops in the UID.
- * This applies to all apps currently in the UID or installed in this UID in the future.
- *
- * @param appOp The app op.
- * @param uid The UID for which to set the app.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
- @SystemApi
- public void resetUidMode(String appOp, int uid, boolean force) {
- int code = strOpToOp(appOp);
- if (!(opAllowsReset(code) || force)) {
- return;
- }
- int mode = opToDefaultMode(code);
- setUidMode(code, uid, mode);
- }
-
/** @hide */
public void setUserRestriction(int code, boolean restricted, IBinder token) {
setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index f5d5e6e..7fe21b2 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.NonNull;
import android.util.SparseIntArray;
import com.android.internal.util.function.QuadFunction;
@@ -73,4 +74,21 @@
* access to app ops for their user.
*/
public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
+
+ /**
+ * Sets the app-ops mode for a certain app-op and uid.
+ *
+ * <p>Similar as {@link AppOpsManager#setMode} but does not require the package manager to be
+ * working. Hence this can be used very early during boot.
+ *
+ * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
+ *
+ * @param code The op code to set.
+ * @param uid The UID for which to set.
+ * @param packageName The package for which to set.
+ * @param mode The new mode to set.
+ * @param isPrivileged If the package is privileged
+ */
+ public abstract void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean isPrivileged);
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 519a274..e759762 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -265,17 +265,6 @@
void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo);
boolean killProcessesBelowForeground(in String reason);
UserInfo getCurrentUser();
- /**
- * Informs ActivityManagerService that the keyguard is showing.
- *
- * @param showingKeyguard True if the keyguard is showing, false otherwise.
- * @param showingAod True if AOD is showing, false otherwise.
- * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
- * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
- * showing is true.
- */
- void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
- int secondaryDisplayShowing);
// This is not public because you need to be very careful in how you
// manage your activity to make sure it is always the uid you expect.
int getLaunchedFromUid(in IBinder activityToken);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index fcfcc21..6f11a76 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -245,16 +245,16 @@
ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType);
/**
- * Informs ActivityManagerService that the keyguard is showing.
+ * Informs ActivityTaskManagerService that the keyguard is showing.
*
* @param showingKeyguard True if the keyguard is showing, false otherwise.
* @param showingAod True if AOD is showing, false otherwise.
- * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard
- * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if
- * showing is true.
+ * @param secondaryDisplaysShowing The displayId's of the secondary displays on which the
+ * keyguard is showing, or {@code null} if there is no such display. Only meaningful if showing
+ * is {@code true}.
*/
void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
- int secondaryDisplayShowing);
+ in int[] secondaryDisplaysShowing);
Bundle getAssistContextExtras(int requestType);
boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle,
in Bundle args);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f267169..e95f9ab 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -66,8 +66,8 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.input.InputManager;
-import android.hardware.iris.IrisManager;
import android.hardware.iris.IIrisService;
+import android.hardware.iris.IrisManager;
import android.hardware.location.ContextHubManager;
import android.hardware.radio.RadioManager;
import android.hardware.usb.IUsbManager;
@@ -163,6 +163,8 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.IAutoFillManager;
import android.view.inputmethod.InputMethodManager;
+import android.view.intelligence.IIntelligenceManager;
+import android.view.intelligence.IntelligenceManager;
import android.view.textclassifier.TextClassificationManager;
import android.view.textservice.TextServicesManager;
@@ -1032,6 +1034,17 @@
return new AutofillManager(ctx.getOuterContext(), service);
}});
+ registerService(Context.INTELLIGENCE_MANAGER_SERVICE, IntelligenceManager.class,
+ new CachedServiceFetcher<IntelligenceManager>() {
+ @Override
+ public IntelligenceManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ // Get the services without throwing as this is an optional feature
+ IBinder b = ServiceManager.getService(Context.INTELLIGENCE_MANAGER_SERVICE);
+ IIntelligenceManager service = IIntelligenceManager.Stub.asInterface(b);
+ return new IntelligenceManager(ctx.getOuterContext(), service);
+ }});
+
registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
@Override
public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 096c7aa..78b7d48 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
import static android.app.WindowConfigurationProto.APP_BOUNDS;
import static android.app.WindowConfigurationProto.WINDOWING_MODE;
+import static android.view.Surface.rotationToString;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -60,6 +61,17 @@
*/
private Rect mAppBounds;
+ /**
+ * The current rotation of this window container relative to the default
+ * orientation of the display it is on (regardless of how deep in the hierarchy
+ * it is). It is used by the configuration hierarchy to apply rotation-dependent
+ * policy during bounds calculation.
+ */
+ private int mRotation = ROTATION_UNDEFINED;
+
+ /** Rotation is not defined, use the parent containers rotation. */
+ public static final int ROTATION_UNDEFINED = -1;
+
/** The current windowing mode of the configuration. */
private @WindowingMode int mWindowingMode;
@@ -161,6 +173,9 @@
/** Bit that indicates that the {@link #mAlwaysOnTop} changed.
* @hide */
public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
+ /** Bit that indicates that the {@link #mRotation} changed.
+ * @hide */
+ public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
/** @hide */
@IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
WINDOW_CONFIG_BOUNDS,
@@ -168,6 +183,7 @@
WINDOW_CONFIG_WINDOWING_MODE,
WINDOW_CONFIG_ACTIVITY_TYPE,
WINDOW_CONFIG_ALWAYS_ON_TOP,
+ WINDOW_CONFIG_ROTATION,
})
public @interface WindowConfig {}
@@ -194,6 +210,7 @@
dest.writeInt(mWindowingMode);
dest.writeInt(mActivityType);
dest.writeInt(mAlwaysOnTop);
+ dest.writeInt(mRotation);
}
private void readFromParcel(Parcel source) {
@@ -202,6 +219,7 @@
mWindowingMode = source.readInt();
mActivityType = source.readInt();
mAlwaysOnTop = source.readInt();
+ mRotation = source.readInt();
}
@Override
@@ -287,6 +305,14 @@
return mBounds;
}
+ public int getRotation() {
+ return mRotation;
+ }
+
+ public void setRotation(int rotation) {
+ mRotation = rotation;
+ }
+
public void setWindowingMode(@WindowingMode int windowingMode) {
mWindowingMode = windowingMode;
}
@@ -324,6 +350,7 @@
setWindowingMode(other.mWindowingMode);
setActivityType(other.mActivityType);
setAlwaysOnTop(other.mAlwaysOnTop);
+ setRotation(other.mRotation);
}
/** Set this object to completely undefined.
@@ -339,6 +366,7 @@
setWindowingMode(WINDOWING_MODE_UNDEFINED);
setActivityType(ACTIVITY_TYPE_UNDEFINED);
setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
+ setRotation(ROTATION_UNDEFINED);
}
/**
@@ -375,6 +403,10 @@
changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
setAlwaysOnTop(delta.mAlwaysOnTop);
}
+ if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) {
+ changed |= WINDOW_CONFIG_ROTATION;
+ setRotation(delta.mRotation);
+ }
return changed;
}
@@ -418,6 +450,11 @@
changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
}
+ if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED)
+ && mRotation != other.mRotation) {
+ changes |= WINDOW_CONFIG_ROTATION;
+ }
+
return changes;
}
@@ -454,6 +491,8 @@
if (n != 0) return n;
n = mAlwaysOnTop - that.mAlwaysOnTop;
if (n != 0) return n;
+ n = mRotation - that.mRotation;
+ if (n != 0) return n;
// if (n != 0) return n;
return n;
@@ -482,6 +521,7 @@
result = 31 * result + mWindowingMode;
result = 31 * result + mActivityType;
result = 31 * result + mAlwaysOnTop;
+ result = 31 * result + mRotation;
return result;
}
@@ -493,6 +533,8 @@
+ " mWindowingMode=" + windowingModeToString(mWindowingMode)
+ " mActivityType=" + activityTypeToString(mActivityType)
+ " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
+ + " mRotation=" + (mRotation == ROTATION_UNDEFINED
+ ? "undefined" : rotationToString(mRotation))
+ "}";
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6a7829b..2aa32c4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3865,6 +3865,14 @@
public static final String AUTOFILL_MANAGER_SERVICE = "autofill";
/**
+ * Official published name of the intelligence service.
+ *
+ * @hide
+ * @see #getSystemService(String)
+ */
+ public static final String INTELLIGENCE_MANAGER_SERVICE = "intelligence";
+
+ /**
* Use with {@link #getSystemService(String)} to access the
* {@link com.android.server.voiceinteraction.SoundTriggerService}.
*
@@ -4219,6 +4227,15 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.os.ThermalService} for accessing the thermal service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String THERMAL_SERVICE = "thermalservice";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service.
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index d3652e8..877dfee 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -57,6 +57,9 @@
*
* <p>This callback will be run on your main thread.
*
+ * <p><em>Note: This callback will not be triggered when preferences are cleared via
+ * {@link Editor#clear()}.</em>
+ *
* @param sharedPreferences The {@link SharedPreferences} that received
* the change.
* @param key The key of the preference that was changed, added, or
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 8fddb99..cef21f6 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -38,4 +38,9 @@
void commit(in IntentSender statusReceiver, boolean forTransferred);
void transfer(in String packageName);
void abandon();
+ boolean isMultiPackage();
+ int[] getChildSessionIds();
+ void addChildSessionId(in int sessionId);
+ void removeChildSessionId(in int sessionId);
+ int getParentSessionId();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e9cfa78..8f90199 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -365,12 +365,14 @@
*/
public @NonNull Session openSession(int sessionId) throws IOException {
try {
- return new Session(mInstaller.openSession(sessionId));
+ try {
+ return new Session(mInstaller.openSession(sessionId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} catch (RuntimeException e) {
ExceptionUtils.maybeUnwrapIOException(e);
throw e;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
}
}
@@ -769,9 +771,18 @@
* If an APK included in this session is already defined by the existing
* installation (for example, the same split name), the APK in this session
* will replace the existing APK.
+ * <p>
+ * In such a case that multiple packages need to be commited simultaneously,
+ * multiple sessions can be referenced by a single multi-package session.
+ * This session is created with no package name and calling
+ * {@link SessionParams#setMultiPackage()} with {@code true}. The
+ * individual session IDs can be added with {@link #addChildSessionId(int)}
+ * and commit of the multi-package session will result in all child sessions
+ * being committed atomically.
*/
public static class Session implements Closeable {
- private IPackageInstallerSession mSession;
+ /** {@hide} */
+ protected final IPackageInstallerSession mSession;
/** {@hide} */
public Session(IPackageInstallerSession session) {
@@ -1080,6 +1091,71 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * @return {@code true} if this session will commit more than one package when it is
+ * committed.
+ */
+ public boolean isMultiPackage() {
+ try {
+ return mSession.isMultiPackage();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the session ID of the multi-package session that this belongs to or
+ * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session.
+ */
+ public int getParentSessionId() {
+ try {
+ return mSession.getParentSessionId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the set of session IDs that will be committed atomically when this session is
+ * committed if this is a multi-package session or null if none exist.
+ */
+ @NonNull
+ public int[] getChildSessionIds() {
+ try {
+ return mSession.getChildSessionIds();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adds a session ID to the set of sessions that will be committed atomically
+ * when this session is committed.
+ *
+ * @param sessionId the session ID to add to this multi-package session.
+ */
+ public void addChildSessionId(int sessionId) {
+ try {
+ mSession.addChildSessionId(sessionId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes a session ID from the set of sessions that will be committed
+ * atomically when this session is committed.
+ *
+ * @param sessionId the session ID to remove from this multi-package session.
+ */
+ public void removeChildSessionId(int sessionId) {
+ try {
+ mSession.removeChildSessionId(sessionId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -1149,6 +1225,8 @@
public String[] grantedRuntimePermissions;
/** {@hide} */
public String installerPackageName;
+ /** {@hide} */
+ public boolean isMultiPackage;
/**
* Construct parameters for a new package install session.
@@ -1178,6 +1256,7 @@
volumeUuid = source.readString();
grantedRuntimePermissions = source.readStringArray();
installerPackageName = source.readString();
+ isMultiPackage = source.readBoolean();
}
/**
@@ -1392,6 +1471,18 @@
this.installerPackageName = installerPackageName;
}
+ /**
+ * Set this session to be the parent of a multi-package install.
+ *
+ * A multi-package install session contains no APKs and only references other install
+ * sessions via ID. When a multi-package session is committed, all of its children
+ * are committed to the system in an atomic manner. If any children fail to install,
+ * all of them do, including the multi-package session.
+ */
+ public void setMultiPackage() {
+ this.isMultiPackage = true;
+ }
+
/** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
@@ -1408,6 +1499,7 @@
pw.printPair("volumeUuid", volumeUuid);
pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
pw.printPair("installerPackageName", installerPackageName);
+ pw.printPair("isMultiPackage", isMultiPackage);
pw.println();
}
@@ -1433,6 +1525,7 @@
dest.writeString(volumeUuid);
dest.writeStringArray(grantedRuntimePermissions);
dest.writeString(installerPackageName);
+ dest.writeBoolean(isMultiPackage);
}
public static final Parcelable.Creator<SessionParams>
@@ -1454,6 +1547,12 @@
*/
public static class SessionInfo implements Parcelable {
+ /**
+ * A session ID that does not exist or is invalid.
+ */
+ public static final int INVALID_ID = -1;
+ /** {@hide} */
+ private static final int[] NO_SESSIONS = {};
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int sessionId;
@@ -1503,6 +1602,12 @@
public String[] grantedRuntimePermissions;
/** {@hide} */
public int installFlags;
+ /** {@hide} */
+ public boolean isMultiPackage;
+ /** {@hide} */
+ public int parentSessionId = INVALID_ID;
+ /** {@hide} */
+ public int[] childSessionIds = NO_SESSIONS;
/** {@hide} */
@UnsupportedAppUsage
@@ -1531,6 +1636,12 @@
referrerUri = source.readParcelable(null);
grantedRuntimePermissions = source.readStringArray();
installFlags = source.readInt();
+ isMultiPackage = source.readBoolean();
+ parentSessionId = source.readInt();
+ childSessionIds = source.createIntArray();
+ if (childSessionIds == null) {
+ childSessionIds = NO_SESSIONS;
+ }
}
/**
@@ -1784,6 +1895,30 @@
return createDetailsIntent();
}
+ /**
+ * Returns true if this session is a multi-package session containing references to other
+ * sessions.
+ */
+ public boolean isMultiPackage() {
+ return isMultiPackage;
+ }
+
+ /**
+ * Returns the parent multi-package session ID if this session belongs to one,
+ * {@link #INVALID_ID} otherwise.
+ */
+ public int getParentSessionId() {
+ return parentSessionId;
+ }
+
+ /**
+ * Returns the set of session IDs that will be committed when this session is commited if
+ * this session is a multi-package session.
+ */
+ public int[] getChildSessionIds() {
+ return childSessionIds;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -1811,6 +1946,9 @@
dest.writeParcelable(referrerUri, flags);
dest.writeStringArray(grantedRuntimePermissions);
dest.writeInt(installFlags);
+ dest.writeBoolean(isMultiPackage);
+ dest.writeInt(parentSessionId);
+ dest.writeIntArray(childSessionIds);
}
public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1f700f7..c1ac061 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -855,6 +855,14 @@
*/
public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that this package
+ * is an APEX package
+ *
+ * @hide
+ */
+ public static final int INSTALL_APEX = 0x00020000;
+
/** @hide */
@IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
DONT_KILL_APP
@@ -907,6 +915,11 @@
public static final int INSTALL_REASON_USER = 4;
/**
+ * @hide
+ */
+ public static final int INSTALL_UNKNOWN = 0;
+
+ /**
* Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
* on success.
*
@@ -2935,6 +2948,15 @@
public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6;
/**
+ * Permission flag: The permission has not been explicitly requested by
+ * the app but has been added automatically by the system. Revoke once
+ * the app does explicitly request it.
+ *
+ * @hide
+ */
+ public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7;
+
+ /**
* Mask for all permission flags.
*
* @hide
@@ -3585,7 +3607,10 @@
FLAG_PERMISSION_POLICY_FIXED,
FLAG_PERMISSION_REVOKE_ON_UPGRADE,
FLAG_PERMISSION_SYSTEM_FIXED,
- FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ FLAG_PERMISSION_GRANTED_BY_DEFAULT,
+ /*
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESED
+ */
})
@Retention(RetentionPolicy.SOURCE)
public @interface PermissionFlags {}
@@ -6125,6 +6150,7 @@
case FLAG_PERMISSION_REVOKE_ON_UPGRADE: return "REVOKE_ON_UPGRADE";
case FLAG_PERMISSION_USER_FIXED: return "USER_FIXED";
case FLAG_PERMISSION_REVIEW_REQUIRED: return "REVIEW_REQUIRED";
+ case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
default: return Integer.toString(flag);
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index dc33bde..7ef5264 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2435,7 +2435,7 @@
}
final int NP = PackageParser.NEW_PERMISSIONS.length;
- StringBuilder implicitPerms = null;
+ StringBuilder newPermsMsg = null;
for (int ip=0; ip<NP; ip++) {
final PackageParser.NewPermissionInfo npi
= PackageParser.NEW_PERMISSIONS[ip];
@@ -2443,19 +2443,20 @@
break;
}
if (!pkg.requestedPermissions.contains(npi.name)) {
- if (implicitPerms == null) {
- implicitPerms = new StringBuilder(128);
- implicitPerms.append(pkg.packageName);
- implicitPerms.append(": compat added ");
+ if (newPermsMsg == null) {
+ newPermsMsg = new StringBuilder(128);
+ newPermsMsg.append(pkg.packageName);
+ newPermsMsg.append(": compat added ");
} else {
- implicitPerms.append(' ');
+ newPermsMsg.append(' ');
}
- implicitPerms.append(npi.name);
+ newPermsMsg.append(npi.name);
pkg.requestedPermissions.add(npi.name);
+ pkg.implicitPermissions.add(npi.name);
}
}
- if (implicitPerms != null) {
- Slog.i(TAG, implicitPerms.toString());
+ if (newPermsMsg != null) {
+ Slog.i(TAG, newPermsMsg.toString());
}
@@ -2472,6 +2473,7 @@
final String perm = newPerms.get(in);
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
+ pkg.implicitPermissions.add(perm);
}
}
}
@@ -6394,6 +6396,9 @@
@UnsupportedAppUsage
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
+ /** Permissions requested but not in the manifest. */
+ public final ArrayList<String> implicitPermissions = new ArrayList<>();
+
@UnsupportedAppUsage
public ArrayList<String> protectedBroadcasts;
@@ -6923,6 +6928,8 @@
dest.readStringList(requestedPermissions);
internStringArrayList(requestedPermissions);
+ dest.readStringList(implicitPermissions);
+ internStringArrayList(implicitPermissions);
protectedBroadcasts = dest.createStringArrayList();
internStringArrayList(protectedBroadcasts);
@@ -7087,6 +7094,7 @@
dest.writeParcelableList(instrumentation, flags);
dest.writeStringList(requestedPermissions);
+ dest.writeStringList(implicitPermissions);
dest.writeStringList(protectedBroadcasts);
// TODO: This doesn't work: b/64295061
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index a8bbeab0..096301c 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -25,6 +25,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -78,6 +79,7 @@
private final @Type int mType;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
+ private List<SharedLibraryInfo> mDependencies;
/**
* Creates a new instance.
@@ -91,7 +93,8 @@
* @hide
*/
public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
- VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
+ VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+ List<SharedLibraryInfo> dependencies) {
mPath = path;
mPackageName = packageName;
mName = name;
@@ -99,11 +102,13 @@
mType = type;
mDeclaringPackage = declaringPackage;
mDependentPackages = dependentPackages;
+ mDependencies = dependencies;
}
private SharedLibraryInfo(Parcel parcel) {
this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
- parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null));
+ parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
+ parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
}
/**
@@ -150,6 +155,47 @@
}
/**
+ * Add a library dependency to that library. Note that this
+ * should be called under the package manager lock.
+ *
+ * @hide
+ */
+ public void addDependency(@Nullable SharedLibraryInfo info) {
+ if (info == null) {
+ // For convenience of the caller, allow null to be passed.
+ // This can happen when we create the dependencies of builtin
+ // libraries.
+ return;
+ }
+ if (mDependencies == null) {
+ mDependencies = new ArrayList<>();
+ }
+ mDependencies.add(info);
+ }
+
+ /**
+ * Clear all dependencies.
+ *
+ * @hide
+ */
+ public void clearDependencies() {
+ mDependencies = null;
+ }
+
+ /**
+ * Gets the libraries this library directly depends on. Note that
+ * the package manager prevents recursive dependencies when installing
+ * a package.
+ *
+ * @return The dependencies.
+ *
+ * @hide
+ */
+ public @Nullable List<SharedLibraryInfo> getDependencies() {
+ return mDependencies;
+ }
+
+ /**
* @deprecated Use {@link #getLongVersion()} instead.
*/
@Deprecated
@@ -232,6 +278,7 @@
parcel.writeInt(mType);
parcel.writeParcelable(mDeclaringPackage, flags);
parcel.writeList(mDependentPackages);
+ parcel.writeTypedList(mDependencies);
}
private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 387d29e8..5afc8a9 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,15 +22,15 @@
*/
public class SharedLibraryNames {
- static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+ public static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
- static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+ public static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
- static final String ANDROID_TEST_BASE = "android.test.base";
+ public static final String ANDROID_TEST_BASE = "android.test.base";
- static final String ANDROID_TEST_MOCK = "android.test.mock";
+ public static final String ANDROID_TEST_MOCK = "android.test.mock";
- static final String ANDROID_TEST_RUNNER = "android.test.runner";
+ public static final String ANDROID_TEST_RUNNER = "android.test.runner";
- static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+ public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 46e66e0..444ca87 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -22,12 +22,14 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.util.Rational;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -193,6 +195,7 @@
private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
private List<CaptureResult.Key<?>> mAvailableResultKeys;
+ private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations;
/**
* Takes ownership of the passed-in properties object
@@ -313,6 +316,103 @@
}
/**
+ * <p>Retrieve camera device recommended stream configuration map
+ * {@link RecommendedStreamConfigurationMap} for a given use case.</p>
+ *
+ * <p>The stream configurations advertised here are efficient in terms of power and performance
+ * for common use cases like preview, video, snapshot, etc. The recommended maps are usually
+ * only small subsets of the exhaustive list provided in
+ * {@link #SCALER_STREAM_CONFIGURATION_MAP} and suggested for a particular use case by the
+ * camera device implementation. For further information about the expected configurations in
+ * various scenarios please refer to:
+ * <ul>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_PREVIEW}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_RECORD}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_VIDEO_SNAPSHOT}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>For example on how this can be used by camera clients to find out the maximum recommended
+ * preview and snapshot resolution, consider the following pseudo-code:
+ * </p>
+ * <pre><code>
+ * public static Size getMaxSize(Size... sizes) {
+ * if (sizes == null || sizes.length == 0) {
+ * throw new IllegalArgumentException("sizes was empty");
+ * }
+ *
+ * Size sz = sizes[0];
+ * for (Size size : sizes) {
+ * if (size.getWidth() * size.getHeight() > sz.getWidth() * sz.getHeight()) {
+ * sz = size;
+ * }
+ * }
+ *
+ * return sz;
+ * }
+ *
+ * CameraCharacteristics characteristics =
+ * cameraManager.getCameraCharacteristics(cameraId);
+ * RecommendedStreamConfigurationMap previewConfig =
+ * characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+ * RecommendedStreamConfigurationMap snapshotConfig =
+ * characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_SNAPSHOT);
+ *
+ * if ((previewConfig != null) && (snapshotConfig != null)) {
+ *
+ * Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes(
+ * ImageFormat.JPEG);
+ * Size[] snapshotSizes = new Size[snapshotSizeSet.size()];
+ * snapshotSizes = snapshotSizeSet.toArray(snapshotSizes);
+ * Size suggestedMaxJpegSize = getMaxSize(snapshotSizes);
+ *
+ * Set<Size> previewSizeSet = snapshotConfig.getOutputSizes(
+ * ImageFormat.PRIVATE);
+ * Size[] previewSizes = new Size[previewSizeSet.size()];
+ * previewSizes = previewSizeSet.toArray(previewSizes);
+ * Size suggestedMaxPreviewSize = getMaxSize(previewSizes);
+ * }
+ *
+ * </code></pre>
+ *
+ * <p>Similar logic can be used for other use cases as well.</p>
+ *
+ * <p>Support for recommended stream configurations is optional. In case there a no
+ * suggested configurations for the particular use case, please refer to
+ * {@link #SCALER_STREAM_CONFIGURATION_MAP} for the exhaustive available list.</p>
+ *
+ * @param usecase Use case id.
+ *
+ * @throws IllegalArgumentException In case the use case argument is invalid.
+ * @return Valid {@link RecommendedStreamConfigurationMap} or null in case the camera device
+ * doesn't have any recommendation for this use case or the recommended configurations
+ * are invalid.
+ */
+ public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
+ @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
+ if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
+ (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
+ ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
+ (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
+ if (mRecommendedConfigurations == null) {
+ mRecommendedConfigurations = mProperties.getRecommendedStreamConfigurations();
+ if (mRecommendedConfigurations == null) {
+ return null;
+ }
+ }
+
+ return mRecommendedConfigurations.get(usecase);
+ }
+
+ throw new IllegalArgumentException(String.format("Invalid use case: %d", usecase));
+ }
+
+ /**
* <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
* camera device can pass as part of the capture session initialization.</p>
*
@@ -329,7 +429,7 @@
* but clients should be aware and expect delays during their application.
* An example usage scenario could look like this:</p>
* <ul>
- * <li>The camera client starts by quering the session parameter key list via
+ * <li>The camera client starts by querying the session parameter key list via
* {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</li>
* <li>Before triggering the capture session create sequence, a capture request
* must be built via {@link CameraDevice#createCaptureRequest } using an
@@ -1583,7 +1683,7 @@
* {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
* <li>Processed (but not-stalling): any non-RAW format without a stall duration. Typically
* {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
- * {@link android.graphics.ImageFormat#NV21 NV21}, or {@link android.graphics.ImageFormat#YV12 YV12}.</li>
+ * {@link android.graphics.ImageFormat#NV21 NV21}, {@link android.graphics.ImageFormat#YV12 YV12}, or {@link android.graphics.ImageFormat#Y8 Y8} .</li>
* </ul>
* <p><b>Range of valid values:</b><br></p>
* <p>For processed (and stalling) format streams, >= 1.</p>
@@ -1646,6 +1746,7 @@
* <li>{@link android.graphics.ImageFormat#NV21 NV21}</li>
* <li>{@link android.graphics.ImageFormat#YV12 YV12}</li>
* <li>Implementation-defined formats, i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#isOutputSupportedFor(Class) }</li>
+ * <li>{@link android.graphics.ImageFormat#Y8 Y8}</li>
* </ul>
* <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
* processed format -- it will return 0 for a non-stalling stream.</p>
@@ -2122,6 +2223,35 @@
* or output will never hurt maximum frame rate (i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration getOutputStallDuration(ImageFormat.PRIVATE, size)} is always 0),</p>
* <p>Attempting to configure an input stream with output streams not
* listed as available in this map is not valid.</p>
+ * <p>Additionally, if the camera device is MONOCHROME with Y8 support, it will also support
+ * the following map of formats if its dependent capability
+ * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}) is supported:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="left">Input Format</th>
+ * <th align="left">Output Format</th>
+ * <th align="left">Capability</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
+ * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td align="left">PRIVATE_REPROCESSING</td>
+ * </tr>
+ * <tr>
+ * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td align="left">YUV_REPROCESSING</td>
+ * </tr>
+ * <tr>
+ * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td align="left">YUV_REPROCESSING</td>
+ * </tr>
+ * </tbody>
+ * </table>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -2297,6 +2427,7 @@
* <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li>
* <li>{@link android.graphics.ImageFormat#RAW10 }</li>
* <li>{@link android.graphics.ImageFormat#RAW12 }</li>
+ * <li>{@link android.graphics.ImageFormat#Y8 }</li>
* </ul>
* <p>All other formats may or may not have an allowed stall duration on
* a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
@@ -2447,6 +2578,37 @@
new Key<Integer>("android.scaler.croppingType", int.class);
/**
+ * <p>Recommended stream configurations for common client use cases.</p>
+ * <p>Optional subset of the android.scaler.availableStreamConfigurations that contains
+ * similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.scaler.availableRecommendedStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+ /**
+ * <p>Recommended mappings of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ * <p>This is a recommended subset of the complete list of mappings found in
+ * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well.
+ * The list however doesn't need to contain all available and supported mappings. Instead of
+ * this developers must list only recommended and efficient entries.
+ * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream
+ * configuration see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP =
+ new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class);
+
+ /**
* <p>The area of the image sensor which corresponds to active pixels after any geometric
* distortion correction has been applied.</p>
* <p>This is the rectangle representing the size of the active region of the sensor (i.e.
@@ -3487,6 +3649,21 @@
new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
/**
+ * <p>Recommended depth stream configurations for common client use cases.</p>
+ * <p>Optional subset of the android.depth.availableDepthStreamConfigurations that
+ * contains similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular depth stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+ /**
* <p>String containing the ids of the underlying physical cameras.</p>
* <p>For a logical camera, this is concatenation of all underlying physical camera ids.
* The null terminator for physical camera id must be preserved so that the whole string
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ce88697..ac00f14 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -356,6 +356,12 @@
* </table><br>
* </p>
*
+ * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
+ * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME})
+ * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
+ * streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
+ * and capabilities.</p>
+ *
* <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
* support at least the following stream combinations in addition to those for
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index d4dc181..ffc2264 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -539,6 +539,8 @@
* <li>{@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into both
* {@link android.graphics.ImageFormat#YUV_420_888 } and
* {@link android.graphics.ImageFormat#JPEG } formats.</li>
+ * <li>For a MONOCHROME camera supporting Y8 format, {@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into
+ * {@link android.graphics.ImageFormat#Y8 }.</li>
* <li>The maximum available resolution for PRIVATE streams
* (both input/output) will match the maximum available
* resolution of JPEG streams.</li>
@@ -612,7 +614,7 @@
* then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at
* least one resolution >= 8 megapixels, with a minimum frame duration of <= 1/20
* s.</p>
- * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be
+ * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, {@link android.graphics.ImageFormat#Y8 }, then those can also be
* captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
* <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees
* as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p>
@@ -646,6 +648,8 @@
* {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li>
* <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the
* maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li>
+ * <li>For a MONOCHROME camera with Y8 format support, all the requirements mentioned
+ * above for YUV_420_888 apply for Y8 format as well.</li>
* <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
* <li>Only the below controls are effective for reprocessing requests and will be present
* in capture results. The reprocess requests are from the original capture results
@@ -692,8 +696,8 @@
* <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
* <li>As of Android P, the {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} entry is listed by this device.</li>
* <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
- * normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
- * format.</li>
+ * normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the
+ * DEPTH16 format.</li>
* </ul>
* <p>Generally, depth output operates at a slower frame rate than standard color capture,
* so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
@@ -877,6 +881,10 @@
/**
* <p>The camera device is a monochrome camera that doesn't contain a color filter array,
* and the pixel values on U and V planes are all 128.</p>
+ * <p>A MONOCHROME camera must support the guaranteed stream combinations required for
+ * its device level and capabilities. Additionally, if the monochrome camera device
+ * supports Y8 format, all mandatory stream combination requirements related to {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888} apply
+ * to {@link android.graphics.ImageFormat#Y8 Y8} as well.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 4a20468..2744e91 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3277,8 +3277,8 @@
* will not slow down capture rate when applying correction. FAST may be the same as OFF if
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
- * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output.</p>
+ * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+ * not applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index a7e185c..2b67f3e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4620,8 +4620,8 @@
* will not slow down capture rate when applying correction. FAST may be the same as OFF if
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
- * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output.</p>
+ * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is
+ * not applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0610d7a..f81bd13 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -21,6 +21,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.marshal.MarshalQueryable;
@@ -38,6 +39,7 @@
import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration;
import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
@@ -50,6 +52,8 @@
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
import android.hardware.camera2.params.OisSample;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.ReprocessFormatsMap;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
@@ -911,6 +915,252 @@
return true;
}
+ private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations,
+ StreamConfigurationMap fullMap, boolean isDepth,
+ ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList,
+ ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList,
+ ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList,
+ boolean[] /*out*/supportsPrivate) {
+
+ streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ streamConfigList.add(new ArrayList<StreamConfiguration> ());
+ streamDurationList.add(new ArrayList<StreamConfigurationDuration> ());
+ streamStallList.add(new ArrayList<StreamConfigurationDuration> ());
+ }
+
+ for (RecommendedStreamConfiguration c : configurations) {
+ int width = c.getWidth();
+ int height = c.getHeight();
+ int internalFormat = c.getFormat();
+ int publicFormat =
+ (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) :
+ StreamConfigurationMap.imageFormatToPublic(internalFormat);
+ Size sz = new Size(width, height);
+ int usecaseBitmap = c.getUsecaseBitmap();
+
+ if (!c.isInput()) {
+ StreamConfigurationDuration minDurationConfiguration = null;
+ StreamConfigurationDuration stallDurationConfiguration = null;
+
+ StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat,
+ width, height, /*input*/ false);
+
+ long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz);
+ if (minFrameDuration > 0) {
+ minDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+ width, height, minFrameDuration);
+ }
+
+ long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz);
+ if (stallDuration > 0) {
+ stallDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+ width, height, stallDuration);
+ }
+
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ if ((usecaseBitmap & (1 << i)) != 0) {
+ ArrayList<StreamConfiguration> sc = streamConfigList.get(i);
+ sc.add(streamConfiguration);
+
+ if (minFrameDuration > 0) {
+ ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i);
+ scd.add(minDurationConfiguration);
+ }
+
+ if (stallDuration > 0) {
+ ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i);
+ scs.add(stallDurationConfiguration);
+ }
+
+ if ((supportsPrivate != null) && !supportsPrivate[i] &&
+ (publicFormat == ImageFormat.PRIVATE)) {
+ supportsPrivate[i] = true;
+ }
+ }
+ }
+ } else {
+ if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) {
+ throw new IllegalArgumentException("Recommended input stream configurations " +
+ "should only be advertised in the ZSL use case!");
+ }
+
+ ArrayList<StreamConfiguration> sc = streamConfigList.get(
+ RecommendedStreamConfigurationMap.USECASE_ZSL);
+ sc.add(new StreamConfiguration(internalFormat,
+ width, height, /*input*/ true));
+ }
+ }
+ }
+
+ private class StreamConfigurationData {
+ StreamConfiguration [] streamConfigurationArray = null;
+ StreamConfigurationDuration [] minDurationArray = null;
+ StreamConfigurationDuration [] stallDurationArray = null;
+ }
+
+ public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc,
+ ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs,
+ StreamConfigurationData /*out*/scData) {
+ if ((scData == null) || (sc == null)) {
+ return;
+ }
+
+ scData.streamConfigurationArray = new StreamConfiguration[sc.size()];
+ scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray);
+
+ if ((scd != null) && !scd.isEmpty()) {
+ scData.minDurationArray = new StreamConfigurationDuration[scd.size()];
+ scData.minDurationArray = scd.toArray(scData.minDurationArray);
+ } else {
+ scData.minDurationArray = new StreamConfigurationDuration[0];
+ }
+
+ if ((scs != null) && !scs.isEmpty()) {
+ scData.stallDurationArray = new StreamConfigurationDuration[scs.size()];
+ scData.stallDurationArray = scs.toArray(scData.stallDurationArray);
+ } else {
+ scData.stallDurationArray = new StreamConfigurationDuration[0];
+ }
+ }
+
+ /**
+ * Retrieve the list of recommended stream configurations.
+ *
+ * @return A list of recommended stream configuration maps for each common use case or null
+ * in case the recommended stream configurations are invalid or incomplete.
+ * @hide
+ */
+ public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() {
+ RecommendedStreamConfiguration[] configurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS);
+ RecommendedStreamConfiguration[] depthConfigurations = getBase(
+ CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS);
+ if ((configurations == null) && (depthConfigurations == null)) {
+ return null;
+ }
+
+ StreamConfigurationMap fullMap = getStreamConfigurationMap();
+ ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations =
+ new ArrayList<RecommendedStreamConfigurationMap> ();
+
+ ArrayList<ArrayList<StreamConfiguration>> streamConfigList =
+ new ArrayList<ArrayList<StreamConfiguration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ boolean[] supportsPrivate =
+ new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT];
+ try {
+ if (configurations != null) {
+ parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false,
+ streamConfigList, streamDurationList, streamStallList, supportsPrivate);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed parsing the recommended stream configurations!");
+ return null;
+ }
+
+ ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList =
+ new ArrayList<ArrayList<StreamConfiguration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ if (depthConfigurations != null) {
+ try {
+ parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true,
+ depthStreamConfigList, depthStreamDurationList, depthStreamStallList,
+ /*supportsPrivate*/ null);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed parsing the recommended depth stream configurations!");
+ return null;
+ }
+ }
+
+ ReprocessFormatsMap inputOutputFormatsMap = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP);
+ HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
+ CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+ boolean listHighResolution = isBurstSupported();
+ recommendedConfigurations.ensureCapacity(
+ RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ StreamConfigurationData scData = new StreamConfigurationData();
+ if (configurations != null) {
+ initializeStreamConfigurationData(streamConfigList.get(i),
+ streamDurationList.get(i), streamStallList.get(i), scData);
+ }
+
+ StreamConfigurationData depthScData = new StreamConfigurationData();
+ if (depthConfigurations != null) {
+ initializeStreamConfigurationData(depthStreamConfigList.get(i),
+ depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
+ }
+
+ if ((scData.streamConfigurationArray == null) &&
+ (depthScData.streamConfigurationArray == null)) {
+ recommendedConfigurations.add(null);
+ continue;
+ }
+
+ StreamConfigurationMap map = null;
+ switch (i) {
+ case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
+ case RecommendedStreamConfigurationMap.USECASE_RAW:
+ case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ /*depthconfiguration*/ null, /*depthminduration*/ null,
+ /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null,
+ /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+ break;
+ case RecommendedStreamConfigurationMap.USECASE_RECORD:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ /*depthconfiguration*/ null, /*depthminduration*/ null,
+ /*depthstallduration*/ null, highSpeedVideoConfigurations,
+ /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+ break;
+ case RecommendedStreamConfigurationMap.USECASE_ZSL:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ depthScData.streamConfigurationArray, depthScData.minDurationArray,
+ depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+ inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
+ break;
+ default:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ depthScData.streamConfigurationArray, depthScData.minDurationArray,
+ depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+ /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
+ }
+
+ recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i,
+ supportsPrivate[i]));
+ }
+
+ return recommendedConfigurations;
+ }
+
+ private boolean isBurstSupported() {
+ boolean ret = false;
+
+ int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ for (int capability : capabilities) {
+ if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+ }
+
private StreamConfigurationMap getStreamConfigurationMap() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -928,14 +1178,7 @@
CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
ReprocessFormatsMap inputOutputFormatsMap = getBase(
CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
- int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
- boolean listHighResolution = false;
- for (int capability : capabilities) {
- if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
- listHighResolution = true;
- break;
- }
- }
+ boolean listHighResolution = isBurstSupported();
return new StreamConfigurationMap(
configurations, minFrameDurations, stallDurations,
depthConfigurations, depthMinFrameDurations, depthStallDurations,
@@ -1399,6 +1642,7 @@
new MarshalQueryableRggbChannelVector(),
new MarshalQueryableBlackLevelPattern(),
new MarshalQueryableHighSpeedVideoConfiguration(),
+ new MarshalQueryableRecommendedStreamConfiguration(),
// generic parcelable marshaler (MUST BE LAST since it has lowest priority)
new MarshalQueryableParcelable(),
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
new file mode 100644
index 0000000..22a76b7
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableRecommendedStreamConfigurations} custom class
+ * {@link RecommendedStreamConfiguration}
+ *
+ * <p>Data is stored as {@code (width, height, format, input, usecaseBitmap)} tuples (int32).</p>
+ */
+public class MarshalQueryableRecommendedStreamConfiguration
+ implements MarshalQueryable<RecommendedStreamConfiguration> {
+ private static final int SIZE = SIZEOF_INT32 * 5;
+
+ private class MarshalerRecommendedStreamConfiguration
+ extends Marshaler<RecommendedStreamConfiguration> {
+ protected MarshalerRecommendedStreamConfiguration(
+ TypeReference<RecommendedStreamConfiguration> typeReference, int nativeType) {
+ super(MarshalQueryableRecommendedStreamConfiguration.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(RecommendedStreamConfiguration value, ByteBuffer buffer) {
+ buffer.putInt(value.getWidth());
+ buffer.putInt(value.getHeight());
+ buffer.putInt(value.getFormat());
+ buffer.putInt(value.isInput() ? 1 : 0);
+ buffer.putInt(value.getUsecaseBitmap());
+ }
+
+ @Override
+ public RecommendedStreamConfiguration unmarshal(ByteBuffer buffer) {
+ int width = buffer.getInt();
+ int height = buffer.getInt();
+ int format = buffer.getInt();
+ boolean input = buffer.getInt() != 0;
+ int usecaseBitmap = buffer.getInt();
+
+ return new RecommendedStreamConfiguration(format, width, height, input, usecaseBitmap);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+
+ }
+
+ @Override
+ public Marshaler<RecommendedStreamConfiguration> createMarshaler(
+ TypeReference<RecommendedStreamConfiguration> managedType, int nativeType) {
+ return new MarshalerRecommendedStreamConfiguration(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<RecommendedStreamConfiguration> managedType,
+ int nativeType) {
+ return nativeType ==
+ TYPE_INT32 && managedType.getType().equals(RecommendedStreamConfiguration.class);
+ }
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
new file mode 100644
index 0000000..5dd0517
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.params;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
+ * with {@link CameraDevice#createCaptureSession}.
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ *
+ * @hide
+ */
+public final class RecommendedStreamConfiguration extends StreamConfiguration{
+
+ /**
+ * Create a new {@link RecommendedStreamConfiguration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param input true if this is an input configuration, false for output configurations
+ * @param usecaseBitmap Use case bitmap
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is ok)
+ *
+ * @hide
+ */
+ public RecommendedStreamConfiguration(
+ final int format, final int width, final int height, final boolean input, final int
+ usecaseBitmap) {
+ super(format, width, height, input);
+ mUsecaseBitmap = usecaseBitmap;
+ }
+
+ /**
+ * Return usecase bitmap.
+ *
+ * @return usecase bitmap
+ */
+ public int getUsecaseBitmap() {
+ return mUsecaseBitmap;
+ }
+
+ /**
+ * Check if this {@link RecommendedStreamConfiguration} is equal to another
+ * {@link RecommendedStreamConfiguration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof RecommendedStreamConfiguration) {
+ final RecommendedStreamConfiguration other = (RecommendedStreamConfiguration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mUsecaseBitmap == other.mUsecaseBitmap &&
+ mInput == other.mInput;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0, mUsecaseBitmap);
+ }
+
+ private final int mUsecaseBitmap;
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
new file mode 100644
index 0000000..59e4a33
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2018 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.hardware.camera2.params;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.util.ArraySet;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraCaptureSession capture session} with
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ *
+ * <p>The recommended list does not replace or deprecate the exhaustive complete list found in
+ * {@link StreamConfigurationMap}. It is a suggestion about available power and performance
+ * efficient stream configurations for a specific use case. Per definition it is only a subset
+ * of {@link StreamConfigurationMap} and can be considered by developers for optimization
+ * purposes.</p>
+ *
+ * <p>This also duplicates the minimum frame durations and stall durations from the
+ * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate
+ * effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available by invoking
+ * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective
+ * usecase id. For more information about supported use case constants see
+ * {@link #USECASE_PREVIEW}.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ * @see CameraDevice#createCaptureSession
+ */
+public final class RecommendedStreamConfigurationMap {
+
+ private static final String TAG = "RecommendedStreamConfigurationMap";
+ private int mUsecase;
+ private boolean mSupportsPrivate;
+ private StreamConfigurationMap mRecommendedMap;
+
+ /** @hide */
+ public static final int MAX_USECASE_COUNT = 32;
+
+ /**
+ * The recommended stream configuration map for use case preview must contain a subset of
+ * efficient, non-stalling configurations that must include both
+ * {@link android.graphics.ImageFormat#PRIVATE} and
+ * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the
+ * camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_PREVIEW = 0x0;
+
+ /**
+ * The recommended stream configuration map for recording must contain a subset of efficient
+ * video configurations that include {@link android.graphics.ImageFormat#PRIVATE}
+ * output format for at least all supported {@link android.media.CamcorderProfile profiles}.
+ * High speed configurations if supported will be available as well. Even if available for the
+ * camera device, input configurations will be absent.
+ */
+ public static final int USECASE_RECORD = 0x1;
+
+ /**
+ * The recommended stream configuration map for use case video snapshot must only contain a
+ * subset of efficient liveshot configurations that include
+ * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least
+ * the maximum resolution of usecase record and will not cause any preview glitches. Even
+ * if available for the camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_VIDEO_SNAPSHOT = 0x2;
+
+ /**
+ * The recommended stream configuration map for use case snapshot must contain a subset of
+ * efficient still capture configurations that must include
+ * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with
+ * size approximately equal to the sensor pixel array size
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * Even if available for the camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_SNAPSHOT = 0x3;
+
+ /**
+ * In case the device supports
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING},
+ * the recommended stream configuration map for use case ZSL must contain a subset of efficient
+ * configurations that include the suggested input and output format mappings. Even if
+ * available for the camera device, high speed configurations will be absent.
+ */
+ public static final int USECASE_ZSL = 0x4;
+
+ /**
+ * In case the device supports
+ * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the
+ * recommended stream configuration map for use case RAW must contain a subset of efficient
+ * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other
+ * RAW output formats. Even if available for the camera device, high speed and input
+ * configurations will be absent.
+ */
+ public static final int USECASE_RAW = 0x5;
+
+ /**
+ * Device specific use cases.
+ * @hide
+ */
+ public static final int USECASE_VENDOR_START = 0x18;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"USECASE_"}, value =
+ {USECASE_PREVIEW,
+ USECASE_RECORD,
+ USECASE_VIDEO_SNAPSHOT,
+ USECASE_SNAPSHOT,
+ USECASE_ZSL,
+ USECASE_RAW })
+ public @interface RecommendedUsecase {};
+
+ /**
+ * Create a new {@link RecommendedStreamConfigurationMap}.
+ *
+ * @param recommendedMap stream configuration map that contains for the specific use case
+ * @param usecase Recommended use case
+ * @param supportsPrivate Flag indicating private format support.
+ *
+ * @hide
+ */
+ public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase,
+ boolean supportsPrivate) {
+ mRecommendedMap = recommendedMap;
+ mUsecase = usecase;
+ mSupportsPrivate = supportsPrivate;
+ }
+
+ /**
+ * Get the use case value for the recommended stream configurations.
+ *
+ * @return Use case id.
+ */
+ public int getRecommendedUseCase() {
+ return mUsecase;
+ }
+
+ private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) {
+ if ((intArray != null) && (intArray.length > 0)) {
+ ArraySet<Integer> integerSet = new ArraySet<Integer>();
+ integerSet.ensureCapacity(intArray.length);
+ for (int intEntry : intArray) {
+ integerSet.add(intEntry);
+ }
+
+ return Collections.unmodifiableSet(integerSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the image {@code format} output formats in this stream configuration.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getOutputFormats}.
+ * </p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @NonNull Set<Integer> getOutputFormats() {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats());
+ }
+
+ /**
+ * Get the image {@code format} output formats for a reprocessing input format.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}.
+ * </p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
+ inputFormat));
+ }
+
+ /**
+ * Get the image {@code format} input formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @Nullable Set<Integer> getInputFormats() {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats());
+ }
+
+ private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) {
+ if ((sizeArray != null) && (sizeArray.length > 0)) {
+ ArraySet<Size> sizeSet = new ArraySet<Size>();
+ sizeSet.addAll(Arrays.asList(sizeArray));
+ return Collections.unmodifiableSet(sizeSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the supported input sizes for this input format.
+ *
+ * <p>The format must have come from {@link #getInputFormats}; otherwise
+ * {@code null} is returned.</p>
+ *
+ * @param format a format from {@link #getInputFormats}
+ * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
+ */
+ public @Nullable Set<Size> getInputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
+ }
+
+ /**
+ * Determine whether or not output surfaces with a particular user-defined format can be passed
+ * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+ * </p>
+ *
+ *
+ * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * {@code true} if using a {@code surface} with this {@code format} will be
+ * supported with {@link CameraDevice#createCaptureSession}
+ *
+ * @throws IllegalArgumentException
+ * if the image format was not a defined named constant
+ * from either {@link ImageFormat} or {@link PixelFormat}
+ */
+ public boolean isOutputSupportedFor(int format) {
+ return mRecommendedMap.isOutputSupportedFor(format);
+ }
+
+ /**
+ * Get a list of sizes compatible with the requested image {@code format}.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getOutputSizes}.
+ * </p>
+ *
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return a non-modifiable set of supported sizes,
+ * or {@code null} if the {@code format} is not a supported output
+ */
+ public @Nullable Set<Size> getOutputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
+ }
+
+ /**
+ * Get a list of supported high speed video recording sizes.
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}.
+ * </p>
+ *
+ * @return a non-modifiable set of supported high speed video recording sizes
+ */
+ public @Nullable Set<Size> getHighSpeedVideoSizes() {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes());
+ }
+
+ private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) {
+ if ((rangeArray != null) && (rangeArray.length > 0)) {
+ ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>();
+ rangeSet.addAll(Arrays.asList(rangeArray));
+ return Collections.unmodifiableSet(rangeSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
+ *
+ * <p>
+ * For further information refer to
+ * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}.
+ * </p>
+ * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
+ * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+ * bound of returned ranges is guaranteed to be greater than or equal to 120.
+ * @throws IllegalArgumentException if input size does not exist in the return value of
+ * getHighSpeedVideoSizes
+ */
+ public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) {
+ return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
+ }
+
+ /**
+ * Get a list of supported high speed video recording FPS ranges.
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}.
+ * </p>
+ * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+ * bound of returned ranges is guaranteed to be larger or equal to 120.
+ */
+ public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() {
+ return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges());
+ }
+
+ /**
+ * Get the supported video sizes for an input high speed FPS range.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
+ * </p>
+ *
+ * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
+ * @return A non-modifiable set of video sizes to create high speed capture sessions for high
+ * speed streaming use cases.
+ *
+ * @throws IllegalArgumentException if input FPS range does not exist in the return value of
+ * getHighSpeedVideoFpsRanges
+ */
+ public @Nullable Set<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
+ }
+
+ /**
+ * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
+ * rate.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}.
+ * </p>
+ *
+ * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
+ * the BURST_CAPTURE capability is not supported
+ */
+ public @Nullable Set<Size> getHighResolutionOutputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
+ }
+
+ /**
+ * Get the minimum
+ * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}.
+ * </p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+ * 0 if the minimum frame duration is not available.
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ */
+ public long getOutputMinFrameDuration(int format, Size size) {
+ return mRecommendedMap.getOutputMinFrameDuration(format, size);
+ }
+
+ /**
+ * Get the stall duration for the format/size combination (in nanoseconds).
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}.
+ * </p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a stall duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ */
+ public long getOutputStallDuration(int format, Size size) {
+ return mRecommendedMap.getOutputStallDuration(format, size);
+ }
+
+ /**
+ * Get a list of sizes compatible with {@code klass} to use as an output.
+ *
+ * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}.
+ * </p>
+ *
+ * @param klass
+ * a non-{@code null} {@link Class} object reference
+ * @return
+ * a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
+ * or {@code null} if the {@code klass} is not a supported output.
+ *
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ */
+ public <T> @Nullable Set<Size> getOutputSizes(Class<T> klass) {
+ if (mSupportsPrivate) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>For more information refer to
+ * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
+ *
+ * @param klass
+ * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+ * 0 if the minimum frame duration is not available.
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ */
+ public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ if (mSupportsPrivate) {
+ return mRecommendedMap.getOutputMinFrameDuration(klass, size);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get the stall duration for the class/size combination (in nanoseconds).
+ *
+ * <p>For more information refer to
+ * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}.
+ *
+ * @param klass
+ * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds, or 0 if the stall duration is
+ * not available.
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ */
+ public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ if (mSupportsPrivate) {
+ return mRecommendedMap.getOutputStallDuration(klass, size);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Determine whether or not the {@code surface} in its current state is suitable to be included
+ * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ *
+ * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+ * </p>
+ *
+ * @param surface a non-{@code null} {@link Surface} object reference
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code surface} was {@code null}
+ * @throws IllegalArgumentException if the Surface endpoint is no longer valid
+ *
+ */
+ public boolean isOutputSupportedFor(Surface surface) {
+ return mRecommendedMap.isOutputSupportedFor(surface);
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index a6fc10f..eb92291 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -40,7 +40,7 @@
*
* @hide
*/
-public final class StreamConfiguration {
+public class StreamConfiguration {
/**
* Create a new {@link StreamConfiguration}.
@@ -164,8 +164,8 @@
return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
}
- private final int mFormat;
- private final int mWidth;
- private final int mHeight;
- private final boolean mInput;
+ protected int mFormat;
+ protected int mWidth;
+ protected int mHeight;
+ protected boolean mInput;
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 414c463..dd052a8 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -98,6 +98,43 @@
HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
ReprocessFormatsMap inputOutputFormatsMap,
boolean listHighResolution) {
+ this(configurations, minFrameDurations, stallDurations,
+ depthConfigurations, depthMinFrameDurations, depthStallDurations,
+ highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
+ /*enforceImplementationDefined*/ true);
+ }
+
+ /**
+ * Create a new {@link StreamConfigurationMap}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+ * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
+ * camera device does not support high speed video recording
+ * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
+ * and thus needs a separate list of slow high-resolution output sizes
+ * @param enforceImplementationDefined a flag indicating whether
+ * IMPLEMENTATION_DEFINED format configuration must be present
+ * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
+ * were {@code null} or any subelements were {@code null}
+ *
+ * @hide
+ */
+ public StreamConfigurationMap(
+ StreamConfiguration[] configurations,
+ StreamConfigurationDuration[] minFrameDurations,
+ StreamConfigurationDuration[] stallDurations,
+ StreamConfiguration[] depthConfigurations,
+ StreamConfigurationDuration[] depthMinFrameDurations,
+ StreamConfigurationDuration[] depthStallDurations,
+ HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
+ ReprocessFormatsMap inputOutputFormatsMap,
+ boolean listHighResolution,
+ boolean enforceImplementationDefined) {
if (configurations == null) {
// If no color configurations exist, ensure depth ones do
@@ -169,7 +206,7 @@
mDepthOutputFormats.get(config.getFormat()) + 1);
}
- if (configurations != null &&
+ if (configurations != null && enforceImplementationDefined &&
mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
throw new AssertionError(
"At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
@@ -208,7 +245,7 @@
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getOutputFormats() {
+ public int[] getOutputFormats() {
return getPublicFormats(/*output*/true);
}
@@ -232,7 +269,7 @@
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getValidOutputFormatsForInput(int inputFormat) {
+ public int[] getValidOutputFormatsForInput(int inputFormat) {
if (mInputOutputFormatsMap == null) {
return new int[0];
}
@@ -250,7 +287,7 @@
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getInputFormats() {
+ public int[] getInputFormats() {
return getPublicFormats(/*output*/false);
}
@@ -426,6 +463,34 @@
}
/**
+ * Determine whether or not the particular stream configuration is suitable to be included
+ * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ *
+ * @param size stream configuration size
+ * @param format stream configuration format
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @see CameraDevice#createCaptureSession
+ * @see #isOutputSupportedFor(Class)
+ * @hide
+ */
+ public boolean isOutputSupportedFor(Size size, int format) {
+ int internalFormat = imageFormatToInternal(format);
+ int dataspace = imageFormatToDataspace(format);
+
+ StreamConfiguration[] configs =
+ dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+ for (StreamConfiguration config : configs) {
+ if ((config.getFormat() == internalFormat) && config.isOutput() &&
+ config.getSize().equals(size)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Get a list of sizes compatible with {@code klass} to use as an output.
*
* <p>Some of the supported classes may support additional formats beyond
@@ -1062,8 +1127,9 @@
* @see ImageFormat
* @see PixelFormat
* @see #checkArgumentFormat
+ * @hide
*/
- static int imageFormatToPublic(int format) {
+ public static int imageFormatToPublic(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_BLOB:
return ImageFormat.JPEG;
@@ -1105,8 +1171,9 @@
* @see ImageFormat
* @see PixelFormat
* @see #checkArgumentFormat
+ * @hide
*/
- static int depthFormatToPublic(int format) {
+ public static int depthFormatToPublic(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_BLOB:
return ImageFormat.DEPTH_POINT_CLOUD;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 7840fd0..9db1f92 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -235,7 +235,8 @@
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
- // If true, scales the brightness to half of desired.
+ // If true, scales the brightness to a fraction of desired (as defined by
+ // screenLowPowerBrightnessFactor).
public boolean lowPowerMode;
// The factor to adjust the screen brightness in low power mode in the range
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 9f11246..2717c4e 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -107,9 +107,10 @@
* This method should be used if the caller wants to receive notifications even after the
* process exits. The client must have an open connection with the Context Hub Service (i.e. it
* cannot have been closed through the {@link #close()} method). Only one PendingIntent can be
- * registered at a time for a single ContextHubClient. If registered successfully, intents will
- * be delivered regarding events for the specified nanoapp from the attached Context Hub. Any
- * unicast messages for this client will also be delivered. The intent will have an extra
+ * registered at a time for a single ContextHubClient, and the PendingIntent cannot be
+ * registered if already registered by a ContextHubClient. If registered successfully, intents
+ * will be delivered regarding events for the specified nanoapp from the attached Context Hub.
+ * Any unicast messages for this client will also be delivered. The intent will have an extra
* {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
* describes the Context Hub the intent event was for. The intent will also have an extra
* {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 98f3567..4cd0001 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -393,4 +393,19 @@
}
return out;
}
+
+ /**
+ * Checks if this MAC Address matches the provided range.
+ *
+ * @param baseAddress MacAddress representing the base address to compare with.
+ * @param mask MacAddress representing the mask to use during comparison.
+ * @return true if this MAC Address matches the given range.
+ *
+ * @hide
+ */
+ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ Preconditions.checkNotNull(baseAddress);
+ Preconditions.checkNotNull(mask);
+ return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+ }
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index ab048c5..b25707a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -32,6 +32,8 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -55,8 +57,8 @@
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0";
private static final String ANGLE_PACKAGE_NAME = "com.android.angle";
- private static final String GLES_MODE_METADATA_KEY = "com.android.angle.GLES_MODE";
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
+ private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private ClassLoader mClassLoader;
private String mLayerPath;
@@ -207,38 +209,11 @@
&& (!angleEnabledApp.isEmpty() && !packageName.isEmpty())
&& angleEnabledApp.equals(packageName)) {
- if (DEBUG) Log.v(TAG, packageName + " opted in for ANGLE via Developer Setting");
+ Log.i(TAG, packageName + " opted in for ANGLE via Developer Setting");
devOptIn = true;
}
- ApplicationInfo appInfo;
- try {
- appInfo = context.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Failed to get info about current application: " + packageName);
- return;
- }
-
- String appPref = "dontcare";
- final BaseBundle metadata = appInfo.metaData;
- if (metadata != null) {
- final String glesMode = metadata.getString(GLES_MODE_METADATA_KEY);
- if (glesMode != null) {
- if (glesMode.equals("angle")) {
- appPref = "angle";
- if (DEBUG) Log.v(TAG, packageName + " opted for ANGLE via AndroidManifest");
- } else if (glesMode.equals("native")) {
- appPref = "native";
- if (DEBUG) Log.v(TAG, packageName + " opted for NATIVE via AndroidManifest");
- } else {
- Log.w(TAG, "Unrecognized GLES_MODE (\"" + glesMode + "\") for " + packageName
- + ". Supported values are \"angle\" or \"native\"");
- }
- }
- }
-
ApplicationInfo angleInfo;
try {
angleInfo = context.getPackageManager().getApplicationInfo(ANGLE_PACKAGE_NAME,
@@ -261,39 +236,76 @@
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
- // Pass the rules file to loader for ANGLE decisions
- AssetManager angleAssets = null;
- try {
- angleAssets =
- context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Failed to get AssetManager for '" + ANGLE_PACKAGE_NAME + "'");
- return;
- }
-
- AssetFileDescriptor assetsFd = null;
- try {
- assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
- } catch (IOException e) {
- Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + " from "
- + "'" + ANGLE_PACKAGE_NAME + "'");
- return;
- }
-
+ // Look up rules file to pass to ANGLE
FileDescriptor rulesFd = null;
long rulesOffset = 0;
long rulesLength = 0;
- if (assetsFd != null) {
- rulesFd = assetsFd.getFileDescriptor();
- rulesOffset = assetsFd.getStartOffset();
- rulesLength = assetsFd.getLength();
- } else {
- Log.w(TAG, "Failed to get file descriptor for " + ANGLE_RULES_FILE);
- return;
+
+ // Check for temporary rules if debuggable or root
+ if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
+ String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
+ if (angleTempRules != null && !angleTempRules.isEmpty()) {
+ Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
+ File tempRulesFile = new File(angleTempRules);
+ if (tempRulesFile.exists()) {
+ Log.i(TAG, angleTempRules + " exists, loading file.");
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(angleTempRules);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Unable to create stream for temp ANGLE rules");
+ }
+
+ if (stream != null) {
+ try {
+ rulesFd = stream.getFD();
+ rulesOffset = 0;
+ rulesLength = stream.getChannel().size();
+ Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get input stream for " + angleTempRules);
+ }
+ }
+ }
+ }
+ }
+
+ // If no temp rules, load the real ones from the APK
+ if (rulesFd == null) {
+
+ // Pass the rules file to loader for ANGLE decisions
+ AssetManager angleAssets = null;
+ try {
+ angleAssets =
+ context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to get AssetManager for '" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ AssetFileDescriptor assetsFd = null;
+ try {
+ assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + " from "
+ + "'" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ if (assetsFd != null) {
+ rulesFd = assetsFd.getFileDescriptor();
+ rulesOffset = assetsFd.getStartOffset();
+ rulesLength = assetsFd.getLength();
+ } else {
+ Log.w(TAG, "Failed to get file descriptor for " + ANGLE_RULES_FILE);
+ return;
+ }
}
// Further opt-in logic is handled in native, so pass relevant info down
- setAngleInfo(paths, packageName, appPref, devOptIn,
+ // TODO: Move the ANGLE selection logic earlier so we don't need to keep these
+ // file descriptors open.
+ setAngleInfo(paths, packageName, devOptIn,
rulesFd, rulesOffset, rulesLength);
}
@@ -434,7 +446,7 @@
private static native void setDebugLayers(String layers);
private static native void setDebugLayersGLES(String layers);
private static native void setDriverPath(String path);
- private static native void setAngleInfo(String path, String appPackage, String appPref,
+ private static native void setAngleInfo(String path, String appPackage,
boolean devOptIn, FileDescriptor rulesFd,
long rulesOffset, long rulesLength);
}
diff --git a/core/java/android/os/IThermalEventListener.aidl b/core/java/android/os/IThermalEventListener.aidl
index 9a6de60..fc93b5c 100644
--- a/core/java/android/os/IThermalEventListener.aidl
+++ b/core/java/android/os/IThermalEventListener.aidl
@@ -27,6 +27,5 @@
* Called when a thermal throttling start/stop event is received.
* @param temperature the temperature at which the event was generated.
*/
- void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
+ void notifyThrottling(in Temperature temperature);
}
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index e388eda..287a5ed 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -19,6 +19,8 @@
import android.os.IThermalEventListener;
import android.os.Temperature;
+import java.util.List;
+
/**
* {@hide}
*/
@@ -30,22 +32,29 @@
*/
void registerThermalEventListener(in IThermalEventListener listener);
/**
+ * Register a listener for thermal events on given temperature type.
+ * @param listener the IThermalEventListener to be notified.
+ * @param type the temperature type IThermalEventListener to be notified.
+ * {@hide}
+ */
+ void registerThermalEventListenerWithType(in IThermalEventListener listener, in int type);
+ /**
* Unregister a previously-registered listener for thermal events.
* @param listener the IThermalEventListener to no longer be notified.
* {@hide}
*/
void unregisterThermalEventListener(in IThermalEventListener listener);
/**
- * Send a thermal throttling start/stop notification to all listeners.
- * @param temperature the temperature at which the event was generated.
+ * Get current temperature with its throttling status.
+ * @return list of android.os.Temperature
* {@hide}
*/
- oneway void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
+ List<Temperature> getCurrentTemperatures();
/**
- * Return whether system performance is currently thermal throttling.
- * @return true if thermal throttling is currently in effect
+ * Get current temperature with its throttling status on given temperature type.
+ * @param type the temperature type to query.
+ * @return list of android.os.Temperature
* {@hide}
*/
- boolean isThrottling();
+ List<Temperature> getCurrentTemperaturesWithType(in int type);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e0b2c78..27c281d 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -477,6 +477,13 @@
public static final String SHUTDOWN_BATTERY_THERMAL_STATE = "thermal,battery";
/**
+ * The value to pass as the 'reason' argument to android_reboot() when device temperature
+ * is too high.
+ * @hide
+ */
+ public static final String SHUTDOWN_THERMAL_STATE = "thermal";
+
+ /**
* The value to pass as the 'reason' argument to android_reboot() when device is running
* critically low on battery.
* @hide
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index 8767731..37ed52c 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -16,6 +16,13 @@
package android.os;
+import android.annotation.IntDef;
+import android.hardware.thermal.V2_0.TemperatureType;
+import android.hardware.thermal.V2_0.ThrottlingSeverity;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Temperature values used by IThermalService.
*/
@@ -24,24 +31,89 @@
* @hide
*/
public class Temperature implements Parcelable {
- /* Temperature value */
+ /** Temperature value */
private float mValue;
- /* A temperature type from HardwarePropertiesManager */
+ /** A temperature type from ThermalHAL */
private int mType;
+ /** Name of this temperature */
+ private String mName;
+ /** The level of the sensor is currently in throttling */
+ private int mStatus;
- public Temperature() {
- this(HardwarePropertiesManager.UNDEFINED_TEMPERATURE,
- Integer.MIN_VALUE);
+ /** @hide */
+ @IntDef(prefix = { "THROTTLING_" }, value = {
+ THROTTLING_NONE,
+ THROTTLING_LIGHT,
+ THROTTLING_MODERATE,
+ THROTTLING_SEVERE,
+ THROTTLING_CRITICAL,
+ THROTTLING_WARNING,
+ THROTTLING_SHUTDOWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ThrottlingStatus {}
+
+ /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ public static final int THROTTLING_NONE = ThrottlingSeverity.NONE;
+ public static final int THROTTLING_LIGHT = ThrottlingSeverity.LIGHT;
+ public static final int THROTTLING_MODERATE = ThrottlingSeverity.MODERATE;
+ public static final int THROTTLING_SEVERE = ThrottlingSeverity.SEVERE;
+ public static final int THROTTLING_CRITICAL = ThrottlingSeverity.CRITICAL;
+ public static final int THROTTLING_WARNING = ThrottlingSeverity.WARNING;
+ public static final int THROTTLING_SHUTDOWN = ThrottlingSeverity.SHUTDOWN;
+
+ /** @hide */
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN,
+ TYPE_CPU,
+ TYPE_GPU,
+ TYPE_BATTERY,
+ TYPE_SKIN,
+ TYPE_USB_PORT,
+ TYPE_POWER_AMPLIFIER,
+ TYPE_BCL_VOLTAGE,
+ TYPE_BCL_CURRENT,
+ TYPE_BCL_PERCENTAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /* Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN;
+ public static final int TYPE_CPU = TemperatureType.CPU;
+ public static final int TYPE_GPU = TemperatureType.GPU;
+ public static final int TYPE_BATTERY = TemperatureType.BATTERY;
+ public static final int TYPE_SKIN = TemperatureType.SKIN;
+ public static final int TYPE_USB_PORT = TemperatureType.USB_PORT;
+ public static final int TYPE_POWER_AMPLIFIER = TemperatureType.POWER_AMPLIFIER;
+ public static final int TYPE_BCL_VOLTAGE = TemperatureType.BCL_VOLTAGE;
+ public static final int TYPE_BCL_CURRENT = TemperatureType.BCL_CURRENT;
+ public static final int TYPE_BCL_PERCENTAGE = TemperatureType.BCL_PERCENTAGE;
+
+ /**
+ * Verify a valid temperature type.
+ *
+ * @return true if a temperature type is valid otherwise false.
+ */
+ public static boolean isValidType(int type) {
+ return type >= TYPE_UNKNOWN && type <= TYPE_BCL_PERCENTAGE;
}
- public Temperature(float value, int type) {
+ public Temperature() {
+ this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE);
+ }
+
+ public Temperature(float value, @Type int type, String name, int status) {
mValue = value;
- mType = type;
+ mType = isValidType(type) ? type : TYPE_UNKNOWN;
+ mName = name;
+ mStatus = status;
}
/**
* Return the temperature value.
- * @return a temperature value in floating point.
+ *
+ * @return a temperature value in floating point could be NaN.
*/
public float getValue() {
return mValue;
@@ -49,18 +121,30 @@
/**
* Return the temperature type.
- * @return a temperature type:
- * HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU, etc.
+ *
+ * @return a temperature type: TYPE_*
*/
- public int getType() {
+ public @Type int getType() {
return mType;
}
- /*
- * Parcel read/write code must be kept in sync with
- * frameworks/native/services/thermalservice/aidl/android/os/
- * Temperature.cpp
+ /**
+ * Return the temperature name.
+ *
+ * @return a temperature name as String.
*/
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Return the temperature throttling status.
+ *
+ * @return a temperature throttling status: THROTTLING_*
+ */
+ public @ThrottlingStatus int getStatus() {
+ return mStatus;
+ }
private Temperature(Parcel p) {
readFromParcel(p);
@@ -68,31 +152,36 @@
/**
* Fill in Temperature members from a Parcel.
+ *
* @param p the parceled Temperature object.
*/
public void readFromParcel(Parcel p) {
mValue = p.readFloat();
mType = p.readInt();
+ mName = p.readString();
+ mStatus = p.readInt();
}
@Override
public void writeToParcel(Parcel p, int flags) {
p.writeFloat(mValue);
p.writeInt(mType);
+ p.writeString(mName);
+ p.writeInt(mStatus);
}
public static final Parcelable.Creator<Temperature> CREATOR =
new Parcelable.Creator<Temperature>() {
- @Override
- public Temperature createFromParcel(Parcel p) {
- return new Temperature(p);
- }
+ @Override
+ public Temperature createFromParcel(Parcel p) {
+ return new Temperature(p);
+ }
- @Override
- public Temperature[] newArray(int size) {
- return new Temperature[size];
- }
- };
+ @Override
+ public Temperature[] newArray(int size) {
+ return new Temperature[size];
+ }
+ };
@Override
public int describeContents() {
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 5bef7ee..8a03e9e 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -331,7 +331,12 @@
* @return intent to request access, or {@code null} if the requested directory is invalid for
* that volume.
* @see DocumentsContract
+ * @deprecated Callers should migrate to using {@link Intent#ACTION_OPEN_DOCUMENT_TREE} instead.
+ * Launching this {@link Intent} on devices running
+ * {@link android.os.Build.VERSION_CODES#Q} or higher, will immediately finish
+ * with a result code of {@link android.app.Activity#RESULT_CANCELED}.
*/
+ @Deprecated
public @Nullable Intent createAccessIntent(String directoryName) {
if ((isPrimary() && directoryName == null) ||
(directoryName != null && !Environment.isStandardDirectory(directoryName))) {
@@ -425,32 +430,4 @@
parcel.writeString(mFsUuid);
parcel.writeString(mState);
}
-
- /** {@hide} */
- public static final class ScopedAccessProviderContract {
-
- private ScopedAccessProviderContract() {
- throw new UnsupportedOperationException("contains constants only");
- }
-
- public static final String AUTHORITY = "com.android.documentsui.scopedAccess";
-
- public static final String TABLE_PACKAGES = "packages";
- public static final String TABLE_PERMISSIONS = "permissions";
-
- public static final String COL_PACKAGE = "package_name";
- public static final String COL_VOLUME_UUID = "volume_uuid";
- public static final String COL_DIRECTORY = "directory";
- public static final String COL_GRANTED = "granted";
-
- public static final String[] TABLE_PACKAGES_COLUMNS = new String[] { COL_PACKAGE };
- public static final String[] TABLE_PERMISSIONS_COLUMNS =
- new String[] { COL_PACKAGE, COL_VOLUME_UUID, COL_DIRECTORY, COL_GRANTED };
-
- public static final int TABLE_PACKAGES_COL_PACKAGE = 0;
- public static final int TABLE_PERMISSIONS_COL_PACKAGE = 0;
- public static final int TABLE_PERMISSIONS_COL_VOLUME_UUID = 1;
- public static final int TABLE_PERMISSIONS_COL_DIRECTORY = 2;
- public static final int TABLE_PERMISSIONS_COL_GRANTED = 3;
- }
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index fc30eed..2ea7066 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -67,15 +67,14 @@
* such an old app asks for a location permission (i.e. the
* {@link SplitPermissionInfo#getSplitPermission()}), then the
* {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
- * {@{@link SplitPermissionInfo#getNewPermissions}) is added.
+ * {@link SplitPermissionInfo#getNewPermissions}) is added.
*
* <p>Note: Regular apps do not have to worry about this. The platform and permission controller
* automatically add the new permissions where needed.
*
* @return All permissions that are split.
*/
- public @NonNull
- List<SplitPermissionInfo> getSplitPermissions() {
+ public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
return SPLIT_PERMISSIONS;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index c0fa1de..3d93afd 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -509,6 +509,100 @@
private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10;
/**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set as the default value when a call was
+ * not blocked by a CallScreeningService or any other system call blocking method.
+ */
+ public static final int BLOCK_REASON_NOT_BLOCKED = 0;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked by a
+ * CallScreeningService. The {@link CallLog.Calls#CALL_SCREENING_COMPONENT_NAME} and
+ * {@link CallLog.Calls#CALL_SCREENING_APP_NAME} columns will indicate which call screening
+ * service was responsible for blocking the call.
+ */
+ public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * configured a contact to be sent directly to voicemail.
+ */
+ public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because it is
+ * in the BlockedNumbers provider.
+ */
+ public static final int BLOCK_REASON_BLOCKED_NUMBER = 3;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from unknown numbers.
+ */
+ public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from restricted numbers.
+ */
+ public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from pay phones.
+ */
+ public static final int BLOCK_REASON_PAY_PHONE = 6;
+
+ /**
+ * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is
+ * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user
+ * has chosen to block all calls from numbers not in their contacts.
+ */
+ public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7;
+
+ /**
+ * The ComponentName of the CallScreeningService which blocked this call. Will be
+ * populated when the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
+
+ /**
+ * The name of the app which blocked a call. Will be populated when the
+ * {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}. Provided as a
+ * convenience so that the call log can still indicate which app blocked a call, even if
+ * that app is no longer installed.
+ * <P>Type: TEXT</P>
+ */
+ public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+
+ /**
+ * Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE},
+ * indicates the reason why a call is blocked.
+ * <P>Type: INTEGER</P>
+ *
+ * <p>
+ * Allowed values:
+ * <ul>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_BLOCKED}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_DIRECT_TO_VOICEMAIL}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_BLOCKED_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_UNKNOWN_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_RESTRICTED_NUMBER}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_PAY_PHONE}</li>
+ * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_IN_CONTACTS}</li>
+ * </ul>
+ * </p>
+ */
+ public static final String BLOCK_REASON = "block_reason";
+
+ /**
* Adds a call to the call log.
*
* @param ci the CallerInfo object to get the target contact from. Can be null
@@ -530,12 +624,14 @@
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
- int presentation, int callType, int features, PhoneAccountHandle accountHandle,
+ int presentation, int callType, int features,
+ PhoneAccountHandle accountHandle,
long start, int duration, Long dataUsage) {
- return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "",
- presentation, callType, features, accountHandle, start, duration,
- dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null,
- /* is_read =*/ false);
+ return addCall(ci, context, number, "" /* postDialDigits */, "" /* viaNumber */,
+ presentation, callType, features, accountHandle, start, duration,
+ dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */,
+ false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */,
+ null /* callScreeningAppName */, null /* callScreeningComponentName */);
}
@@ -572,8 +668,10 @@
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) {
return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType,
- features, accountHandle, start, duration, dataUsage, addForAllUsers,
- userToBeInsertedTo, /* is_read =*/ false);
+ features, accountHandle, start, duration, dataUsage, addForAllUsers,
+ userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED
+ /* callBlockReason */, null /* callScreeningAppName */,
+ null /* callScreeningComponentName */);
}
/**
@@ -602,8 +700,11 @@
* @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be
* inserted to. null if it is inserted to the current user. The
* value is ignored if @{link addForAllUsers} is true.
- * @param is_read Flag to show if the missed call log has been read by the user or not.
+ * @param isRead Flag to show if the missed call log has been read by the user or not.
* Used for call log restore of missed calls.
+ * @param callBlockReason The reason why the call is blocked.
+ * @param callScreeningAppName The call screening application name which block the call.
+ * @param callScreeningComponentName The call screening component name which block the call.
*
* @result The URI of the call log entry belonging to the user that made or received this
* call. This could be of the shadow provider. Do not return it to non-system apps,
@@ -615,7 +716,8 @@
String postDialDigits, String viaNumber, int presentation, int callType,
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
- boolean is_read) {
+ boolean isRead, int callBlockReason, String callScreeningAppName,
+ String callScreeningComponentName) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
number, userToBeInsertedTo, addForAllUsers));
@@ -690,9 +792,13 @@
values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0);
if (callType == MISSED_TYPE) {
- values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0));
+ values.put(IS_READ, Integer.valueOf(isRead ? 1 : 0));
}
+ values.put(BLOCK_REASON, callBlockReason);
+ values.put(CALL_SCREENING_APP_NAME, callScreeningAppName);
+ values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
+
if ((ci != null) && (ci.contactIdOrZero > 0)) {
// Update usage information for the number associated with the contact ID.
// We need to use both the number and the ID for obtaining a data ID since other
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7de55e6..0283941 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1600,8 +1600,11 @@
* Applications typically use this action to ask the user to revert the "Do not ask again"
* status of directory access requests made by
* {@link android.os.storage.StorageVolume#createAccessIntent(String)}.
+ * @deprecated use {@link #ACTION_APPLICATION_DETAILS_SETTINGS} to manage storage permissions
+ * for a specific application
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS =
"android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
@@ -8199,6 +8202,12 @@
"packages_to_clear_data_before_full_restore";
/**
+ * Setting to determine whether to use the new notification priority handling features.
+ * @hide
+ */
+ public static final String NOTIFICATION_NEW_INTERRUPTION_MODEL = "new_interruption_model";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -8312,6 +8321,7 @@
CHARGING_VIBRATION_ENABLED,
ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+ NOTIFICATION_NEW_INTERRUPTION_MODEL,
};
/**
@@ -8471,6 +8481,7 @@
VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
}
/**
@@ -11509,6 +11520,24 @@
public static final String NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled";
/**
+ * Whether or not show hidden launcher icon apps feature is enabled.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED =
+ "show_hidden_icon_apps_enabled";
+
+ /**
+ * Whether or not show new app installed notification is enabled.
+ * Type: int (0 for false, 1 for true)
+ * Default: 0
+ * @hide
+ */
+ public static final String SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED =
+ "show_new_app_installed_notification_enabled";
+
+ /**
* Flag to keep background restricted profiles running after exiting. If disabled,
* the restricted profile can be put into stopped state as soon as the user leaves it.
* Type: int (0 for false, 1 for true)
@@ -12500,6 +12529,17 @@
"privileged_device_identifier_target_q_behavior_enabled";
/**
+ * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
+ * permission check for 3P apps.
+ *
+ * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+ *
+ * @hide
+ */
+ public static final String PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED =
+ "privileged_device_identifier_3p_check_relaxed";
+
+ /**
* If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
* and restoring to lower version of platform API will be skipped.
*
diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl
new file mode 100644
index 0000000..bacad8b
--- /dev/null
+++ b/core/java/android/service/intelligence/IIntelligenceService.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.service.intelligence;
+
+import android.service.intelligence.InteractionSessionId;
+import android.service.intelligence.InteractionContext;
+
+import android.view.intelligence.ContentCaptureEvent;
+
+import java.util.List;
+
+
+/**
+ * Interface from the system to an intelligence service.
+ *
+ * @hide
+ */
+oneway interface IIntelligenceService {
+
+ // Called when session is created (context not null) or destroyed (context null)
+ void onSessionLifecycle(in InteractionContext context, in InteractionSessionId sessionId);
+
+ void onContentCaptureEvents(in InteractionSessionId sessionId,
+ in List<ContentCaptureEvent> events);
+}
diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java
index 4b8825d..a2b60f0 100644
--- a/core/java/android/service/intelligence/IntelligenceService.java
+++ b/core/java/android/service/intelligence/IntelligenceService.java
@@ -15,16 +15,24 @@
*/
package android.service.intelligence;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.intelligence.ContentCaptureEvent;
import java.util.List;
/**
- * A service used to captures the content of the screen.
+ * A service used to capture the content of the screen.
*
* <p>The data collected by this service can be analyzed and combined with other sources to provide
* contextual data in other areas of the system such as Autofill.
@@ -34,6 +42,8 @@
@SystemApi
public abstract class IntelligenceService extends Service {
+ private static final String TAG = "IntelligenceService";
+
/**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
@@ -43,6 +53,50 @@
public static final String SERVICE_INTERFACE =
"android.service.intelligence.IntelligenceService";
+ private Handler mHandler;
+
+ private final IIntelligenceService mInterface = new IIntelligenceService.Stub() {
+
+ @Override
+ public void onSessionLifecycle(InteractionContext context, InteractionSessionId sessionId)
+ throws RemoteException {
+ if (context != null) {
+ mHandler.sendMessage(
+ obtainMessage(IntelligenceService::onCreateInteractionSession,
+ IntelligenceService.this, context, sessionId));
+ } else {
+ mHandler.sendMessage(
+ obtainMessage(IntelligenceService::onDestroyInteractionSession,
+ IntelligenceService.this, sessionId));
+ }
+ }
+ @Override
+ public void onContentCaptureEvents(InteractionSessionId sessionId,
+ List<ContentCaptureEvent> events) {
+ mHandler.sendMessage(
+ obtainMessage(IntelligenceService::onContentCaptureEvent,
+ IntelligenceService.this, sessionId, events));
+
+ }
+ };
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ /** @hide */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Log.w(TAG, "Tried to bind to wrong intent: " + intent);
+ return null;
+ }
+
/**
* Creates a new interaction session.
*
@@ -59,11 +113,12 @@
* @param sessionId the session's Id
* @param events the events
*/
+ // TODO(b/111276913): rename to onContentCaptureEvents
public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId,
@NonNull List<ContentCaptureEvent> events);
/**
- * Destroys the content capture session identified by the specified {@code sessionId}.
+ * Destroys the interaction session.
*
* @param sessionId the id of the session to destroy
*/
diff --git a/core/java/android/service/intelligence/InteractionContext.aidl b/core/java/android/service/intelligence/InteractionContext.aidl
new file mode 100644
index 0000000..4ce6aa4
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionContext.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018, 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.service.intelligence;
+
+parcelable InteractionContext;
diff --git a/core/java/android/service/intelligence/InteractionContext.java b/core/java/android/service/intelligence/InteractionContext.java
index 4d83820..c1803ad 100644
--- a/core/java/android/service/intelligence/InteractionContext.java
+++ b/core/java/android/service/intelligence/InteractionContext.java
@@ -23,6 +23,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,7 +35,7 @@
public final class InteractionContext implements Parcelable {
/**
- * Flag used to indicate that the app explicitly disabled contents capture for the activity
+ * Flag used to indicate that the app explicitly disabled content capture for the activity
* (using
* {@link android.view.intelligence.IntelligenceManager#disableContentCapture()}),
* in which case the service will just receive activity-level events.
@@ -54,24 +57,34 @@
@Retention(RetentionPolicy.SOURCE)
@interface ContextCreationFlags{}
+ // TODO(b/111276913): create new object for taskId + componentName / reuse on other places
+ private final @NonNull ComponentName mComponentName;
+ private final int mTaskId;
+ private final int mDisplayId;
+ private final int mFlags;
+
+
/** @hide */
- InteractionContext() {
+ public InteractionContext(@NonNull ComponentName componentName, int taskId, int displayId,
+ int flags) {
+ mComponentName = Preconditions.checkNotNull(componentName);
+ mTaskId = taskId;
+ mDisplayId = displayId;
+ mFlags = flags;
}
/**
* Gets the id of the {@link TaskInfo task} associated with this context.
*/
public int getTaskId() {
- //TODO(b/111276913): implement
- return 108;
+ return mTaskId;
}
/**
* Gets the activity associated with this context.
*/
public @NonNull ComponentName getActivityComponent() {
- //TODO(b/111276913): implement
- return null;
+ return mComponentName;
}
/**
@@ -79,8 +92,7 @@
* {G android.hardware.display.DisplayManager#getDisplay(int) DisplayManager.getDisplay()}.
*/
public int getDisplayId() {
- //TODO(b/111276913): implement
- return 42;
+ return mDisplayId;
}
/**
@@ -90,8 +102,26 @@
* {@link #FLAG_DISABLED_BY_APP}.
*/
public @ContextCreationFlags int getFlags() {
- //TODO(b/111276913): implement
- return 42;
+ return mFlags;
+ }
+
+ /**
+ * @hide
+ */
+ // TODO(b/111276913): dump to proto as well
+ public void dump(PrintWriter pw) {
+ pw.print("comp="); pw.print(mComponentName.flattenToShortString());
+ pw.print(", taskId="); pw.print(mTaskId);
+ pw.print(", displayId="); pw.print(mDisplayId);
+ if (mFlags > 0) {
+ pw.print(", flags="); pw.print(mFlags);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Context[act=" + mComponentName.flattenToShortString() + ", taskId=" + mTaskId
+ + ", displayId=" + mDisplayId + ", flags=" + mFlags + "]";
}
@Override
@@ -101,6 +131,10 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mComponentName, flags);
+ parcel.writeInt(mTaskId);
+ parcel.writeInt(mDisplayId);
+ parcel.writeInt(mFlags);
}
public static final Parcelable.Creator<InteractionContext> CREATOR =
@@ -108,8 +142,11 @@
@Override
public InteractionContext createFromParcel(Parcel parcel) {
- // TODO(b/111276913): implement
- return null;
+ final ComponentName componentName = parcel.readParcelable(null);
+ final int taskId = parcel.readInt();
+ final int displayId = parcel.readInt();
+ final int flags = parcel.readInt();
+ return new InteractionContext(componentName, taskId, displayId, flags);
}
@Override
diff --git a/core/java/android/service/intelligence/InteractionSessionId.aidl b/core/java/android/service/intelligence/InteractionSessionId.aidl
new file mode 100644
index 0000000..a5392b6
--- /dev/null
+++ b/core/java/android/service/intelligence/InteractionSessionId.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018, 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.service.intelligence;
+
+parcelable InteractionSessionId;
diff --git a/core/java/android/service/intelligence/InteractionSessionId.java b/core/java/android/service/intelligence/InteractionSessionId.java
index 4c9d706..667193b 100644
--- a/core/java/android/service/intelligence/InteractionSessionId.java
+++ b/core/java/android/service/intelligence/InteractionSessionId.java
@@ -16,17 +16,85 @@
package android.service.intelligence;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.io.PrintWriter;
+import java.util.UUID;
+
// TODO(b/111276913): add javadocs / implement equals/hashcode/string
/** @hide */
@SystemApi
public final class InteractionSessionId implements Parcelable {
- /** @hide */
+ private final @NonNull String mValue;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
public InteractionSessionId() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param value The internal value.
+ *
+ * @hide
+ */
+ public InteractionSessionId(@NonNull String value) {
+ mValue = value;
+ }
+
+ /**
+ * @hide
+ */
+ public String getValue() {
+ return mValue;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final InteractionSessionId other = (InteractionSessionId) obj;
+ if (mValue == null) {
+ if (other.mValue != null) return false;
+ } else if (!mValue.equals(other.mValue)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>NOTE: </b>this method is only useful for debugging purposes and is not guaranteed to
+ * be stable, hence it should not be used to identify the session.
+ */
+ @Override
+ public String toString() {
+ return mValue;
+ }
+
+ /** @hide */
+ // TODO(b/111276913): dump to proto as well
+ public void dump(PrintWriter pw) {
+ pw.print(mValue);
}
@Override
@@ -36,6 +104,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mValue);
}
public static final Parcelable.Creator<InteractionSessionId> CREATOR =
@@ -43,8 +112,7 @@
@Override
public InteractionSessionId createFromParcel(Parcel parcel) {
- // TODO(b/111276913): implement
- return null;
+ return new InteractionSessionId(parcel.readString());
}
@Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 769dd1b..b047ef7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,7 +42,6 @@
private static final Map<String, String> DEFAULT_FLAGS;
static {
DEFAULT_FLAGS = new HashMap<>();
- DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f8bdfe2..5c07f44 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -111,9 +111,6 @@
// caller must call setNewConfiguration() sometime later.
Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
IBinder freezeThisOneIfNeeded, int displayId);
- // Notify window manager of the new display override configuration. Returns an array of stack
- // ids that were affected by the update, ActivityManager should resize these stacks.
- int[] setNewDisplayOverrideConfiguration(in Configuration overrideConfig, int displayId);
void startFreezingScreen(int exitAnim, int enterAnim);
void stopFreezingScreen();
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 0a3403b..7e5c149 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -2523,10 +2523,11 @@
}
/**
- * Retrieve the repeat count of the event. For both key up and key down
- * events, this is the number of times the key has repeated with the first
- * down starting at 0 and counting up from there. For multiple key
- * events, this is the number of down/up pairs that have occurred.
+ * Retrieve the repeat count of the event. For key down events,
+ * this is the number of times the key has repeated with the first
+ * down starting at 0 and counting up from there. For key up events,
+ * this is always equal to zero. For multiple key events,
+ * this is the number of down/up pairs that have occurred.
*
* @return The number of times the key has repeated.
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 43fcce3..453d788 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9852,12 +9852,12 @@
// We weren't called from within a direct call to fitSystemWindows,
// call into it as a fallback in case we're in a class that overrides it
// and has logic to perform.
- if (fitSystemWindows(insets.getSystemWindowInsets())) {
+ if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) {
return insets.consumeSystemWindowInsets();
}
} else {
// We were called from within a direct call to fitSystemWindows.
- if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+ if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) {
return insets.consumeSystemWindowInsets();
}
}
@@ -9960,7 +9960,7 @@
protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets),
outLocalInsets);
- inoutInsets.set(innerInsets.getSystemWindowInsets());
+ inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect());
return innerInsets.isSystemWindowInsetsConsumed();
}
@@ -9979,7 +9979,7 @@
|| mAttachInfo == null
|| ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
&& !mAttachInfo.mOverscanRequested)) {
- outLocalInsets.set(in.getSystemWindowInsets());
+ outLocalInsets.set(in.getSystemWindowInsetsAsRect());
return in.consumeSystemWindowInsets().inset(outLocalInsets);
} else {
// The application wants to take care of fitting system window for
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 8628da3..4a7e783 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,8 +17,10 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.graphics.Insets;
import android.graphics.Rect;
import com.android.internal.util.Preconditions;
@@ -43,26 +45,24 @@
*/
public final class WindowInsets {
- private Rect mSystemWindowInsets;
- private Rect mWindowDecorInsets;
- private Rect mStableInsets;
- private Rect mTempRect;
- private boolean mIsRound;
- private DisplayCutout mDisplayCutout;
+ @NonNull private final Insets mSystemWindowInsets;
+ @NonNull private final Insets mWindowDecorInsets;
+ @NonNull private final Insets mStableInsets;
+ @Nullable private Rect mTempRect;
+ private final boolean mIsRound;
+ @Nullable private final DisplayCutout mDisplayCutout;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
* changes in this mode, we instead have a flag whether the navigation bar size should always
* be consumed, so the app is treated like there is no virtual navigation bar at all.
*/
- private boolean mAlwaysConsumeNavBar;
+ private final boolean mAlwaysConsumeNavBar;
- private boolean mSystemWindowInsetsConsumed = false;
- private boolean mWindowDecorInsetsConsumed = false;
- private boolean mStableInsetsConsumed = false;
- private boolean mDisplayCutoutConsumed = false;
-
- private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+ private final boolean mSystemWindowInsetsConsumed;
+ private final boolean mWindowDecorInsetsConsumed;
+ private final boolean mStableInsetsConsumed;
+ private final boolean mDisplayCutoutConsumed;
/**
* Since new insets may be added in the future that existing apps couldn't
@@ -74,21 +74,27 @@
public static final WindowInsets CONSUMED;
static {
- CONSUMED = new WindowInsets(null, null, null, false, false, null);
+ CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null);
}
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
+ this(Insets.of(systemWindowInsets), Insets.of(windowDecorInsets), Insets.of(stableInsets),
+ isRound, alwaysConsumeNavBar, displayCutout);
+ }
+
+ private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets,
+ Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar,
+ DisplayCutout displayCutout) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
- mSystemWindowInsets = mSystemWindowInsetsConsumed
- ? EMPTY_RECT : new Rect(systemWindowInsets);
+ mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets;
mWindowDecorInsetsConsumed = windowDecorInsets == null;
- mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets);
+ mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets;
mStableInsetsConsumed = stableInsets == null;
- mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets);
+ mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets;
mIsRound = isRound;
mAlwaysConsumeNavBar = alwaysConsumeNavBar;
@@ -104,16 +110,21 @@
* @param src Source to copy insets from
*/
public WindowInsets(WindowInsets src) {
- mSystemWindowInsets = src.mSystemWindowInsets;
- mWindowDecorInsets = src.mWindowDecorInsets;
- mStableInsets = src.mStableInsets;
- mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
- mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
- mStableInsetsConsumed = src.mStableInsetsConsumed;
- mIsRound = src.mIsRound;
- mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
- mDisplayCutout = src.mDisplayCutout;
- mDisplayCutoutConsumed = src.mDisplayCutoutConsumed;
+ this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets,
+ src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets,
+ src.mStableInsetsConsumed ? null : src.mStableInsets,
+ src.mIsRound, src.mAlwaysConsumeNavBar,
+ displayCutoutCopyConstructorArgument(src));
+ }
+
+ private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
+ if (w.mDisplayCutoutConsumed) {
+ return null;
+ } else if (w.mDisplayCutout == null) {
+ return DisplayCutout.NO_CUTOUT;
+ } else {
+ return w.mDisplayCutout;
+ }
}
/** @hide */
@@ -126,22 +137,35 @@
* Used to provide a safe copy of the system window insets to pass through
* to the existing fitSystemWindows method and other similar internals.
* @hide
+ *
+ * @deprecated use {@link #getSystemWindowInsets()} instead.
*/
- @UnsupportedAppUsage
- public Rect getSystemWindowInsets() {
+ @Deprecated
+ @NonNull
+ public Rect getSystemWindowInsetsAsRect() {
if (mTempRect == null) {
mTempRect = new Rect();
}
- if (mSystemWindowInsets != null) {
- mTempRect.set(mSystemWindowInsets);
- } else {
- // If there were no system window insets, this is just empty.
- mTempRect.setEmpty();
- }
+ mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top,
+ mSystemWindowInsets.right, mSystemWindowInsets.bottom);
return mTempRect;
}
/**
+ * Returns the system window insets in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The system window insets
+ */
+ @NonNull
+ public Insets getSystemWindowInsets() {
+ return mSystemWindowInsets;
+ }
+
+ /**
* Returns the left system window inset in pixels.
*
* <p>The system window inset represents the area of a full-screen window that is
@@ -304,11 +328,13 @@
*
* @return A modified copy of this WindowInsets
*/
+ @NonNull
public WindowInsets consumeDisplayCutout() {
- final WindowInsets result = new WindowInsets(this);
- result.mDisplayCutout = null;
- result.mDisplayCutoutConsumed = true;
- return result;
+ return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+ mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+ mStableInsetsConsumed ? null : mStableInsets,
+ mIsRound, mAlwaysConsumeNavBar,
+ null /* displayCutout */);
}
@@ -349,101 +375,95 @@
*
* @return A modified copy of this WindowInsets
*/
+ @NonNull
public WindowInsets consumeSystemWindowInsets() {
- final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = EMPTY_RECT;
- result.mSystemWindowInsetsConsumed = true;
- return result;
+ return new WindowInsets(null /* systemWindowInsets */,
+ mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+ mStableInsetsConsumed ? null : mStableInsets,
+ mIsRound, mAlwaysConsumeNavBar,
+ displayCutoutCopyConstructorArgument(this));
}
- /**
- * Returns a copy of this WindowInsets with selected system window insets fully consumed.
- *
- * @param left true to consume the left system window inset
- * @param top true to consume the top system window inset
- * @param right true to consume the right system window inset
- * @param bottom true to consume the bottom system window inset
- * @return A modified copy of this WindowInsets
- * @hide pending API
- */
- public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
- boolean right, boolean bottom) {
- if (left || top || right || bottom) {
- final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(
- left ? 0 : mSystemWindowInsets.left,
- top ? 0 : mSystemWindowInsets.top,
- right ? 0 : mSystemWindowInsets.right,
- bottom ? 0 : mSystemWindowInsets.bottom);
- return result;
- }
- return this;
- }
-
+ // TODO(b/119190588): replace @code with @link below
/**
* Returns a copy of this WindowInsets with selected system window insets replaced
* with new values.
*
+ * <p>Note: If the system window insets are already consumed, this method will return them
+ * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
+ * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
+ * whether they were consumed, and this method returns invalid non-zero consumed insets.
+ *
* @param left New left inset in pixels
* @param top New top inset in pixels
* @param right New right inset in pixels
* @param bottom New bottom inset in pixels
* @return A modified copy of this WindowInsets
+ * @deprecated use {@code Builder#Builder(WindowInsets)} with
+ * {@link Builder#setSystemWindowInsets(Insets)} instead.
*/
- public WindowInsets replaceSystemWindowInsets(int left, int top,
- int right, int bottom) {
- final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(left, top, right, bottom);
- return result;
+ @Deprecated
+ @NonNull
+ public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
+ // Compat edge case: what should this do if the insets have already been consumed?
+ // On platforms prior to Q, the behavior was to override the insets with non-zero values,
+ // but leave them consumed, which is invalid (consumed insets must be zero).
+ // The behavior is now keeping them consumed and discarding the new insets.
+ if (mSystemWindowInsetsConsumed) {
+ return this;
+ }
+ return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
}
+ // TODO(b/119190588): replace @code with @link below
/**
* Returns a copy of this WindowInsets with selected system window insets replaced
* with new values.
*
+ * <p>Note: If the system window insets are already consumed, this method will return them
+ * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
+ * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
+ * whether they were consumed, and this method returns invalid non-zero consumed insets.
+ *
* @param systemWindowInsets New system window insets. Each field is the inset in pixels
* for that edge
* @return A modified copy of this WindowInsets
+ * @deprecated use {@code Builder#Builder(WindowInsets)} with
+ * {@link Builder#setSystemWindowInsets(Insets)} instead.
*/
+ @Deprecated
+ @NonNull
public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
- final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(systemWindowInsets);
- return result;
+ return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
+ systemWindowInsets.right, systemWindowInsets.bottom);
}
/**
* @hide
*/
+ @NonNull
public WindowInsets consumeWindowDecorInsets() {
- final WindowInsets result = new WindowInsets(this);
- result.mWindowDecorInsets.set(0, 0, 0, 0);
- result.mWindowDecorInsetsConsumed = true;
- return result;
+ return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+ null /* windowDecorInsets */,
+ mStableInsetsConsumed ? null : mStableInsets,
+ mIsRound, mAlwaysConsumeNavBar,
+ displayCutoutCopyConstructorArgument(this));
}
/**
- * @hide
+ * Returns the stable insets in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @return The stable insets
*/
- public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
- boolean right, boolean bottom) {
- if (left || top || right || bottom) {
- final WindowInsets result = new WindowInsets(this);
- result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
- top ? 0 : mWindowDecorInsets.top,
- right ? 0 : mWindowDecorInsets.right,
- bottom ? 0 : mWindowDecorInsets.bottom);
- return result;
- }
- return this;
- }
-
- /**
- * @hide
- */
- public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
- final WindowInsets result = new WindowInsets(this);
- result.mWindowDecorInsets = new Rect(left, top, right, bottom);
- return result;
+ @NonNull
+ public Insets getStableInsets() {
+ return mStableInsets;
}
/**
@@ -527,11 +547,13 @@
*
* @return A modified copy of this WindowInsets
*/
+ @NonNull
public WindowInsets consumeStableInsets() {
- final WindowInsets result = new WindowInsets(this);
- result.mStableInsets = EMPTY_RECT;
- result.mStableInsetsConsumed = true;
- return result;
+ return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
+ mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
+ null /* stableInsets */,
+ mIsRound, mAlwaysConsumeNavBar,
+ displayCutoutCopyConstructorArgument(this));
}
/**
@@ -555,8 +577,11 @@
* Returns a copy of this instance inset in the given directions.
*
* @see #inset(int, int, int, int)
+ * @deprecated use {@link #inset(Insets)}
* @hide
*/
+ @Deprecated
+ @NonNull
public WindowInsets inset(Rect r) {
return inset(r.left, r.top, r.right, r.bottom);
}
@@ -564,6 +589,17 @@
/**
* Returns a copy of this instance inset in the given directions.
*
+ * @see #inset(int, int, int, int)
+ * @hide
+ */
+ @NonNull
+ public WindowInsets inset(Insets insets) {
+ return inset(insets.left, insets.top, insets.right, insets.bottom);
+ }
+
+ /**
+ * Returns a copy of this instance inset in the given directions.
+ *
* This is intended for dispatching insets to areas of the window that are smaller than the
* current area.
*
@@ -579,35 +615,27 @@
* @param bottom the amount of insets to remove from the bottom. Must be non-negative.
*
* @return the inset insets
- *
- * @hide pending API
*/
- @UnsupportedAppUsage
+ @NonNull
public WindowInsets inset(int left, int top, int right, int bottom) {
Preconditions.checkArgumentNonnegative(left);
Preconditions.checkArgumentNonnegative(top);
Preconditions.checkArgumentNonnegative(right);
Preconditions.checkArgumentNonnegative(bottom);
- WindowInsets result = new WindowInsets(this);
- if (!result.mSystemWindowInsetsConsumed) {
- result.mSystemWindowInsets =
- insetInsets(result.mSystemWindowInsets, left, top, right, bottom);
- }
- if (!result.mWindowDecorInsetsConsumed) {
- result.mWindowDecorInsets =
- insetInsets(result.mWindowDecorInsets, left, top, right, bottom);
- }
- if (!result.mStableInsetsConsumed) {
- result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom);
- }
- if (mDisplayCutout != null) {
- result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom);
- if (result.mDisplayCutout.isEmpty()) {
- result.mDisplayCutout = null;
- }
- }
- return result;
+ return new WindowInsets(
+ mSystemWindowInsetsConsumed ? null :
+ insetInsets(mSystemWindowInsets, left, top, right, bottom),
+ mWindowDecorInsetsConsumed ? null :
+ insetInsets(mWindowDecorInsets, left, top, right, bottom),
+ mStableInsetsConsumed ? null :
+ insetInsets(mStableInsets, left, top, right, bottom),
+ mIsRound, mAlwaysConsumeNavBar,
+ mDisplayCutoutConsumed
+ ? null :
+ mDisplayCutout == null
+ ? DisplayCutout.NO_CUTOUT
+ : mDisplayCutout.inset(left, top, right, bottom));
}
@Override
@@ -634,7 +662,7 @@
mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
}
- private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) {
+ private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
int newLeft = Math.max(0, insets.left - left);
int newTop = Math.max(0, insets.top - top);
int newRight = Math.max(0, insets.right - right);
@@ -642,7 +670,7 @@
if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
return insets;
}
- return new Rect(newLeft, newTop, newRight, newBottom);
+ return Insets.of(newLeft, newTop, newRight, newBottom);
}
/**
@@ -651,4 +679,122 @@
boolean isSystemWindowInsetsConsumed() {
return mSystemWindowInsetsConsumed;
}
+
+ /**
+ * Builder for WindowInsets.
+ */
+ public static class Builder {
+
+ private Insets mSystemWindowInsets;
+ private Insets mStableInsets;
+ private DisplayCutout mDisplayCutout;
+
+ private Insets mWindowDecorInsets;
+ private boolean mIsRound;
+ private boolean mAlwaysConsumeNavBar;
+
+ /**
+ * Creates a builder where all insets are initially consumed.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Creates a builder where all insets are initialized from {@link WindowInsets}.
+ *
+ * @param insets the instance to initialize from.
+ */
+ public Builder(WindowInsets insets) {
+ mSystemWindowInsets = insets.mSystemWindowInsetsConsumed ? null
+ : insets.mSystemWindowInsets;
+ mStableInsets = insets.mStableInsetsConsumed ? null : insets.mStableInsets;
+ mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
+ mWindowDecorInsets = insets.mWindowDecorInsetsConsumed ? null
+ : insets.mWindowDecorInsets;
+ mIsRound = insets.mIsRound;
+ mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
+ }
+
+ /**
+ * Sets system window insets in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system
+ * windows.</p>
+ *
+ * @see #getSystemWindowInsets()
+ * @return itself
+ */
+ @NonNull
+ public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
+ Preconditions.checkNotNull(systemWindowInsets);
+ mSystemWindowInsets = systemWindowInsets;
+ return this;
+ }
+
+ /**
+ * Sets the stable insets in pixels.
+ *
+ * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
+ * partially or fully obscured by the system UI elements. This value does not change
+ * based on the visibility state of those elements; for example, if the status bar is
+ * normally shown, but temporarily hidden, the stable inset will still provide the inset
+ * associated with the status bar being shown.</p>
+ *
+ * @see #getStableInsets()
+ * @return itself
+ */
+ @NonNull
+ public Builder setStableInsets(@NonNull Insets stableInsets) {
+ Preconditions.checkNotNull(stableInsets);
+ mStableInsets = stableInsets;
+ return this;
+ }
+
+ /**
+ * Sets the display cutout.
+ *
+ * @see #getDisplayCutout()
+ * @param displayCutout the display cutout or null if there is none
+ * @return itself
+ */
+ @NonNull
+ public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
+ mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
+ public Builder setWindowDecorInsets(@NonNull Insets windowDecorInsets) {
+ Preconditions.checkNotNull(windowDecorInsets);
+ mWindowDecorInsets = windowDecorInsets;
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
+ public Builder setRound(boolean round) {
+ mIsRound = round;
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
+ public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) {
+ mAlwaysConsumeNavBar = alwaysConsumeNavBar;
+ return this;
+ }
+
+ /**
+ * Builds a {@link WindowInsets} instance.
+ *
+ * @return the {@link WindowInsets} instance.
+ */
+ @NonNull
+ public WindowInsets build() {
+ return new WindowInsets(mSystemWindowInsets, mWindowDecorInsets, mStableInsets,
+ mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
+ }
+ }
}
diff --git a/core/java/android/view/inspector/ChildTraverser.java b/core/java/android/view/inspector/ChildTraverser.java
new file mode 100644
index 0000000..b775de5
--- /dev/null
+++ b/core/java/android/view/inspector/ChildTraverser.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface for visiting all the child nodes of an inspectable object.
+ *
+ * Inspectable objects may return a collection of children as an array, an {@link Iterable} or an
+ * {@link java.util.Iterator}. This provides a unified API for traversing across all the children
+ * of an inspectable node.
+ *
+ * This interface is consumed by {@link InspectionHelper#traverseChildren(Object, ChildTraverser)}
+ * and may be implemented as a lambda.
+ *
+ * @see InspectionHelper#traverseChildren(Object, ChildTraverser)
+ * @hide
+ */
+@FunctionalInterface
+public interface ChildTraverser {
+ /**
+ * Visit one child object of a parent inspectable object.
+ *
+ * The iteration interface will filter null values out before passing them to this method, but
+ * some child objects may not be inspectable. It is up to the implementor to determine their
+ * inspectablity and what to do with them.
+ *
+ * @param child A child object, guaranteed not to be null.
+ */
+ void traverseChild(@NonNull Object child);
+}
diff --git a/core/java/android/view/inspector/InspectableChildren.java b/core/java/android/view/inspector/InspectableChildren.java
new file mode 100644
index 0000000..de8fa29
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableChildren.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter for an inspectable node's inspectable children.
+ *
+ * This annotation can be applied to any getter that returns a collection of objects, either an
+ * array, an {@link Iterable} or a {@link java.util.Iterator}. The getter may return null, which
+ * will be treated as an empty collection. Additionally, the inspector will discard any null
+ * entries in the collection.
+ *
+ * By default, this annotation is inherited. At runtime, the inspector introspects on the class
+ * hierachy and uses the annotated getter from the bottommost class, if different from any
+ * annoated getters of the parent class. If a class inherits from a parent class with an annotated
+ * getter, but does not include this annotation, the child class will be traversed using the
+ * getter annotated on the parent. This holds true even if the child class overrides the getter.
+ *
+ * @see InspectionHelper#traverseChildren(Object, ChildTraverser)
+ * @see InspectionHelper#hasChildTraversal()
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableChildren {
+}
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
new file mode 100644
index 0000000..716409c
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableNodeName.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks the node name to display to a developer in the inspection tree.
+ *
+ * This annotation is optional to marking a class as inspectable. If it is omitted, the node name
+ * will be inferred using the semantics of {@link Class#getSimpleName()}. The fully qualified class
+ * name is always available in the tree, this is for display purposes only. If a class is inflated
+ * from XML and the tag it inflates from does not match its simple name, this annotation should be
+ * used to inform the inspector to display the XML tag name in the inspection tree view.
+ *
+ * This annotation does not inherit. If a class extends an annotated parent class, but does not
+ * annotate itself, its node name will be inferred from its Java name.
+ *
+ * @see InspectionHelper#getNodeName()
+ * @hide
+ */
+@Target({TYPE})
+@Retention(SOURCE)
+public @interface InspectableNodeName {
+ /**
+ * The display name for nodes of this type.
+ *
+ * @return The name for nodes of this type
+ */
+ String value();
+}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
new file mode 100644
index 0000000..b0fd503
--- /dev/null
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a getter of a property on an inspectable node.
+ *
+ * This annotation is inherited by default. If a child class doesn't add it to a getter, but a
+ * parent class does, the property will be inspected, even if the child overrides the definition
+ * of the getter. If a child class defines a property of the same name of a property on the parent
+ * but on a different getter, the inspector will use the child's getter when inspecting instances
+ * of the child, and the parent's otherwise.
+ *
+ * @see InspectionHelper#mapProperties(PropertyMapper)
+ * @see InspectionHelper#readProperties(Object, PropertyReader)
+ * @hide
+ */
+@Target({METHOD})
+@Retention(SOURCE)
+public @interface InspectableProperty {
+ /**
+ * The name of the property.
+ *
+ * If left empty (the default), the property name will be inferred from the name of the getter
+ * method.
+ *
+ * @return The name of the property.
+ */
+ String value() default "";
+}
diff --git a/core/java/android/view/inspector/InspectionHelper.java b/core/java/android/view/inspector/InspectionHelper.java
new file mode 100644
index 0000000..27a9704
--- /dev/null
+++ b/core/java/android/view/inspector/InspectionHelper.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An interface for companion objects used to inspect views.
+ *
+ * Inspection helpers only need to handle the properties, name and traversal of the specific class
+ * they are defined for, not anything from a parent class. At runtime, the inspector instantiates
+ * one instance of each inspection helper, and handles visiting them in the correct inheritance
+ * order for each type it inspects.
+ *
+ * Properties are read from the top of the type tree to the bottom, so that classes that override
+ * a property in their parent class can overwrite it in the reader. In general, properties will
+ * cleanly inherit through their getters, and the inspector runtime will read the properties of a
+ * parent class via the parent's inspection helper, and the child helper will only read properties
+ * added or changed since the parent was defined.
+ *
+ * Only one child traversal is considered for each class. If a descendant class defines a
+ * different child traversal than its parent, only the bottom traversal is used. If a class does
+ * not define its own child traversal, but one of its ancestors does, the bottom-most ancestor's
+ * traversal will be used.
+ *
+ * @param <T> The type of inspectable this helper operates on
+ * @hide
+ */
+public interface InspectionHelper<T> {
+ /**
+ * Map the string names of the properties this helper knows about to integer IDs.
+ *
+ * Each helper is responsible for storing the integer IDs of all its properties. This is the
+ * only method that is allowed to modify the stored IDs.
+ *
+ * Calling {@link #readProperties(T, PropertyReader)} before calling this results in
+ * undefined behavior.
+ *
+ * @param propertyMapper A {@link PropertyMapper} or lambda which maps string names to IDs.
+ */
+ void mapProperties(@NonNull PropertyMapper propertyMapper);
+
+ /**
+ * Read the values of an instance of this helper's type into a {@link PropertyReader}.
+ *
+ * This method needs to return the property IDs stored by
+ * {@link #mapProperties(PropertyMapper)}. Implementations should track if their properties
+ * have been mapped and throw a {@link UninitializedPropertyMapException} if this method is
+ * called before {mapProperties}.
+ *
+ * @param inspectable A object of type {@link T} to read the properties of.
+ * @param propertyReader An object which receives the property IDs and values.
+ */
+ void readProperties(@NonNull T inspectable, @NonNull PropertyReader propertyReader);
+
+ /**
+ * Query if this inspectable type can potentially have child nodes.
+ *
+ * E.g.: any descendant of {@link android.view.ViewGroup} can have child nodes, but a leaf
+ * view like {@link android.widget.ImageView} may not.
+ *
+ * The default implementation always returns false. If an implementing class overrides this, it
+ * should also define {@link #traverseChildren(T, ChildTraverser)}.
+ *
+ * @return True if this inspectable type can potentially have child nodes, false otherwise.
+ */
+ default boolean hasChildTraversal() {
+ return false;
+ }
+
+ /**
+ * Traverse the child nodes of an instance of this helper's type into a {@link ChildTraverser}.
+ *
+ * This provides the ability to traverse over a variety of collection APIs (e.g.: arrays,
+ * {@link Iterable}, or {@link java.util.Iterator}) in a uniform fashion. The traversal must be
+ * in the order defined by this helper's type. If the getter returns null, the helper must
+ * treat it as an empty collection.
+ *
+ * The default implementation throws a {@link NoChildTraversalException}. If
+ * {@link #hasChildTraversal()} returns is overriden to return true, it is expected that the
+ * implementing class will also override this method and provide a traversal.
+ *
+ * @param inspectable An object of type {@link T} to traverse the child nodes of.
+ * @param childTraverser A {@link ChildTraverser} or lamba to receive the children in order.
+ * @throws NoChildTraversalException If there is no defined child traversal
+ */
+ default void traverseChildren(
+ @NonNull T inspectable,
+ @SuppressWarnings("unused") @NonNull ChildTraverser childTraverser) {
+ throw new NoChildTraversalException(inspectable.getClass());
+ }
+
+ /**
+ * Get an optional name to display to developers for inspection nodes of this helper's type.
+ *
+ * The default implementation returns null, which will cause the runtime to use the class's
+ * simple name as defined by {@link Class#getSimpleName()} as the node name.
+ *
+ * If the type of this helper is inflated from XML, this method should be overridden to return
+ * the string used as the tag name for this type in XML.
+ *
+ * @return A string to use as the node name, or null to use the simple class name fallback.
+ */
+ @Nullable
+ default String getNodeName() {
+ return null;
+ }
+
+ /**
+ * Thrown by {@link #readProperties(Object, PropertyReader)} if called before
+ * {@link #mapProperties(PropertyMapper)}.
+ */
+ class UninitializedPropertyMapException extends RuntimeException {
+ public UninitializedPropertyMapException() {
+ super("Unable to read properties of an inspectable before mapping their IDs.");
+ }
+ }
+
+ /**
+ * Thrown by {@link #traverseChildren(Object, ChildTraverser)} if no child traversal exists.
+ */
+ class NoChildTraversalException extends RuntimeException {
+ public NoChildTraversalException(Class cls) {
+ super(String.format(
+ "Class %s does not have a defined child traversal. Cannot traverse children.",
+ cls.getCanonicalName()
+ ));
+ }
+ }
+}
diff --git a/core/java/android/view/inspector/OWNERS b/core/java/android/view/inspector/OWNERS
new file mode 100644
index 0000000..0473f54
--- /dev/null
+++ b/core/java/android/view/inspector/OWNERS
@@ -0,0 +1,3 @@
+alanv@google.com
+ashleyrose@google.com
+aurimas@google.com
\ No newline at end of file
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
new file mode 100644
index 0000000..35550bd
--- /dev/null
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import android.annotation.NonNull;
+
+/**
+ * An interface for mapping the string names of inspectable properties to integer identifiers.
+ *
+ * This interface is consumed by {@link InspectionHelper#mapProperties(PropertyMapper)}.
+ *
+ * Mapping properties to IDs enables quick comparisons against shadow copies of inspectable
+ * objects without performing a large number of string comparisons.
+ *
+ * @see InspectionHelper#mapProperties(PropertyMapper)
+ * @hide
+ */
+public interface PropertyMapper {
+ /**
+ * Map a string name to an integer ID for a primitive boolean property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapBoolean(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive byte property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapByte(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive char property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapChar(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive double property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapDouble(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive float property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapFloat(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive int property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapInt(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive long property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapLong(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for a primitive short property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapShort(@NonNull String name);
+
+ /**
+ * Map a string name to an integer ID for an object property.
+ *
+ * @param name The name of the property
+ * @return An integer ID for the property
+ * @throws PropertyConflictException If the property name is already mapped as another type.
+ */
+ int mapObject(@NonNull String name);
+
+ /**
+ * Thrown from a map method if a property name is already mapped as different type.
+ */
+ class PropertyConflictException extends RuntimeException {
+ public PropertyConflictException(
+ @NonNull String name,
+ @NonNull String newPropertyType,
+ @NonNull String existingPropertyType) {
+ super(String.format(
+ "Attempted to map property \"%s\" as type %s, but it is already mapped as %s.",
+ name,
+ newPropertyType,
+ existingPropertyType
+ ));
+ }
+ }
+}
diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java
new file mode 100644
index 0000000..df81c10
--- /dev/null
+++ b/core/java/android/view/inspector/PropertyReader.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 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.view.inspector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * An interface for reading the properties of an inspectable object.
+ *
+ * Used as the parameter for {@link InspectionHelper#readProperties(Object, PropertyReader)}.
+ * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
+ * implementation is able to work with primitives. Implementations should be prepared to accept
+ * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
+ *
+ * @see InspectionHelper#readProperties(Object, PropertyReader)
+ * @hide
+ */
+public interface PropertyReader {
+ /**
+ * Read a primitive boolean property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean}
+ */
+ void readBoolean(int id, boolean value);
+
+ /**
+ * Read a primitive byte property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte}
+ */
+ void readByte(int id, byte value);
+
+ /**
+ * Read a primitive character property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char}
+ */
+ void readChar(int id, char value);
+
+ /**
+ * Read a read a primitive double property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double}
+ */
+ void readDouble(int id, double value);
+
+ /**
+ * Read a primitive float property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float}
+ */
+ void readFloat(int id, float value);
+
+ /**
+ * Read a primitive integer property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int}
+ */
+ void readInt(int id, int value);
+
+ /**
+ * Read a primitive long property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long}
+ */
+ void readLong(int id, long value);
+
+ /**
+ * Read a primitive short property.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short}
+ */
+ void readShort(int id, short value);
+
+ /**
+ * Read any object as a property.
+ *
+ * If value is null, the property is marked as empty.
+ *
+ * @param id Identifier of the property from a {@link PropertyMapper}
+ * @param value Value of the property
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
+ */
+ void readObject(int id, @Nullable Object value);
+
+ /**
+ * Thrown if a client calls a typed read method for a property of a different type.
+ */
+ class PropertyTypeMismatchException extends RuntimeException {
+ public PropertyTypeMismatchException(
+ int id,
+ @NonNull String expectedPropertyType,
+ @NonNull String actualPropertyType,
+ @Nullable String propertyName) {
+ super(formatMessage(id, expectedPropertyType, actualPropertyType, propertyName));
+ }
+
+ public PropertyTypeMismatchException(
+ int id,
+ @NonNull String expectedPropertyType,
+ @NonNull String actualPropertyType) {
+ super(formatMessage(id, expectedPropertyType, actualPropertyType, null));
+ }
+
+ private static @NonNull String formatMessage(
+ int id,
+ @NonNull String expectedPropertyType,
+ @NonNull String actualPropertyType,
+ @Nullable String propertyName) {
+
+ if (propertyName == null) {
+ return String.format(
+ "Attempted to read property with ID 0x%08X as type %s, "
+ + "but the ID is of type %s.",
+ id,
+ expectedPropertyType,
+ actualPropertyType
+ );
+ } else {
+ return String.format(
+ "Attempted to read property \"%s\" with ID 0x%08X as type %s, "
+ + "but the ID is of type %s.",
+ propertyName,
+ id,
+ expectedPropertyType,
+ actualPropertyType
+ );
+ }
+ }
+ }
+}
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.aidl b/core/java/android/view/intelligence/ContentCaptureEvent.aidl
new file mode 100644
index 0000000..c66a6cb
--- /dev/null
+++ b/core/java/android/view/intelligence/ContentCaptureEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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.view.intelligence;
+
+parcelable ContentCaptureEvent;
diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.java b/core/java/android/view/intelligence/ContentCaptureEvent.java
index b8330e5..2530ae3 100644
--- a/core/java/android/view/intelligence/ContentCaptureEvent.java
+++ b/core/java/android/view/intelligence/ContentCaptureEvent.java
@@ -30,6 +30,11 @@
@SystemApi
public final class ContentCaptureEvent implements Parcelable {
+ /** @hide */
+ public static final int TYPE_ACTIVITY_DESTROYED = -2;
+ /** @hide */
+ public static final int TYPE_ACTIVITY_CREATED = -1;
+
/**
* Called when the activity is started.
*/
@@ -85,10 +90,18 @@
TYPE_VIEW_TEXT_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
- @interface EventType{}
+ public @interface EventType{}
+
+ private final int mType;
+ private final long mEventTime;
+ private final int mFlags;
+
/** @hide */
- ContentCaptureEvent() {
+ public ContentCaptureEvent(int type, long eventTime, int flags) {
+ mType = type;
+ mEventTime = eventTime;
+ mFlags = flags;
}
/**
@@ -99,14 +112,14 @@
* {@link #TYPE_VIEW_ADDED}, {@link #TYPE_VIEW_REMOVED}, or {@link #TYPE_VIEW_TEXT_CHANGED}.
*/
public @EventType int getType() {
- return 42;
+ return mType;
}
/**
* Gets when the event was generated, in ms.
*/
public long getEventTime() {
- return 48151623;
+ return mEventTime;
}
/**
@@ -116,7 +129,7 @@
* {@link android.view.intelligence.IntelligenceManager#FLAG_USER_INPUT}.
*/
public int getFlags() {
- return 0;
+ return mFlags;
}
/**
@@ -149,6 +162,15 @@
return null;
}
+ @Override
+ public String toString() {
+ final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
+ .append(getTypeAsString(mType)).append(", time=").append(mEventTime);
+ if (mFlags > 0) {
+ string.append(", flags=").append(mFlags);
+ }
+ return string.append(']').toString();
+ }
@Override
public int describeContents() {
@@ -157,6 +179,9 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mType);
+ parcel.writeLong(mEventTime);
+ parcel.writeInt(mFlags);
}
public static final Parcelable.Creator<ContentCaptureEvent> CREATOR =
@@ -164,8 +189,10 @@
@Override
public ContentCaptureEvent createFromParcel(Parcel parcel) {
- // TODO(b/111276913): implement
- return null;
+ final int type = parcel.readInt();
+ final long eventTime = parcel.readLong();
+ final int flags = parcel.readInt();
+ return new ContentCaptureEvent(type, eventTime, flags);
}
@Override
@@ -173,4 +200,27 @@
return new ContentCaptureEvent[size];
}
};
+
+
+ /** @hide */
+ public static String getTypeAsString(@EventType int type) {
+ switch (type) {
+ case TYPE_ACTIVITY_STARTED:
+ return "ACTIVITY_STARTED";
+ case TYPE_ACTIVITY_RESUMED:
+ return "ACTIVITY_RESUMED";
+ case TYPE_ACTIVITY_PAUSED:
+ return "ACTIVITY_PAUSED";
+ case TYPE_ACTIVITY_STOPPED:
+ return "ACTIVITY_STOPPED";
+ case TYPE_VIEW_ADDED:
+ return "VIEW_ADDED";
+ case TYPE_VIEW_REMOVED:
+ return "VIEW_REMOVED";
+ case TYPE_VIEW_TEXT_CHANGED:
+ return "VIEW_TEXT_CHANGED";
+ default:
+ return "UKNOWN_TYPE: " + type;
+ }
+ }
}
diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl
new file mode 100644
index 0000000..2f128de
--- /dev/null
+++ b/core/java/android/view/intelligence/IIntelligenceManager.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.view.intelligence;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.service.intelligence.InteractionSessionId;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+oneway interface IIntelligenceManager {
+ /**
+ * Starts a session, sending the "remote" sessionId to the receiver.
+ */
+ void startSession(int userId, IBinder activityToken, in ComponentName componentName,
+ in InteractionSessionId sessionId, int flags, in IResultReceiver result);
+
+ /**
+ * Finishes a session.
+ */
+ void finishSession(int userId, in InteractionSessionId sessionId);
+
+ /**
+ * Sends a batch of events
+ */
+ void sendEvents(int userId, in InteractionSessionId sessionId,
+ in List<ContentCaptureEvent> events);
+}
diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java
index 5513ce2f..9bf6c2c 100644
--- a/core/java/android/view/intelligence/IntelligenceManager.java
+++ b/core/java/android/view/intelligence/IntelligenceManager.java
@@ -18,29 +18,196 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.service.intelligence.InteractionSessionId;
+import android.util.Log;
+import android.view.intelligence.ContentCaptureEvent.EventType;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
import java.util.Set;
/**
- * TODO(b/111276913): add javadocs / implement / add SystemService / PackageFeature
+ * TODO(b/111276913): add javadocs / implement
*/
+@SystemService(Context.INTELLIGENCE_MANAGER_SERVICE)
public final class IntelligenceManager {
+ private static final String TAG = "IntelligenceManager";
+
+ // TODO(b/111276913): define a way to dynamically set it (for example, using settings?)
+ private static final boolean VERBOSE = false;
+
/**
* Used to indicate that a text change was caused by user input (for example, through IME).
*/
//TODO(b/111276913): link to notifyTextChanged() method once available
public static final int FLAG_USER_INPUT = 0x1;
+
+ /**
+ * Initial state, when there is no session.
+ *
+ * @hide
+ */
+ public static final int STATE_UNKNOWN = 0;
+
+ /**
+ * Service's startSession() was called, but server didn't confirm it was created yet.
+ *
+ * @hide
+ */
+ public static final int STATE_WAITING_FOR_SERVER = 1;
+
+ /**
+ * Session is active.
+ *
+ * @hide
+ */
+ public static final int STATE_ACTIVE = 2;
+
private final Context mContext;
+ @Nullable
+ private final IIntelligenceManager mService;
+
+ private final Object mLock = new Object();
+
+ @Nullable
+ @GuardedBy("mLock")
+ private InteractionSessionId mId;
+
+ @GuardedBy("mLock")
+ private int mState = STATE_UNKNOWN;
+
+ @GuardedBy("mLock")
+ private IBinder mApplicationToken;
+
+ // TODO(b/111276913): replace by an interface name implemented by Activity, similar to
+ // AutofillClient
+ @GuardedBy("mLock")
+ private ComponentName mComponentName;
+
/** @hide */
- public IntelligenceManager(@NonNull Context context) {
+ public IntelligenceManager(@NonNull Context context, @Nullable IIntelligenceManager service) {
mContext = Preconditions.checkNotNull(context, "context cannot be null");
+ mService = service;
+ }
+
+ /** @hide */
+ public void onActivityCreated(@NonNull IBinder token, @NonNull ComponentName componentName) {
+ if (!isContentCaptureEnabled()) return;
+
+ synchronized (mLock) {
+ if (mState != STATE_UNKNOWN) {
+ Log.w(TAG, "ignoring onActivityStarted(" + token + ") while on state "
+ + getStateAsStringLocked());
+ return;
+ }
+ mState = STATE_WAITING_FOR_SERVER;
+ mId = new InteractionSessionId();
+ mApplicationToken = token;
+ mComponentName = componentName;
+
+ if (VERBOSE) {
+ Log.v(TAG, "onActivityStarted(): token=" + token + ", act=" + componentName
+ + ", id=" + mId);
+ }
+ final int flags = 0; // TODO(b/111276913): get proper flags
+
+ try {
+ mService.startSession(mContext.getUserId(), mApplicationToken, componentName,
+ mId, flags, new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData)
+ throws RemoteException {
+ synchronized (mLock) {
+ if (resultCode > 0) {
+ mState = STATE_ACTIVE;
+ } else {
+ // TODO(b/111276913): handle other cases like disabled by
+ // service
+ mState = STATE_UNKNOWN;
+ }
+ if (VERBOSE) {
+ Log.v(TAG, "onActivityStarted() result: code=" + resultCode
+ + ", id=" + mId
+ + ", state=" + getStateAsStringLocked());
+ }
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Used for intermediate events (i.e, other than created and destroyed).
+ *
+ * @hide
+ */
+ public void onActivityLifecycleEvent(@EventType int type) {
+ if (!isContentCaptureEnabled()) return;
+
+ //TODO(b/111276913): should buffer event (and call service on handler thread), instead of
+ // calling right away
+ final ContentCaptureEvent event = new ContentCaptureEvent(type, SystemClock.uptimeMillis(),
+ 0);
+ final List<ContentCaptureEvent> events = Arrays.asList(event);
+
+ synchronized (mLock) {
+ //TODO(b/111276913): check session state; for example, how to handle if it's waiting for
+ // remote id
+
+ if (VERBOSE) {
+ Log.v(TAG, "onActivityLifecycleEvent() for " + mComponentName.flattenToShortString()
+ + ": " + ContentCaptureEvent.getTypeAsString(type));
+ }
+
+ try {
+ mService.sendEvents(mContext.getUserId(), mId, events);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /** @hide */
+ public void onActivityDestroyed() {
+ if (!isContentCaptureEnabled()) return;
+
+ synchronized (mLock) {
+ //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
+ // id) and send it to the cache of batched commands
+
+ if (VERBOSE) {
+ Log.v(TAG, "onActivityDestroyed(): state=" + getStateAsStringLocked()
+ + ", mId=" + mId);
+ }
+
+ try {
+ mService.finishSession(mContext.getUserId(), mId);
+ mState = STATE_UNKNOWN;
+ mId = null;
+ mApplicationToken = null;
+ mComponentName = null;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -54,11 +221,13 @@
}
/**
- * Checks whether contents capture is enabled for this activity.
+ * Checks whether content capture is enabled for this activity.
*/
public boolean isContentCaptureEnabled() {
- //TODO(b/111276913): implement
- return false;
+ //TODO(b/111276913): properly implement by checking if it was explicitly disabled by
+ // service, or if service is not set
+ // (and probably renamign to isEnabledLocked()
+ return mService != null;
}
/**
@@ -68,6 +237,7 @@
* it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
*/
public void disableContentCapture() {
+ //TODO(b/111276913): implement
}
/**
@@ -140,4 +310,40 @@
//TODO(b/111276913): implement
return null;
}
+
+ /** @hide */
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.println("IntelligenceManager");
+ final String prefix2 = prefix + " ";
+ synchronized (mLock) {
+ pw.print(prefix2); pw.print("mContext: "); pw.println(mContext);
+ pw.print(prefix2); pw.print("mService: "); pw.println(mService);
+ pw.print(prefix2); pw.print("user: "); pw.println(mContext.getUserId());
+ pw.print(prefix2); pw.print("enabled: "); pw.println(isContentCaptureEnabled());
+ pw.print(prefix2); pw.print("id: "); pw.println(mId);
+ pw.print(prefix2); pw.print("state: "); pw.print(mState); pw.print(" (");
+ pw.print(getStateAsStringLocked()); pw.println(")");
+ pw.print(prefix2); pw.print("appToken: "); pw.println(mApplicationToken);
+ pw.print(prefix2); pw.print("componentName: "); pw.println(mComponentName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private String getStateAsStringLocked() {
+ return getStateAsString(mState);
+ }
+
+ @NonNull
+ private static String getStateAsString(int state) {
+ switch (state) {
+ case STATE_UNKNOWN:
+ return "UNKNOWN";
+ case STATE_WAITING_FOR_SERVER:
+ return "WAITING_FOR_SERVER";
+ case STATE_ACTIVE:
+ return "ACTIVE";
+ default:
+ return "INVALID:" + state;
+ }
+ }
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f96f088..5b1544b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3928,6 +3928,7 @@
SelectionModifierCursorController selectionController = getSelectionController();
if (selectionController.mStartHandle == null) {
// As these are for initializing selectionController, hide() must be called.
+ loadHandleDrawables(false /* overwrite */);
selectionController.initHandles();
selectionController.hide();
}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 6a3fc0f..9da2a43 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -28,6 +28,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -568,7 +569,7 @@
private Point getCurrentClampedWindowCoordinates() {
final Rect windowBounds;
if (mParentSurface.mIsMainWindowSurface) {
- final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
+ final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
windowBounds = new Rect(systemInsets.left, systemInsets.top,
mParentSurface.mWidth - systemInsets.right,
mParentSurface.mHeight - systemInsets.bottom);
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index aa7bdb6..e2c23de 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1001,7 +1001,7 @@
insets.getSystemWindowInsetRight(), 0);
}
}
- mFrameOffsets.set(insets.getSystemWindowInsets());
+ mFrameOffsets.set(insets.getSystemWindowInsetsAsRect());
insets = updateColorViews(insets, true /* animate */);
insets = updateStatusGuard(insets);
if (getForeground() != null) {
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 4a1c955..ba0ff01 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -313,8 +313,7 @@
pullChildren();
final int vis = getWindowSystemUiVisibility();
- final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
- final Rect systemInsets = insets.getSystemWindowInsets();
+ final Rect systemInsets = insets.getSystemWindowInsetsAsRect();
// The top and bottom action bars are always within the content area.
boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index e07a208..2e7501f 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -83,7 +83,8 @@
return 0;
}
std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
- builder->langId, builder->variant, std::move(builder->fonts));
+ builder->langId, builder->variant, std::move(builder->fonts),
+ true /* isCustomFallback */);
if (family->getCoverage().length() == 0) {
return 0;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d391de7..a8b0640 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -28,6 +28,7 @@
#include "SkBlurDrawLooper.h"
#include "SkColorFilter.h"
+#include "SkFontTypes.h"
#include "SkMaskFilter.h"
#include "SkPath.h"
#include "SkPathEffect.h"
@@ -684,13 +685,13 @@
}
static jint getHinting(jlong paintHandle) {
- return reinterpret_cast<Paint*>(paintHandle)->getHinting()
- == Paint::kNo_Hinting ? 0 : 1;
+ return (SkFontHinting)reinterpret_cast<Paint*>(paintHandle)->getHinting()
+ == kNo_SkFontHinting ? 0 : 1;
}
static void setHinting(jlong paintHandle, jint mode) {
reinterpret_cast<Paint*>(paintHandle)->setHinting(
- mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
+ mode == 0 ? kNo_SkFontHinting : kNormal_SkFontHinting);
}
static void setAntiAlias(jlong paintHandle, jboolean aa) {
diff --git a/core/jni/android/graphics/fonts/FontFamily.cpp b/core/jni/android/graphics/fonts/FontFamily.cpp
index 767e068..249e4f3 100644
--- a/core/jni/android/graphics/fonts/FontFamily.cpp
+++ b/core/jni/android/graphics/fonts/FontFamily.cpp
@@ -57,7 +57,7 @@
// Regular JNI
static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr,
- jstring langTags, jint variant) {
+ jstring langTags, jint variant, jboolean isCustomFallback) {
std::unique_ptr<NativeFamilyBuilder> builder(toBuilder(builderPtr));
uint32_t localeId;
if (langTags == nullptr) {
@@ -67,7 +67,8 @@
localeId = minikin::registerLocaleList(str.c_str());
}
std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
- localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts));
+ localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts),
+ isCustomFallback);
if (family->getCoverage().length() == 0) {
// No coverage means minikin rejected given font for some reasons.
jniThrowException(env, "java/lang/IllegalArgumentException",
@@ -87,7 +88,7 @@
static const JNINativeMethod gFontFamilyBuilderMethods[] = {
{ "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder },
{ "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont },
- { "nBuild", "(JLjava/lang/String;I)J", (void*) FontFamily_Builder_build },
+ { "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build },
{ "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
};
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 80572f3..b1a9866 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -32,16 +32,15 @@
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn,
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jboolean devOptIn,
jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
- ScopedUtfChars appPrefChars(env, appPref);
int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- appPrefChars.c_str(), devOptIn, rulesFd_native, rulesOffset, rulesLength);
+ devOptIn, rulesFd_native, rulesOffset, rulesLength);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -68,7 +67,7 @@
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
- { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
{ "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4e20e29..8e9a0bf 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -20,7 +20,9 @@
#include <sys/mount.h>
#include <linux/fs.h>
+#include <functional>
#include <list>
+#include <optional>
#include <sstream>
#include <string>
@@ -70,6 +72,8 @@
namespace {
+using namespace std::placeholders;
+
using android::String8;
using android::base::StringAppendF;
using android::base::StringPrintf;
@@ -651,12 +655,12 @@
static FileDescriptorTable* gOpenFdTable = NULL;
static bool FillFileDescriptorVector(JNIEnv* env,
- jintArray java_fds,
+ jintArray managed_fds,
std::vector<int>* fds,
std::string* error_msg) {
CHECK(fds != nullptr);
- if (java_fds != nullptr) {
- ScopedIntArrayRO ar(env, java_fds);
+ if (managed_fds != nullptr) {
+ ScopedIntArrayRO ar(env, managed_fds);
if (ar.get() == nullptr) {
*error_msg = "Bad fd array";
return false;
@@ -669,246 +673,46 @@
return true;
}
-// Utility routine to specialize a zygote child process.
-static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
- jint runtime_flags, jobjectArray javaRlimits,
- jlong permittedCapabilities, jlong effectiveCapabilities,
- jint mount_external, jstring java_se_info, jstring java_se_name,
- bool is_system_server, bool is_child_zygote, jstring instructionSet,
- jstring dataDir, jstring packageName, jobjectArray packagesForUid,
- jobjectArray visibleVolIds) {
- std::string error_msg;
-
- auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
- __attribute__ ((noreturn)) {
- const char* se_name_c_str = nullptr;
- std::unique_ptr<ScopedUtfChars> se_name;
- if (java_se_name != nullptr) {
- se_name.reset(new ScopedUtfChars(env, java_se_name));
- se_name_c_str = se_name->c_str();
- }
- if (se_name_c_str == nullptr && is_system_server) {
- se_name_c_str = "system_server";
- }
- const std::string& error_msg = (se_name_c_str == nullptr)
- ? msg
- : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
- env->FatalError(error_msg.c_str());
- __builtin_unreachable();
- };
-
- // Keep capabilities across UID change, unless we're staying root.
- if (uid != 0) {
- if (!EnableKeepCapabilities(&error_msg)) {
- fail_fn(error_msg);
+[[noreturn]]
+static void ZygoteFailure(JNIEnv* env,
+ const char* process_name,
+ jstring managed_process_name,
+ const std::string& msg) {
+ std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
+ if (managed_process_name != nullptr) {
+ scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
+ if (scoped_managed_process_name_ptr->c_str() != nullptr) {
+ process_name = scoped_managed_process_name_ptr->c_str();
}
}
- if (!SetInheritable(permittedCapabilities, &error_msg)) {
- fail_fn(error_msg);
- }
- if (!DropCapabilitiesBoundingSet(&error_msg)) {
- fail_fn(error_msg);
- }
+ const std::string& error_msg =
+ (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
- bool use_native_bridge = !is_system_server && (instructionSet != NULL)
- && android::NativeBridgeAvailable();
- if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
- }
- if (use_native_bridge && dataDir == NULL) {
- // dataDir should never be null if we need to use a native bridge.
- // In general, dataDir will never be null for normal applications. It can only happen in
- // special cases (for isolated processes which are not associated with any app). These are
- // launched by the framework and should not be emulated anyway.
- use_native_bridge = false;
- ALOGW("Native bridge will not be used because dataDir == NULL.");
- }
+ env->FatalError(error_msg.c_str());
+ __builtin_unreachable();
+}
- std::string package_name_str("");
- if (packageName != nullptr) {
- ScopedUtfChars package(env, packageName);
- package_name_str = package.c_str();
- } else if (is_system_server) {
- package_name_str = "android";
- }
- std::vector<std::string> packages_for_uid;
- if (packagesForUid != nullptr) {
- jsize count = env->GetArrayLength(packagesForUid);
- for (jsize i = 0; i < count; ++i) {
- jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i);
- ScopedUtfChars package(env, package_for_uid);
- packages_for_uid.push_back(package.c_str());
- }
- }
- std::vector<std::string> visible_vol_ids;
- if (visibleVolIds != nullptr) {
- jsize count = env->GetArrayLength(visibleVolIds);
- for (jsize i = 0; i < count; ++i) {
- jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i);
- ScopedUtfChars vol(env, visible_vol_id);
- visible_vol_ids.push_back(vol.c_str());
- }
- }
- bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
- package_name_str, packages_for_uid, visible_vol_ids);
- if (!success) {
- ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
- if (errno == ENOTCONN || errno == EROFS) {
- // When device is actively encrypting, we get ENOTCONN here
- // since FUSE was mounted before the framework restarted.
- // When encrypted device is booting, we get EROFS since
- // FUSE hasn't been created yet by init.
- // In either case, continue without external storage.
+static std::optional<std::string> ExtractJString(JNIEnv* env,
+ const char* process_name,
+ jstring managed_process_name,
+ jstring managed_string) {
+ if (managed_string == nullptr) {
+ return std::optional<std::string>();
+ } else {
+ ScopedUtfChars scoped_string_chars(env, managed_string);
+
+ if (scoped_string_chars.c_str() != nullptr) {
+ return std::optional<std::string>(scoped_string_chars.c_str());
} else {
- fail_fn(error_msg);
+ ZygoteFailure(env, process_name, managed_process_name, "Failed to extract JString.");
}
}
-
- // If this zygote isn't root, it won't be able to create a process group,
- // since the directory is owned by root.
- if (!is_system_server && getuid() == 0) {
- int rc = createProcessGroup(uid, getpid());
- if (rc != 0) {
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc));
- }
- }
- }
-
- if (!SetGids(env, javaGids, &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (!SetRLimits(env, javaRlimits, &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- ScopedUtfChars data_dir(env, dataDir);
- android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
- }
-
- int rc = setresgid(gid, gid, gid);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
- }
-
- // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
- // uid from 0, which clears capabilities. The other alternative is to call
- // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
- // b/71859146). As the result, privileged syscalls used below still need to be accessible in
- // app process.
- SetUpSeccompFilter(uid);
-
- rc = setresuid(uid, uid, uid);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
- }
-
- // The "dumpable" flag of a process, which controls core dump generation, is
- // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
- // user or group ID changes. See proc(5) for possible values. In most cases,
- // the value is 0, so core dumps are disabled for zygote children. However,
- // when running in a Chrome OS container, the value is already set to 2,
- // which allows the external crash reporter to collect all core dumps. Since
- // only system crashes are interested, core dump is disabled for app
- // processes. This also ensures compliance with CTS.
- int dumpable = prctl(PR_GET_DUMPABLE);
- if (dumpable == -1) {
- ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
- }
- if (dumpable == 2 && uid >= AID_APP) {
- if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
- ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
- }
- }
-
- if (NeedsNoRandomizeWorkaround()) {
- // Work around ARM kernel ASLR lossage (http://b/5817320).
- int old_personality = personality(0xffffffff);
- int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
- if (new_personality == -1) {
- ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
- }
- }
-
- if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
- &error_msg)) {
- fail_fn(error_msg);
- }
-
- if (!SetSchedulerPolicy(&error_msg)) {
- fail_fn(error_msg);
- }
-
- const char* se_info_c_str = NULL;
- ScopedUtfChars* se_info = NULL;
- if (java_se_info != NULL) {
- se_info = new ScopedUtfChars(env, java_se_info);
- se_info_c_str = se_info->c_str();
- if (se_info_c_str == NULL) {
- fail_fn("se_info_c_str == NULL");
- }
- }
- const char* se_name_c_str = NULL;
- ScopedUtfChars* se_name = NULL;
- if (java_se_name != NULL) {
- se_name = new ScopedUtfChars(env, java_se_name);
- se_name_c_str = se_name->c_str();
- if (se_name_c_str == NULL) {
- fail_fn("se_name_c_str == NULL");
- }
- }
- rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
- if (rc == -1) {
- fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
- is_system_server, se_info_c_str, se_name_c_str));
- }
-
- // Make it easier to debug audit logs by setting the main thread's name to the
- // nice name rather than "app_process".
- if (se_name_c_str == NULL && is_system_server) {
- se_name_c_str = "system_server";
- }
- if (se_name_c_str != NULL) {
- SetThreadName(se_name_c_str);
- }
-
- delete se_info;
- delete se_name;
-
- // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
- UnsetChldSignalHandler();
-
- if (is_system_server) {
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks);
- if (env->ExceptionCheck()) {
- fail_fn("Error calling post fork system server hooks.");
- }
- // TODO(oth): Remove hardcoded label here (b/117874058).
- static const char* kSystemServerLabel = "u:r:system_server:s0";
- if (selinux_android_setcon(kSystemServerLabel) != 0) {
- fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
- }
- }
-
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
- is_system_server, is_child_zygote, instructionSet);
- if (env->ExceptionCheck()) {
- fail_fn("Error calling post fork hooks.");
- }
}
-// Utility routine to fork zygote and specialize the child process.
-static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
- jintArray fdsToClose, jintArray fdsToIgnore) {
+// Utility routine to fork a zygote.
+static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
+ jintArray managed_fds_to_close, jintArray managed_fds_to_ignore) {
SetSignalHandlers();
// Block SIGCHLD prior to fork.
@@ -916,23 +720,9 @@
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
- auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
- __attribute__ ((noreturn)) {
- const char* se_name_c_str = nullptr;
- std::unique_ptr<ScopedUtfChars> se_name;
- if (java_se_name != nullptr) {
- se_name.reset(new ScopedUtfChars(env, java_se_name));
- se_name_c_str = se_name->c_str();
- }
- if (se_name_c_str == nullptr && is_system_server) {
- se_name_c_str = "system_server";
- }
- const std::string& error_msg = (se_name_c_str == nullptr)
- ? msg
- : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
- env->FatalError(error_msg.c_str());
- __builtin_unreachable();
- };
+ // Curry a failure function.
+ auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
+ nullptr, _1);
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
@@ -948,18 +738,18 @@
__android_log_close();
stats_log_close();
+ // 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::string error_msg;
-
- // 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;
- if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
+ if (!FillFileDescriptorVector(env, managed_fds_to_ignore, &fds_to_ignore, &error_msg)) {
fail_fn(error_msg);
}
- if (gOpenFdTable == NULL) {
+
+ if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
- if (gOpenFdTable == NULL) {
+ if (gOpenFdTable == nullptr) {
fail_fn(error_msg);
}
} else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
@@ -975,7 +765,7 @@
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
- if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
+ if (!DetachDescriptors(env, managed_fds_to_close, &error_msg)) {
fail_fn(error_msg);
}
@@ -993,9 +783,236 @@
if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
+
return pid;
}
+// Utility routine to specialize a zygote child process.
+static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
+ jint runtime_flags, jobjectArray rlimits,
+ jlong permitted_capabilities, jlong effective_capabilities,
+ jint mount_external, jstring managed_se_info,
+ jstring managed_nice_name, bool is_system_server,
+ bool is_child_zygote, jstring managed_instruction_set,
+ jstring managed_app_data_dir, jstring managed_package_name,
+ jobjectArray managed_pacakges_for_uid,
+ jobjectArray managed_visible_vol_ids) {
+ auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
+ managed_nice_name, _1);
+ auto extract_fn = std::bind(ExtractJString, env, is_system_server ? "system_server" : "zygote",
+ managed_nice_name, _1);
+
+ auto se_info = extract_fn(managed_se_info);
+ auto nice_name = extract_fn(managed_nice_name);
+ auto instruction_set = extract_fn(managed_instruction_set);
+ auto app_data_dir = extract_fn(managed_app_data_dir);
+ auto package_name = extract_fn(managed_package_name);
+
+ std::string error_msg;
+
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ if (!EnableKeepCapabilities(&error_msg)) {
+ fail_fn(error_msg);
+ }
+ }
+
+ if (!SetInheritable(permitted_capabilities, &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (!DropCapabilitiesBoundingSet(&error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ bool use_native_bridge = !is_system_server &&
+ instruction_set.has_value() &&
+ android::NativeBridgeAvailable() &&
+ android::NeedsNativeBridge(instruction_set.value().c_str());
+
+ if (use_native_bridge && !app_data_dir.has_value()) {
+ // The app_data_dir variable should never be empty if we need to use a
+ // native bridge. In general, app_data_dir will never be empty for normal
+ // applications. It can only happen in special cases (for isolated
+ // processes which are not associated with any app). These are launched by
+ // the framework and should not be emulated anyway.
+ use_native_bridge = false;
+ ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr.");
+ }
+
+ if (!package_name.has_value()) {
+ if (is_system_server) {
+ package_name.emplace("android");
+ } else {
+ package_name.emplace("");
+ }
+ }
+
+ std::vector<std::string> packages_for_uid;
+ if (managed_pacakges_for_uid != nullptr) {
+ jsize count = env->GetArrayLength(managed_pacakges_for_uid);
+ for (jsize package_index = 0; package_index < count; ++package_index) {
+ jstring managed_package_for_uid =
+ (jstring) env->GetObjectArrayElement(managed_pacakges_for_uid, package_index);
+
+ auto package_for_uid = extract_fn(managed_package_for_uid);
+ if (LIKELY(package_for_uid.has_value())) {
+ packages_for_uid.emplace_back(std::move(package_for_uid.value()));
+ } else {
+ fail_fn("Null string found in managed packages_for_uid.");
+ }
+ }
+ }
+
+ std::vector<std::string> visible_vol_ids;
+ if (managed_visible_vol_ids != nullptr) {
+ jsize count = env->GetArrayLength(managed_visible_vol_ids);
+ for (jsize vol_id_index = 0; vol_id_index < count; ++vol_id_index) {
+ jstring managed_visible_vol_id =
+ (jstring) env->GetObjectArrayElement(managed_visible_vol_ids, vol_id_index);
+
+ auto visible_vol_id = extract_fn(managed_visible_vol_id);
+ if (LIKELY(visible_vol_id.has_value())) {
+ visible_vol_ids.emplace_back(std::move(visible_vol_id.value()));
+ } else {
+ fail_fn("Null string found in managed visible_vol_ids.");
+ }
+ }
+ }
+
+ if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
+ package_name.value(), packages_for_uid, visible_vol_ids)) {
+ ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ fail_fn(error_msg);
+ }
+ }
+
+ // If this zygote isn't root, it won't be able to create a process group,
+ // since the directory is owned by root.
+ if (!is_system_server && getuid() == 0) {
+ int rc = createProcessGroup(uid, getpid());
+ if (rc == -EROFS) {
+ ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+ } else if (rc != 0) {
+ ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ }
+ }
+
+ if (!SetGids(env, gids, &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (!SetRLimits(env, rlimits, &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (use_native_bridge) {
+ // Due to the logic behind use_native_bridge we know that both app_data_dir
+ // and instruction_set contain values.
+ android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
+ instruction_set.value().c_str());
+ }
+
+ if (setresgid(gid, gid, gid) == -1) {
+ fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
+ }
+
+ // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
+ // before changing uid from 0, which clears capabilities. The other
+ // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
+ // breaks SELinux domain transition (see b/71859146). As the result,
+ // privileged syscalls used below still need to be accessible in app process.
+ SetUpSeccompFilter(uid);
+
+ if (setresuid(uid, uid, uid) == -1) {
+ fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
+ }
+
+ // The "dumpable" flag of a process, which controls core dump generation, is
+ // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
+ // user or group ID changes. See proc(5) for possible values. In most cases,
+ // the value is 0, so core dumps are disabled for zygote children. However,
+ // when running in a Chrome OS container, the value is already set to 2,
+ // which allows the external crash reporter to collect all core dumps. Since
+ // only system crashes are interested, core dump is disabled for app
+ // processes. This also ensures compliance with CTS.
+ int dumpable = prctl(PR_GET_DUMPABLE);
+ if (dumpable == -1) {
+ ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
+ }
+
+ if (dumpable == 2 && uid >= AID_APP) {
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+ ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+ }
+ }
+
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+ }
+ }
+
+ if (!SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
+ &error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ if (!SetSchedulerPolicy(&error_msg)) {
+ fail_fn(error_msg);
+ }
+
+ const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
+ const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+
+ if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
+ fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
+ uid, is_system_server, se_info_ptr, nice_name_ptr));
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (nice_name.has_value()) {
+ SetThreadName(nice_name.value().c_str());
+ } else if (is_system_server) {
+ SetThreadName("system_server");
+ }
+
+ // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+ UnsetChldSignalHandler();
+
+ if (is_system_server) {
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks);
+ if (env->ExceptionCheck()) {
+ fail_fn("Error calling post fork system server hooks.");
+ }
+ // TODO(oth): Remove hardcoded label here (b/117874058).
+ static const char* kSystemServerLabel = "u:r:system_server:s0";
+ if (selinux_android_setcon(kSystemServerLabel) != 0) {
+ fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
+ }
+ }
+
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
+ is_system_server, is_child_zygote, managed_instruction_set);
+
+ if (env->ExceptionCheck()) {
+ fail_fn("Error calling post fork hooks.");
+ }
+}
+
static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
@@ -1008,16 +1025,82 @@
RuntimeAbort(env, __LINE__, "capget failed");
}
- return capdata[0].effective |
- (static_cast<uint64_t>(capdata[1].effective) << 32);
+ return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32);
+}
+
+static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids,
+ bool is_child_zygote) {
+ jlong capabilities = 0;
+
+ /*
+ * Grant the following capabilities to the Bluetooth user:
+ * - CAP_WAKE_ALARM
+ * - CAP_NET_RAW
+ * - CAP_NET_BIND_SERVICE (for DHCP client functionality)
+ * - CAP_SYS_NICE (for setting RT priority for audio-related threads)
+ */
+
+ if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
+ capabilities |= (1LL << CAP_WAKE_ALARM);
+ capabilities |= (1LL << CAP_NET_RAW);
+ capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+ capabilities |= (1LL << CAP_SYS_NICE);
+ }
+
+ /*
+ * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+ */
+
+ bool gid_wakelock_found = false;
+ if (gid == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ } else if (gids != nullptr) {
+ jsize gids_num = env->GetArrayLength(gids);
+ ScopedIntArrayRO native_gid_proxy(env, gids);
+
+ if (native_gid_proxy.get() == nullptr) {
+ RuntimeAbort(env, __LINE__, "Bad gids array");
+ }
+
+ for (int gid_index = gids_num; --gids_num >= 0;) {
+ if (native_gid_proxy[gid_index] == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ break;
+ }
+ }
+ }
+
+ if (gid_wakelock_found) {
+ capabilities |= (1LL << CAP_BLOCK_SUSPEND);
+ }
+
+ /*
+ * Grant child Zygote processes the following capabilities:
+ * - CAP_SETUID (change UID of child processes)
+ * - CAP_SETGID (change GID of child processes)
+ * - CAP_SETPCAP (change capabilities of child processes)
+ */
+
+ if (is_child_zygote) {
+ capabilities |= (1LL << CAP_SETUID);
+ capabilities |= (1LL << CAP_SETGID);
+ capabilities |= (1LL << CAP_SETPCAP);
+ }
+
+ /*
+ * Containers run without some capabilities, so drop any caps that are not
+ * available.
+ */
+
+ return capabilities & GetEffectiveCapabilityMask(env);
}
} // anonymous namespace
namespace android {
static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
- // security_getenforce is not allowed on app process. Initialize and cache the value before
- // zygote forks.
+ // security_getenforce is not allowed on app process. Initialize and cache
+ // the value before zygote forks.
g_is_security_enforced = security_getenforce();
}
@@ -1028,78 +1111,35 @@
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
- jint mount_external, jstring se_info, jstring se_name,
- jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
- jstring instructionSet, jstring appDataDir, jstring packageName,
- jobjectArray packagesForUid, jobjectArray visibleVolIds) {
- jlong capabilities = 0;
+ jint mount_external, jstring se_info, jstring nice_name,
+ jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
+ jstring instruction_set, jstring app_data_dir, jstring package_name,
+ jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
+ jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
- // Grant CAP_WAKE_ALARM to the Bluetooth process.
- // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
- // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
- // audio-related threads.
- // TODO: consider making such functionality an RPC to netd.
- if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
- capabilities |= (1LL << CAP_WAKE_ALARM);
- capabilities |= (1LL << CAP_NET_RAW);
- capabilities |= (1LL << CAP_NET_BIND_SERVICE);
- capabilities |= (1LL << CAP_SYS_NICE);
- }
-
- // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
- bool gid_wakelock_found = false;
- if (gid == AID_WAKELOCK) {
- gid_wakelock_found = true;
- } else if (gids != NULL) {
- jsize gids_num = env->GetArrayLength(gids);
- ScopedIntArrayRO ar(env, gids);
- if (ar.get() == NULL) {
- RuntimeAbort(env, __LINE__, "Bad gids array");
- }
- for (int i = 0; i < gids_num; i++) {
- if (ar[i] == AID_WAKELOCK) {
- gid_wakelock_found = true;
- break;
- }
- }
- }
- if (gid_wakelock_found) {
- capabilities |= (1LL << CAP_BLOCK_SUSPEND);
- }
-
- // If forking a child zygote process, that zygote will need to be able to change
- // the UID and GID of processes it forks, as well as drop those capabilities.
- if (is_child_zygote) {
- capabilities |= (1LL << CAP_SETUID);
- capabilities |= (1LL << CAP_SETGID);
- capabilities |= (1LL << CAP_SETPCAP);
- }
-
- // Containers run without some capabilities, so drop any caps that are not
- // available.
- capabilities &= GetEffectiveCapabilityMask(env);
-
- pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
+ pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
- mount_external, se_info, se_name, false,
- is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName,
- packagesForUid, visibleVolIds);
+ mount_external, se_info, nice_name, false,
+ is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+ package_name, packages_for_uid, visible_vol_ids);
}
return pid;
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
- jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
- jlong effectiveCapabilities) {
- pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
+ jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
+ jlong effective_capabilities) {
+ pid_t pid = ForkCommon(env, true,
+ /* managed_fds_to_close= */ nullptr,
+ /* managed_fds_to_ignore= */ nullptr);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
- permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
- false, NULL, NULL, nullptr, nullptr, nullptr);
+ permitted_capabilities, effective_capabilities,
+ MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
+ false, nullptr, nullptr, nullptr, nullptr, nullptr);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -1133,7 +1173,7 @@
ScopedUtfChars path_native(env, path);
const char* path_cstr = path_native.c_str();
if (!path_cstr) {
- RuntimeAbort(env, __LINE__, "path_cstr == NULL");
+ RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
}
FileDescriptorWhitelist::Get()->Allow(path_cstr);
}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 2ace1ac..480b1ea 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -11,6 +11,9 @@
yaochen@google.com
yro@google.com
+# Settings UI
+per-file settings_enums.proto=zhfan@google.com
+
# Frameworks
ogunwale@google.com
jjaggi@google.com
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 5433393..3a908dc 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -64,5 +64,8 @@
// OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent)
BIOMETRIC_ENROLL_ACTIVITY = 1586;
+
+ // OPEN: Settings > Privacy
+ TOP_LEVEL_PRIVACY = 1587;
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8f28970..0b9e347 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -26,6 +26,7 @@
import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
import "frameworks/base/core/proto/android/os/ps.proto";
+import "frameworks/base/core/proto/android/os/statsdata.proto";
import "frameworks/base/core/proto/android/os/system_properties.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
@@ -301,6 +302,12 @@
(section).userdebug_and_eng_only = true
];
+ optional android.os.StatsDataDumpProto stats_data = 3023 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "stats --proto",
+ (section).userdebug_and_eng_only = true
+ ];
+
// Reserved for OEMs.
extensions 50000 to 100000;
}
diff --git a/core/proto/android/os/statsdata.proto b/core/proto/android/os/statsdata.proto
new file mode 100644
index 0000000..25d76b8
--- /dev/null
+++ b/core/proto/android/os/statsdata.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Dump of statsd report data (dumpsys stats --proto).
+message StatsDataDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // The following is an android.os.statsd.ConfigMetricsReportList, which is defined
+ // in frameworks/base/cmds/statsd/src/stats_log.proto. It should not be imported (even weakly)
+ // in AOSP because it would drag with it atoms.proto, which is enormous and awkward.
+ repeated bytes config_metrics_report_list = 1;
+
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3072977..69ebb59 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -725,8 +725,10 @@
optional SettingProto set_install_location = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto shortcut_manager_constants = 104;
optional SettingProto show_first_crash_dialog = 105 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_hidden_launcher_icon_apps_enabled = 141 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_restart_in_crash_dialog = 106 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_mute_in_crash_dialog = 107 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto show_new_app_installed_notification_enabled = 142 [ (android.privacy).dest = DEST_AUTOMATIC ];
message SmartSelection {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -966,5 +968,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 141;
+ // Next tag = 143;
}
diff --git a/core/res/TEST_MAPPING b/core/res/TEST_MAPPING
new file mode 100644
index 0000000..1d22d782
--- /dev/null
+++ b/core/res/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermission2TestCases",
+ "options": [
+ {
+ "include-filter": "android.permission2.cts.PermissionPolicyTest#testPlatformPermissionPolicyUnaltered"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index a0c02ed..c1ca33e 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -44,9 +44,10 @@
<dimen name="car_headline3_size">24sp</dimen>
<dimen name="car_headline4_size">20sp</dimen>
<dimen name="car_body1_size">32sp</dimen>
- <dimen name="car_body2_size">26sp</dimen>
- <dimen name="car_body3_size">16sp</dimen>
- <dimen name="car_body4_size">14sp</dimen>
+ <dimen name="car_body2_size">28sp</dimen>
+ <dimen name="car_body3_size">26sp</dimen>
+ <dimen name="car_body4_size">24sp</dimen>
+ <!-- car_body5_size is deprecated -->
<dimen name="car_body5_size">18sp</dimen>
<dimen name="car_label1_size">26sp</dimen>
<dimen name="car_label2_size">64sp</dimen>
@@ -85,6 +86,7 @@
<dimen name="car_borderless_button_horizontal_padding">0dp</dimen>
<dimen name="car_button_radius">@dimen/car_radius_1</dimen>
<dimen name="car_pill_button_size">56dp</dimen>
+ <dimen name="car_touch_target_size">76dp</dimen>
<!-- Seekbar -->
<dimen name="car_seekbar_height">6dp</dimen>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6bd02ac..3342266 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -370,6 +370,7 @@
Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,
@@ -393,7 +394,9 @@
Settings.Global.SETTINGS_USE_PSD_API,
Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
Settings.Global.SHOW_FIRST_CRASH_DIALOG,
+ Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
+ Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index c8e46fc..ca6d6cfe 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertThat;
import android.content.Context;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
@@ -57,9 +58,8 @@
mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
- assertThat(insets.getSystemWindowInsets(), equalTo(new Rect()));
- assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
- insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect()));
+ assertThat(insets.getSystemWindowInsets(), equalTo(Insets.NONE));
+ assertThat(insets.getStableInsets(), equalTo(Insets.NONE));
}
@Test
@@ -68,10 +68,8 @@
mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
- assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40)));
- assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
- insets.getStableInsetRight(), insets.getStableInsetBottom()),
- equalTo(new Rect(10, 0, 30, 0)));
+ assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(0, 20, 0, 40)));
+ assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 0, 30, 0)));
}
@Test
@@ -80,10 +78,8 @@
mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
- assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40)));
- assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
- insets.getStableInsetRight(), insets.getStableInsetBottom()),
- equalTo(new Rect(10, 20, 30, 40)));
+ assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(10, 20, 30, 40)));
+ assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40)));
}
private static class ViewRootImplAccessor {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 9546a4a..c580c46 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -16,8 +16,6 @@
package android.graphics;
-import android.annotation.UnsupportedAppUsage;
-
public class ImageFormat {
/*
* these constants are chosen to be binary compatible with their previous
@@ -92,20 +90,21 @@
* </ul>
* </p>
*
- * <pre> y_size = stride * height </pre>
+ * <pre> size = stride * height </pre>
*
* <p>For example, the {@link android.media.Image} object can provide data
- * in this format from a {@link android.hardware.camera2.CameraDevice}
- * through a {@link android.media.ImageReader} object if this format is
- * supported by {@link android.hardware.camera2.CameraDevice}.</p>
+ * in this format from a {@link android.hardware.camera2.CameraDevice} (if
+ * supported) through a {@link android.media.ImageReader} object. The
+ * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a
+ * single plane containing the pixel data. The pixel stride is always 1 in
+ * {@link android.media.Image.Plane#getPixelStride()}, and the
+ * {@link android.media.Image.Plane#getRowStride()} describes the vertical
+ * neighboring pixel distance (in bytes) between adjacent rows.</p>
*
* @see android.media.Image
* @see android.media.ImageReader
* @see android.hardware.camera2.CameraDevice
- *
- * @hide
*/
- @UnsupportedAppUsage
public static final int Y8 = 0x20203859;
/**
@@ -787,6 +786,7 @@
case DEPTH_POINT_CLOUD:
case PRIVATE:
case RAW_DEPTH:
+ case Y8:
return true;
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index a09b063..7e8bfb3 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -566,7 +566,7 @@
final CustomFallbackBuilder builder = new CustomFallbackBuilder(family)
.setStyle(new FontStyle(weight, slant));
if (mFallbackFamilyName != null) {
- builder.setFallback(mFallbackFamilyName);
+ builder.setSystemFallback(mFallbackFamilyName);
}
final Typeface typeface = builder.build();
if (key != null) {
@@ -584,6 +584,14 @@
/**
* A builder class for creating new Typeface instance.
*
+ * There are two font fallback mechanisms, custom font fallback and system font fallback.
+ * The custom font fallback is a simple ordered list. The text renderer tries to see if it can
+ * render a character with the first font and if that font does not support the character, try
+ * next one and so on. It will keep trying until end of the custom fallback chain. The maximum
+ * length of the custom fallback chain is 64.
+ * The system font fallback is a system pre-defined fallback chain. The system fallback is
+ * processed only when no matching font is found in the custom font fallback.
+ *
* <p>
* Examples,
* 1) Create Typeface from single ttf file.
@@ -617,15 +625,29 @@
* Font font = new Font.Builder("your_font_file.ttf").build();
* FontFamily family = new FontFamily.Builder(font).build();
* Typeface typeface = new Typeface.CustomFallbackBuilder(family)
- * .setFallback("serif") // Set serif font family as the fallback.
+ * .setSystemFallback("serif") // Set serif font family as the fallback.
+ * .build();
+ * </code>
+ * </pre>
+ * 4) Create Typeface from single ttf file and set another ttf file for the fallback.
+ * <pre>
+ * <code>
+ * Font font = new Font.Builder("English.ttf").build();
+ * FontFamily family = new FontFamily.Builder(font).build();
+ *
+ * Font fallbackFont = new Font.Builder("Arabic.ttf").build();
+ * FontFamily fallbackFamily = new FontFamily.Builder(fallbackFont).build();
+ * Typeface typeface = new Typeface.CustomFallbackBuilder(family)
+ * .addCustomFallback(fallbackFamily) // Specify fallback family.
+ * .setSystemFallback("serif") // Set serif font family as the fallback.
* .build();
* </code>
* </pre>
* </p>
*/
public static class CustomFallbackBuilder {
- // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
- private final android.graphics.fonts.FontFamily mFamily;
+ private static final int MAX_CUSTOM_FALLBACK = 64;
+ private final ArrayList<FontFamily> mFamilies = new ArrayList<>();
private String mFallbackName = null;
private @Nullable FontStyle mStyle;
@@ -634,19 +656,20 @@
*
* @param family a family object
*/
- // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
- public CustomFallbackBuilder(@NonNull android.graphics.fonts.FontFamily family) {
+ public CustomFallbackBuilder(@NonNull FontFamily family) {
Preconditions.checkNotNull(family);
- mFamily = family;
+ mFamilies.add(family);
}
/**
* Sets a system fallback by name.
*
+ * For more information about fallback, see class description.
+ *
* @param familyName a family name to be used for fallback if the provided fonts can not be
* used
*/
- public CustomFallbackBuilder setFallback(@NonNull String familyName) {
+ public CustomFallbackBuilder setSystemFallback(@NonNull String familyName) {
Preconditions.checkNotNull(familyName);
mFallbackName = familyName;
return this;
@@ -667,19 +690,40 @@
}
/**
+ * Append a font family to the end of the custom font fallback.
+ *
+ * You can set up to 64 custom fallback families including the first font family you passed
+ * to the constructor.
+ * For more information about fallback, see class description.
+ *
+ * @param family a fallback family
+ * @throws IllegalArgumentException if you give more than 64 custom fallback families
+ */
+ public CustomFallbackBuilder addCustomFallback(@NonNull FontFamily family) {
+ Preconditions.checkNotNull(family);
+ Preconditions.checkArgument(mFamilies.size() < MAX_CUSTOM_FALLBACK,
+ "Custom fallback limit exceeded(" + MAX_CUSTOM_FALLBACK + ")");
+ mFamilies.add(family);
+ return this;
+ }
+
+ /**
* Create the Typeface based on the configured values.
*
* @return the Typeface object
*/
public Typeface build() {
+ final int userFallbackSize = mFamilies.size();
final FontFamily[] fallback = SystemFonts.getSystemFallback(mFallbackName);
- final FontFamily[] fullFamilies = new FontFamily[fallback.length + 1];
- final long[] ptrArray = new long[fallback.length + 1];
- ptrArray[0] = mFamily.getNativePtr();
- fullFamilies[0] = mFamily;
+ final FontFamily[] fullFamilies = new FontFamily[fallback.length + userFallbackSize];
+ final long[] ptrArray = new long[fallback.length + userFallbackSize];
+ for (int i = 0; i < userFallbackSize; ++i) {
+ ptrArray[i] = mFamilies.get(i).getNativePtr();
+ fullFamilies[i] = mFamilies.get(i);
+ }
for (int i = 0; i < fallback.length; ++i) {
- ptrArray[i + 1] = fallback[i].getNativePtr();
- fullFamilies[i + 1] = fallback[i];
+ ptrArray[i + userFallbackSize] = fallback[i].getNativePtr();
+ fullFamilies[i + userFallbackSize] = fallback[i];
}
final int weight = mStyle == null ? 400 : mStyle.getWeight();
final int italic =
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 18b41fa..3c44916 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -149,9 +149,13 @@
}
/**
- * Returns the alpha value of this drawable's color.
+ * Returns the alpha value of this drawable's color. Note this may not be the same alpha value
+ * provided in {@link Drawable#setAlpha(int)}. Instead this will return the alpha of the color
+ * combined with the alpha provided by setAlpha
*
* @return A value between 0 and 255.
+ *
+ * @see ColorDrawable#setAlpha(int)
*/
@Override
public int getAlpha() {
@@ -159,7 +163,9 @@
}
/**
- * Sets the color's alpha value.
+ * Applies the given alpha to the underlying color. Note if the color already has
+ * an alpha applied to it, this will apply this alpha to the existing value instead of
+ * overwriting it.
*
* @param alpha The alpha value to set, between 0 and 255.
*/
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 14d31d9..c0f1b16 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -108,16 +108,17 @@
* @return a font family
*/
public @NonNull FontFamily build() {
- return build("", FontConfig.Family.VARIANT_DEFAULT);
+ return build("", FontConfig.Family.VARIANT_DEFAULT, true /* isCustomFallback */);
}
/** @hide */
- public @NonNull FontFamily build(@NonNull String langTags, int variant) {
+ public @NonNull FontFamily build(@NonNull String langTags, int variant,
+ boolean isCustomFallback) {
final long builderPtr = nInitBuilder();
for (int i = 0; i < mFonts.size(); ++i) {
nAddFont(builderPtr, mFonts.get(i).getNativePtr());
}
- final long ptr = nBuild(builderPtr, langTags, variant);
+ final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback);
final FontFamily family = new FontFamily(mFonts, ptr);
sFamilyRegistory.registerNativeAllocation(family, ptr);
return family;
@@ -130,7 +131,8 @@
private static native long nInitBuilder();
@CriticalNative
private static native void nAddFont(long builderPtr, long fontPtr);
- private static native long nBuild(long builderPtr, String langTags, int variant);
+ private static native long nBuild(long builderPtr, String langTags, int variant,
+ boolean isCustomFallback);
@CriticalNative
private static native long nGetReleaseNativeFamily();
}
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 750adb2..4a9cf14 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -208,7 +208,7 @@
b.addFont(font);
}
}
- return b == null ? null : b.build(languageTags, variant);
+ return b == null ? null : b.build(languageTags, variant, false /* isCustomFallback */);
}
private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 288ba32..9e69488 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -162,6 +162,13 @@
LOG(INFO) << base::StringPrintf("PG (%02x): ",
package_group.dynamic_ref_table.mAssignedPackageId)
<< list;
+
+ for (size_t i = 0; i < 256; i++) {
+ if (package_group.dynamic_ref_table.mLookupTable[i] != 0) {
+ LOG(INFO) << base::StringPrintf(" e[0x%02x] -> 0x%02x", (uint8_t) i,
+ package_group.dynamic_ref_table.mLookupTable[i]);
+ }
+ }
}
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index dc4a0a7..388548b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6998,18 +6998,28 @@
}
status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
- uint8_t resolvedType;
+ uint8_t resolvedType = Res_value::TYPE_REFERENCE;
+ switch (value->dataType) {
+ case Res_value::TYPE_ATTRIBUTE:
+ resolvedType = Res_value::TYPE_ATTRIBUTE;
+ // fallthrough
+ case Res_value::TYPE_REFERENCE:
+ // Only resolve non-dynamic references and attributes if the package is loaded as a
+ // library or if a shared library is attempting to retrieve its own resource
+ if (!(mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) {
+ return NO_ERROR;
+ }
- if (value->dataType == Res_value::TYPE_ATTRIBUTE
- || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
- resolvedType = Res_value::TYPE_ATTRIBUTE;
-
- } else if (value->dataType == Res_value::TYPE_REFERENCE
- || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
- resolvedType = Res_value::TYPE_REFERENCE;
-
- } else {
- return NO_ERROR;
+ // If the package is loaded as shared library, the resource reference
+ // also need to be fixed.
+ break;
+ case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
+ resolvedType = Res_value::TYPE_ATTRIBUTE;
+ // fallthrough
+ case Res_value::TYPE_DYNAMIC_REFERENCE:
+ break;
+ default:
+ return NO_ERROR;
}
status_t err = lookupResourceId(&value->data);
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index a028515..59abad45 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1709,13 +1709,13 @@
struct resource_name
{
- const char16_t* package;
+ const char16_t* package = NULL;
size_t packageLen;
- const char16_t* type;
- const char* type8;
+ const char16_t* type = NULL;
+ const char* type8 = NULL;
size_t typeLen;
- const char16_t* name;
- const char* name8;
+ const char16_t* name = NULL;
+ const char* name8 = NULL;
size_t nameLen;
};
diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp
index df44e34..5acc46a 100644
--- a/libs/androidfw/tests/DynamicRefTable_test.cpp
+++ b/libs/androidfw/tests/DynamicRefTable_test.cpp
@@ -40,6 +40,26 @@
EXPECT_EQ(value2.data, 0x02010000);
};
+TEST(DynamicRefTableTest, LookupSharedLibSelfAttributes) {
+ // Shared library
+ DynamicRefTable shared_table(0x03, /* appAsLib */ false);
+ shared_table.addMapping(0x00, 0x03);
+ Res_value value;
+ value.dataType = Res_value::TYPE_ATTRIBUTE;
+ value.data = 0x00010000;
+ ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
+ EXPECT_EQ(value.data, 0x03010000);
+
+ // App loaded as a shared library
+ DynamicRefTable shared_app_table(0x04, /* appAsLib */ true);
+ shared_app_table.addMapping(0x7f, 0x04);
+ Res_value value2;
+ value2.dataType = Res_value::TYPE_ATTRIBUTE;
+ value2.data = 0x7f010000;
+ ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+ EXPECT_EQ(value2.data, 0x04010000);
+};
+
TEST(DynamicRefTableTest, LookupDynamicReferences) {
// Shared library
DynamicRefTable shared_table(0x2, /* appAsLib */ false);
@@ -51,24 +71,46 @@
ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR);
EXPECT_EQ(value.data, 0x05010000);
- // App loaded as a shared library
- DynamicRefTable shared_app_table(0x2, /* appAsLib */ true);
- shared_app_table.addMapping(0x03, 0x05);
- shared_app_table.addMapping(0x7f, 0x2);
- Res_value value2;
- value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
- value2.data = 0x03010000;
- ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
- EXPECT_EQ(value2.data, 0x05010000);
-
// Regular application
DynamicRefTable app_table(0x7f, /* appAsLib */ false);
app_table.addMapping(0x03, 0x05);
Res_value value3;
- value3.dataType = Res_value::TYPE_REFERENCE;
+ value3.dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
value3.data = 0x03010000;
ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR);
EXPECT_EQ(value3.data, 0x05010000);
};
+TEST(DynamicRefTableTest, LookupDynamicAttributes) {
+// App loaded as a shared library
+ DynamicRefTable shared_app_table(0x2, /* appAsLib */ true);
+ shared_app_table.addMapping(0x03, 0x05);
+ shared_app_table.addMapping(0x7f, 0x2);
+ Res_value value2;
+ value2.dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
+ value2.data = 0x03010000;
+ ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR);
+ EXPECT_EQ(value2.data, 0x05010000);
+}
+
+TEST(DynamicRefTableTest, DoNotLookupNonDynamicReferences) {
+ // Regular application
+ DynamicRefTable app_table(0x7f, /* appAsLib */ false);
+ Res_value value;
+ value.dataType = Res_value::TYPE_REFERENCE;
+ value.data = 0x03010000;
+ ASSERT_EQ(app_table.lookupResourceValue(&value), NO_ERROR);
+ EXPECT_EQ(value.data, 0x03010000);
+};
+
+TEST(DynamicRefTableTest, DoNotLookupNonDynamicAttributes) {
+ // App with custom package id
+ DynamicRefTable custom_app_table(0x8f, /* appAsLib */ false);
+ Res_value value2;
+ value2.dataType = Res_value::TYPE_ATTRIBUTE;
+ value2.data = 0x03010000;
+ ASSERT_EQ(custom_app_table.lookupResourceValue(&value2), NO_ERROR);
+ EXPECT_EQ(value2.data, 0x03010000);
+};
+
} // namespace android
\ No newline at end of file
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 9eb4a13f3..26d2896 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -94,15 +94,15 @@
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
ResTable::resource_name res_name;
- ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, false, &res_name));
+ ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, true, &res_name));
ASSERT_TRUE(res_name.package != NULL);
ASSERT_TRUE(res_name.type != NULL);
- ASSERT_TRUE(res_name.name != NULL);
+ ASSERT_TRUE(res_name.name8 != NULL);
EXPECT_EQ(String16("com.android.basic"), String16(res_name.package, res_name.packageLen));
EXPECT_EQ(String16("array"), String16(res_name.type, res_name.typeLen));
- EXPECT_EQ(String16("integerArray1"), String16(res_name.name, res_name.nameLen));
+ EXPECT_EQ(String8("integerArray1"), String8(res_name.name8, res_name.nameLen));
}
constexpr const uint32_t kNonOverlaidResourceId = 0x7fff0000u;
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index f0053a4..17d2db71 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -176,7 +176,7 @@
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/SkiaVulkanPipeline.cpp",
"pipeline/skia/VectorDrawableAtlas.cpp",
- "pipeline/skia/VkFunctorDrawable.cpp",
+ "pipeline/skia/VkInteropFunctorDrawable.cpp",
"renderstate/RenderState.cpp",
"renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 2ca40b9..05dc340 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -139,7 +139,7 @@
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
uint32_t flags = paint->getFlags();
- SkPaint::Hinting hinting = paint->getHinting();
+ SkFontHinting hinting = (SkFontHinting)paint->getHinting();
// select only flags that might affect text layout
flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag |
@@ -150,7 +150,7 @@
void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) {
paint->setFlags(paintFlags & SkPaint::kAllFlags);
- paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16));
+ paint->setHinting(static_cast<SkFontHinting>(paintFlags >> 16));
}
void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 596b8af..45022e7 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -24,7 +24,7 @@
#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/GLFunctorDrawable.h"
-#include "pipeline/skia/VkFunctorDrawable.h"
+#include "pipeline/skia/VkInteropFunctorDrawable.h"
namespace android {
namespace uirenderer {
@@ -124,8 +124,8 @@
uirenderer::GlFunctorLifecycleListener* listener) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener,
- asSkCanvas());
+ functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor,
+ listener, asSkCanvas());
} else {
functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener,
asSkCanvas());
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 2ca110f..7fc41ac 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -22,7 +22,7 @@
#include "SkiaProfileRenderer.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
-#include "VkFunctorDrawable.h"
+#include "VkInteropFunctorDrawable.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -144,7 +144,7 @@
}
void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
- VkFunctorDrawable::vkInvokeFunctor(functor);
+ VkInteropFunctorDrawable::vkInvokeFunctor(functor);
}
sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
similarity index 92%
rename from libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
rename to libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 6486ddb..a594206 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "VkFunctorDrawable.h"
+#include "VkInteropFunctorDrawable.h"
#include <private/hwui/DrawGlInfo.h>
#include "renderthread/EglManager.h"
@@ -64,7 +64,7 @@
}
};
-void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) {
+void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) {
ScopedDrawRequest _drawRequest{};
sGLDrawThread->queue().runSync([&]() {
EGLDisplay display = sEglManager.eglDisplay();
@@ -78,11 +78,11 @@
#define FENCE_TIMEOUT 2000000000
-void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
ATRACE_CALL();
if (canvas->getGrContext() == nullptr) {
- SkDEBUGF(("Attempting to draw VkFunctor into an unsupported surface"));
+ SkDEBUGF(("Attempting to draw VkInteropFunctor into an unsupported surface"));
return;
}
@@ -99,10 +99,11 @@
ColorTypeToPixelFormat(surfaceInfo.colorType()),
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
- std::string("VkFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + "]");
+ std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) +
+ "]");
status_t error = mFrameBuffer->initCheck();
if (error < 0) {
- ALOGW("VkFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
+ ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
return;
}
@@ -202,7 +203,7 @@
canvas->restore();
}
-VkFunctorDrawable::~VkFunctorDrawable() {
+VkInteropFunctorDrawable::~VkInteropFunctorDrawable() {
if (mListener.get() != nullptr) {
ScopedDrawRequest _drawRequest{};
sGLDrawThread->queue().runSync([&]() {
@@ -211,7 +212,7 @@
}
}
-void VkFunctorDrawable::syncFunctor() const {
+void VkInteropFunctorDrawable::syncFunctor() const {
ScopedDrawRequest _drawRequest{};
sGLDrawThread->queue().runSync([&]() {
(*mFunctor)(DrawGlInfo::kModeSync, nullptr);
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
similarity index 86%
rename from libs/hwui/pipeline/skia/VkFunctorDrawable.h
rename to libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
index e37f6fb..3269cfb 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
@@ -30,11 +30,12 @@
* This drawable wraps a Vulkan functor enabling it to be recorded into a list
* of Skia drawing commands.
*/
-class VkFunctorDrawable : public FunctorDrawable {
+class VkInteropFunctorDrawable : public FunctorDrawable {
public:
- VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+ VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener,
+ SkCanvas* canvas)
: FunctorDrawable(functor, listener, canvas) {}
- virtual ~VkFunctorDrawable();
+ virtual ~VkInteropFunctorDrawable();
void syncFunctor() const override;
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index fb1fde2..3d50d2d 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -232,9 +232,9 @@
return;
}
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
- dprintf(fd, "\nVersion: %" PRId64, proto->version_code());
- dprintf(fd, "\nStats since: %" PRId64 "ns", proto->stats_start());
- dprintf(fd, "\nStats end: %" PRId64 "ns", proto->stats_end());
+ dprintf(fd, "\nVersion: %lld", proto->version_code());
+ dprintf(fd, "\nStats since: %lldns", proto->stats_start());
+ dprintf(fd, "\nStats end: %lldns", proto->stats_end());
auto summary = proto->summary();
dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 0377426..ad76559 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -97,7 +97,6 @@
bool write(uint64_t fieldId, double val);
bool write(uint64_t fieldId, float val);
bool write(uint64_t fieldId, int val);
- bool write(uint64_t fieldId, long val);
bool write(uint64_t fieldId, long long val);
bool write(uint64_t fieldId, bool val);
bool write(uint64_t fieldId, std::string val);
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 0c62d52..ff3fad6 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -116,34 +116,6 @@
}
bool
-ProtoOutputStream::write(uint64_t fieldId, long val)
-{
- if (mCompact) return false;
- const uint32_t id = (uint32_t)fieldId;
- switch (fieldId & FIELD_TYPE_MASK) {
- case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
- case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
- case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
- case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
- case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
- case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
- case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
- case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
- case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
- case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
- case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
- case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
- case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
- case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
- default:
- ALOGW("Field type %d is not supported when writing long val.",
- (int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
- return false;
- }
- return true;
-}
-
-bool
ProtoOutputStream::write(uint64_t fieldId, long long val)
{
return internalWrite(fieldId, val, "long long");
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index b51caa5..0b3c973 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -23,9 +23,7 @@
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.SurfaceTexture;
-import android.net.Uri;
import android.os.Handler;
-import android.os.Parcel;
import android.os.PersistableBundle;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -34,7 +32,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -241,47 +238,6 @@
return new MediaPlayer2Impl(context);
}
- private static final String[] decodeMediaPlayer2Uri(String location) {
- Uri uri = Uri.parse(location);
- if (!"mediaplayer2".equals(uri.getScheme())) {
- return new String[] {location};
- }
-
- List<String> uris = uri.getQueryParameters("uri");
- if (uris.isEmpty()) {
- return new String[] {location};
- }
-
- List<String> keys = uri.getQueryParameters("key");
- List<String> values = uri.getQueryParameters("value");
- if (keys.size() != values.size()) {
- return new String[] {uris.get(0)};
- }
-
- List<String> ls = new ArrayList();
- ls.add(uris.get(0));
- for (int i = 0; i < keys.size() ; i++) {
- ls.add(keys.get(i));
- ls.add(values.get(i));
- }
-
- return ls.toArray(new String[ls.size()]);
- }
-
- private static final String encodeMediaPlayer2Uri(String uri, String[] keys, String[] values) {
- Uri.Builder builder = new Uri.Builder();
- builder.scheme("mediaplayer2").path("/").appendQueryParameter("uri", uri);
- if (keys == null || values == null || keys.length != values.length) {
- return builder.build().toString();
- }
- for (int i = 0; i < keys.length ; i++) {
- builder
- .appendQueryParameter("key", keys[i])
- .appendQueryParameter("value", values[i]);
- }
- return builder.build().toString();
- }
-
/**
* @hide
*/
@@ -291,12 +247,6 @@
}
/**
- * Returns a {@link MediaPlayerBase} implementation which runs based on
- * this MediaPlayer2 instance.
- */
- public abstract MediaPlayerBase getMediaPlayerBase();
-
- /**
* Releases the resources held by this {@code MediaPlayer2} object.
*
* It is considered good practice to call this method when you're
@@ -342,8 +292,7 @@
* Starts or resumes playback. If playback had previously been paused,
* playback will continue from where it was paused. If playback had
* reached end of stream and been paused, or never started before,
- * playback will start at the beginning. If the source had not been
- * prepared, the player will prepare the source and play.
+ * playback will start at the beginning.
*
* @return a token which can be used to cancel the operation later with {@link #cancel}.
*/
@@ -376,18 +325,6 @@
public abstract Object skipToNext();
/**
- * Moves the media to specified time position.
- * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
- *
- * @param msec the offset in milliseconds from the start to seek to
- * @return a token which can be used to cancel the operation later with {@link #cancel}.
- */
- // This is an asynchronous call.
- public Object seekTo(long msec) {
- return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
- }
-
- /**
* Gets the current playback position.
*
* @return the current position in milliseconds
@@ -404,9 +341,8 @@
/**
* Gets the current buffered media source position received through progressive downloading.
- * The received buffering percentage indicates how much of the content has been buffered
- * or played. For example a buffering update of 80 percent when half the content
- * has already been played indicates that the next 30 percent of the
+ * For example a buffering update of 8000 milliseconds when 5000 milliseconds of the content
+ * has already been played indicates that the next 3000 milliseconds of the
* content to play has been buffered.
*
* @return the current buffered media source position in milliseconds
@@ -416,7 +352,6 @@
/**
* MediaPlayer2 has not been prepared or just has been reset.
* In this state, MediaPlayer2 doesn't fetch data.
- * @hide
*/
public static final int PLAYER_STATE_IDLE = 1001;
@@ -424,26 +359,23 @@
* MediaPlayer2 has been just prepared.
* In this state, MediaPlayer2 just fetches data from media source,
* but doesn't actively render data.
- * @hide
*/
public static final int PLAYER_STATE_PREPARED = 1002;
/**
* MediaPlayer2 is paused.
- * In this state, MediaPlayer2 doesn't actively render data.
- * @hide
+ * In this state, MediaPlayer2 has allocated resources to construct playback
+ * pipeline, but it doesn't actively render data.
*/
public static final int PLAYER_STATE_PAUSED = 1003;
/**
* MediaPlayer2 is actively playing back data.
- * @hide
*/
public static final int PLAYER_STATE_PLAYING = 1004;
/**
* MediaPlayer2 has hit some fatal error and cannot continue playback.
- * @hide
*/
public static final int PLAYER_STATE_ERROR = 1005;
@@ -469,7 +401,7 @@
/**
* Sets the audio attributes for this MediaPlayer2.
* See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepare()} in order
+ * You must call this method before {@link #play()} and {@link #pause()} in order
* for the audio attributes to become effective thereafter.
* @param attributes a non-null set of audio attributes
* @return a token which can be used to cancel the operation later with {@link #cancel}.
@@ -547,7 +479,7 @@
public abstract Object setPlayerVolume(float volume);
/**
- * Returns the current volume of this player to this player.
+ * Returns the current volume of this player.
* Note that it does not take into account the associated stream volume.
* @return the player volume.
*/
@@ -561,24 +493,9 @@
}
/**
- * Create a request parcel which can be routed to the native media
- * player using {@link #invoke(Parcel, Parcel)}. The Parcel
- * returned has the proper InterfaceToken set. The caller should
- * not overwrite that token, i.e it can only append data to the
- * Parcel.
- *
- * @return A parcel suitable to hold a request for the native
- * player.
- * {@hide}
- */
- public Parcel newRequest() {
- return null;
- }
-
- /**
* Insert a task in the command queue to help the client to identify whether a batch
* of commands has been finished. When this command is processed, a notification
- * {@code EventCallback.onCommandLabelReached} will be fired with the
+ * {@link EventCallback#onCommandLabelReached onCommandLabelReached} will be fired with the
* given {@code label}.
*
* @see EventCallback#onCommandLabelReached
@@ -595,16 +512,13 @@
* portion of the media.
*
* Either a surface holder or surface must be set if a display or video sink
- * is needed. Not calling this method or {@link #setSurface(Surface)}
+ * is needed. Not calling this method or {@link #setSurface(Surface)}
* when playing back a video will result in only the audio track being played.
* A null surface holder or surface will result in only the audio track being
* played.
*
* @param sh the SurfaceHolder to use for video display
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
* @return a token which can be used to cancel the operation later with {@link #cancel}.
- * @hide
*/
public abstract Object setDisplay(SurfaceHolder sh);
@@ -624,56 +538,44 @@
*
* @param surface The {@link Surface} to be used for the video portion of
* the media.
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
* @return a token which can be used to cancel the operation later with {@link #cancel}.
*/
// This is an asynchronous call.
public abstract Object setSurface(Surface surface);
- /* Do not change these video scaling mode values below without updating
- * their counterparts in system/window.h! Please do not forget to update
- * {@link #isVideoScalingModeSupported} when new video scaling modes
- * are added.
- */
/**
- * Specifies a video scaling mode. The content is stretched to the
- * surface rendering area. When the surface has the same aspect ratio
- * as the content, the aspect ratio of the content is maintained;
- * otherwise, the aspect ratio of the content is not maintained when video
- * is being rendered.
- * There is no content cropping with this video scaling mode.
- */
- public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1;
-
- /**
- * Specifies a video scaling mode. The content is scaled, maintaining
- * its aspect ratio. The whole surface area is always used. When the
- * aspect ratio of the content is the same as the surface, no content
- * is cropped; otherwise, content is cropped to fit the surface.
- * @hide
- */
- public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2;
-
- /**
- * Sets video scaling mode. To make the target video scaling mode
- * effective during playback, this method must be called after
- * data source is set. If not called, the default video
- * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
+ * Set the low-level power management behavior for this MediaPlayer2. This
+ * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
+ * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
+ * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
*
- * <p> The supported video scaling modes are:
- * <ul>
- * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
- * </ul>
+ * <p>This function has the MediaPlayer2 access the low-level power manager
+ * service to control the device's power usage while playing is occurring.
+ * The parameter is a combination of {@link android.os.PowerManager} wake flags.
+ * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
+ * permission.
+ * By default, no attempt is made to keep the device awake during playback.
*
- * @param mode target video scaling mode. Must be one of the supported
- * video scaling modes; otherwise, IllegalArgumentException will be thrown.
+ * @param context the Context to use
+ * @param mode the power/wake mode to set
* @return a token which can be used to cancel the operation later with {@link #cancel}.
- *
- * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
- * @hide
+ * @see android.os.PowerManager
*/
- public abstract Object setVideoScalingMode(int mode);
+ // This is an asynchronous call.
+ public abstract Object setWakeMode(Context context, int mode);
+
+ /**
+ * Control whether we should use the attached SurfaceHolder to keep the
+ * screen on while video playback is occurring. This is the preferred
+ * method over {@link #setWakeMode} where possible, since it doesn't
+ * require that the application have permission for low-level wake lock
+ * access.
+ *
+ * @param screenOn Supply true to keep the screen on, false to allow it to turn off.
+ * @return a token which can be used to cancel the operation later with {@link #cancel}.
+ */
+ // This is an asynchronous call.
+ public abstract Object setScreenOnWhilePlaying(boolean screenOn);
/**
* Cancels a pending command.
@@ -702,7 +604,7 @@
* @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
* does not correspond to a valid audio device.
*/
- // This is an asynchronous call.
+ // This is a synchronous call.
@Override
public abstract boolean setPreferredDevice(AudioDeviceInfo deviceInfo);
@@ -747,58 +649,16 @@
AudioRouting.OnRoutingChangedListener listener);
/**
- * Set the low-level power management behavior for this MediaPlayer2.
+ * Returns the size of the video.
*
- * <p>This function has the MediaPlayer2 access the low-level power manager
- * service to control the device's power usage while playing is occurring.
- * The parameter is a combination of {@link android.os.PowerManager} wake flags.
- * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
- * permission.
- * By default, no attempt is made to keep the device awake during playback.
- *
- * @param context the Context to use
- * @param mode the power/wake mode to set
- * @see android.os.PowerManager
- * @hide
- */
- public abstract void setWakeMode(Context context, int mode);
-
- /**
- * Control whether we should use the attached SurfaceHolder to keep the
- * screen on while video playback is occurring. This is the preferred
- * method over {@link #setWakeMode} where possible, since it doesn't
- * require that the application have permission for low-level wake lock
- * access.
- *
- * @param screenOn Supply true to keep the screen on, false to allow it
- * to turn off.
- * @hide
- */
- public abstract void setScreenOnWhilePlaying(boolean screenOn);
-
- /**
- * Returns the width of the video.
- *
- * @return the width of the video, or 0 if there is no video,
- * no display surface was set, or the width has not been determined
- * yet. The {@code EventCallback} can be registered via
+ * @return the size of the video. The width and height of size could be 0 if there is no video,
+ * no display surface was set, or the size has not been determined yet.
+ * The {@code EventCallback} can be registered via
* {@link #setEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the width
+ * notification {@code EventCallback.onVideoSizeChanged} when the size
* is available.
*/
- public abstract int getVideoWidth();
-
- /**
- * Returns the height of the video.
- *
- * @return the height of the video, or 0 if there is no video,
- * no display surface was set, or the height has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #setEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the height is
- * available.
- */
- public abstract int getVideoHeight();
+ public abstract VideoSize getVideoSize();
/**
* Return Metrics data about the current player.
@@ -958,6 +818,18 @@
public abstract SyncParams getSyncParams();
/**
+ * Moves the media to specified time position.
+ * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
+ *
+ * @param msec the offset in milliseconds from the start to seek to
+ * @return a token which can be used to cancel the operation later with {@link #cancel}.
+ */
+ // This is an asynchronous call.
+ public Object seekTo(long msec) {
+ return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+ }
+
+ /**
* Seek modes used in method seekTo(long, int) to move media position
* to a specified location.
*
@@ -1287,11 +1159,10 @@
*
* @param mp the MediaPlayer2 associated with this callback
* @param dsd the DataSourceDesc of this data source
- * @param width the width of the video
- * @param height the height of the video
+ * @param size the size of the video
*/
public void onVideoSizeChanged(
- MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) { }
+ MediaPlayer2 mp, DataSourceDesc dsd, VideoSize size) { }
/**
* Called to indicate an avaliable timed text
@@ -1719,18 +1590,21 @@
*/
public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31;
- /** The player just completed a call {@link #setVideoScalingMode}.
- * @see EventCallback#onCallCompleted
- * @hide
- */
- public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 32;
-
/** The player just completed a call {@link #setDisplay}.
* @see EventCallback#onCallCompleted
- * @hide
*/
public static final int CALL_COMPLETED_SET_DISPLAY = 33;
+ /** The player just completed a call {@link #setWakeMode}.
+ * @see EventCallback#onCallCompleted
+ */
+ public static final int CALL_COMPLETED_SET_WAKE_MODE = 34;
+
+ /** The player just completed a call {@link #setScreenOnWhilePlaying}.
+ * @see EventCallback#onCallCompleted
+ */
+ public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35;
+
/**
* The start of the methods which have separate call complete callback.
* @hide
@@ -1776,8 +1650,9 @@
CALL_COMPLETED_SKIP_TO_NEXT,
CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
CALL_COMPLETED_SET_BUFFERING_PARAMS,
- CALL_COMPLETED_SET_VIDEO_SCALING_MODE,
CALL_COMPLETED_SET_DISPLAY,
+ CALL_COMPLETED_SET_WAKE_MODE,
+ CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING,
CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
CALL_COMPLETED_PREPARE_DRM,
})
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index ef8db1d..47ab7fac 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -19,11 +19,11 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ContentProvider;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
-import android.graphics.SurfaceTexture;
import android.graphics.Rect;
import android.media.MediaPlayer2Proto.PlayerMessage;
import android.media.MediaPlayer2Proto.Value;
@@ -34,9 +34,6 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;
@@ -78,18 +75,22 @@
native_init();
}
+ private static final int NEXT_SOURCE_STATE_ERROR = -1;
+ private static final int NEXT_SOURCE_STATE_INIT = 0;
+ private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+ private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
private final static String TAG = "MediaPlayer2Impl";
private Context mContext;
- private long mNativeContext; // accessed by native methods
+ private long mNativeContext; // accessed by native methods
private long mNativeSurfaceTexture; // accessed by native methods
- private int mListenerContext; // accessed by native methods
+ private int mListenerContext; // accessed by native methods
private SurfaceHolder mSurfaceHolder;
private PowerManager.WakeLock mWakeLock = null;
private boolean mScreenOnWhilePlaying;
private boolean mStayAwake;
- private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
private final Object mSrcLock = new Object();
//--- guarded by |mSrcLock| start
@@ -105,6 +106,7 @@
private AtomicInteger mBufferedPercentageCurrent = new AtomicInteger(0);
private AtomicInteger mBufferedPercentageNext = new AtomicInteger(0);
private volatile float mVolume = 1.0f;
+ private VideoSize mVideoSize = new VideoSize(0, 0);
// Modular DRM
private final Object mDrmLock = new Object();
@@ -134,7 +136,7 @@
/**
* Default constructor.
- * <p>When done with the MediaPlayer2Impl, you should call {@link #close()},
+ * <p>When done with the MediaPlayer2Impl, you should call {@link #close()},
* to free the resources. If not released, too many MediaPlayer2Impl instances may
* result in an exception.</p>
*/
@@ -152,45 +154,11 @@
}
@Override
- public MediaPlayerBase getMediaPlayerBase() {
- return null;
- }
-
- /**
- * Releases the resources held by this {@code MediaPlayer2} object.
- *
- * It is considered good practice to call this method when you're
- * done using the MediaPlayer2. In particular, whenever an Activity
- * of an application is paused (its onPause() method is called),
- * or stopped (its onStop() method is called), this method should be
- * invoked to release the MediaPlayer2 object, unless the application
- * has a special need to keep the object around. In addition to
- * unnecessary resources (such as memory and instances of codecs)
- * being held, failure to call this method immediately if a
- * MediaPlayer2 object is no longer needed may also lead to
- * continuous battery consumption for mobile devices, and playback
- * failure for other applications if no multiple instances of the
- * same codec are supported on a device. Even if multiple instances
- * of the same codec are supported, some performance degradation
- * may be expected when unnecessary multiple instances are used
- * at the same time.
- *
- * {@code close()} may be safely called after a prior {@code close()}.
- * This class implements the Java {@code AutoCloseable} interface and
- * may be used with try-with-resources.
- */
- @Override
public void close() {
super.close();
release();
}
- /**
- * Starts or resumes playback. If playback had previously been paused,
- * playback will continue from where it was paused. If playback had
- * been stopped, or never started before, playback will start at the
- * beginning.
- */
@Override
public Object play() {
return addTask(new Task(CALL_COMPLETED_PLAY, false) {
@@ -204,14 +172,6 @@
private native void _start() throws IllegalStateException;
- /**
- * Prepares the player for playback, asynchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepare(). For streams, you should call prepare(),
- * which returns immediately, rather than blocking until enough data has been
- * buffered.
- */
@Override
public Object prepare() {
return addTask(new Task(CALL_COMPLETED_PREPARE, true) {
@@ -224,9 +184,6 @@
public native void _prepare();
- /**
- * Pauses playback. Call play() to resume.
- */
@Override
public Object pause() {
return addTask(new Task(CALL_COMPLETED_PAUSE, false) {
@@ -241,11 +198,6 @@
private native void _pause() throws IllegalStateException;
- /**
- * Tries to play next data source if applicable.
- *
- * @throws IllegalStateException if it is called in an invalid state
- */
@Override
public Object skipToNext() {
return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
@@ -259,32 +211,12 @@
});
}
- /**
- * Gets the current playback position.
- *
- * @return the current position in milliseconds
- */
@Override
public native long getCurrentPosition();
- /**
- * Gets the duration of the file.
- *
- * @return the duration in milliseconds, if no duration is available
- * (for example, if streaming live content), -1 is returned.
- */
@Override
public native long getDuration();
- /**
- * Gets the current buffered media source position received through progressive downloading.
- * The received buffering percentage indicates how much of the content has been buffered
- * or played. For example a buffering update of 80 percent when half the content
- * has already been played indicates that the next 30 percent of the
- * content to play has been buffered.
- *
- * @return the current buffered media source position in milliseconds
- */
@Override
public long getBufferedPosition() {
// Use cached buffered percent for now.
@@ -298,14 +230,6 @@
private native int native_getState();
- /**
- * Sets the audio attributes for this MediaPlayer2.
- * See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepare()} in order
- * for the audio attributes to become effective thereafter.
- * @param attributes a non-null set of audio attributes
- * @throws IllegalArgumentException if the attributes are null or invalid.
- */
@Override
public Object setAudioAttributes(@NonNull AudioAttributes attributes) {
return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
@@ -326,11 +250,6 @@
return attributes;
}
- /**
- * Sets the data source as described by a DataSourceDesc.
- *
- * @param dsd the descriptor of data source you want to play
- */
@Override
public Object setDataSource(@NonNull DataSourceDesc dsd) {
return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
@@ -351,12 +270,6 @@
});
}
- /**
- * Sets a single data source as described by a DataSourceDesc which will be played
- * after current data source is finished.
- *
- * @param dsd the descriptor of data source you want to play after current one
- */
@Override
public Object setNextDataSource(@NonNull DataSourceDesc dsd) {
return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
@@ -374,11 +287,6 @@
});
}
- /**
- * Sets a list of data sources to be played sequentially after current data source is done.
- *
- * @param dsds the list of data sources you want to play after current one
- */
@Override
public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
@@ -428,16 +336,11 @@
}
}
- /**
- * Configures the player to loop on the current data source.
- * @param loop true if the current data source is meant to loop.
- */
@Override
public Object loopCurrent(boolean loop) {
return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
@Override
void process() {
- // TODO: set the looping mode, send notification
setLooping(loop);
}
});
@@ -445,57 +348,29 @@
private native void setLooping(boolean looping);
- /**
- * Sets the volume of the audio of the media to play, expressed as a linear multiplier
- * on the audio samples.
- * Note that this volume is specific to the player, and is separate from stream volume
- * used across the platform.<br>
- * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
- * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
- * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
- */
@Override
public Object setPlayerVolume(float volume) {
return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
@Override
void process() {
mVolume = volume;
- _setVolume(volume);
+ native_setVolume(volume);
}
});
}
- private native void _setVolume(float volume);
+ private native void native_setVolume(float volume);
- /**
- * Returns the current volume of this player to this player.
- * Note that it does not take into account the associated stream volume.
- * @return the player volume.
- */
@Override
public float getPlayerVolume() {
return mVolume;
}
- /**
- * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
- */
@Override
public float getMaxPlayerVolume() {
return 1.0f;
}
- private static final int NEXT_SOURCE_STATE_ERROR = -1;
- private static final int NEXT_SOURCE_STATE_INIT = 0;
- private static final int NEXT_SOURCE_STATE_PREPARING = 1;
- private static final int NEXT_SOURCE_STATE_PREPARED = 2;
-
- /*
- * Update the MediaPlayer2Impl SurfaceTexture.
- * Call after setting a new display surface.
- */
- private native void _setVideoSurface(Surface surface);
-
/* Do not change these values (starting with INVOKE_ID) without updating
* their counterparts in include/media/mediaplayer2.h!
*/
@@ -504,7 +379,6 @@
private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
private static final int INVOKE_ID_SELECT_TRACK = 4;
private static final int INVOKE_ID_DESELECT_TRACK = 5;
- private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
/**
@@ -518,7 +392,7 @@
* native player.
*/
private PlayerMessage invoke(PlayerMessage msg) {
- byte[] ret = _invoke(msg.toByteArray());
+ byte[] ret = native_invoke(msg.toByteArray());
if (ret == null) {
return null;
}
@@ -529,7 +403,7 @@
}
}
- private native byte[] _invoke(byte[] request);
+ private native byte[] native_invoke(byte[] request);
@Override
public Object notifyWhenCommandLabelReached(Object label) {
@@ -559,7 +433,7 @@
} else {
surface = null;
}
- _setVideoSurface(surface);
+ native_setVideoSurface(surface);
updateSurfaceScreenOn();
}
});
@@ -574,49 +448,13 @@
Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
}
mSurfaceHolder = null;
- _setVideoSurface(surface);
+ native_setVideoSurface(surface);
updateSurfaceScreenOn();
}
});
}
- /**
- * Sets video scaling mode. To make the target video scaling mode
- * effective during playback, this method must be called after
- * data source is set. If not called, the default video
- * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
- *
- * <p> The supported video scaling modes are:
- * <ul>
- * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
- * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}
- * </ul>
- *
- * @param mode target video scaling mode. Must be one of the supported
- * video scaling modes; otherwise, IllegalArgumentException will be thrown.
- *
- * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
- * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
- * @hide
- */
- @Override
- public Object setVideoScalingMode(int mode) {
- return addTask(new Task(CALL_COMPLETED_SET_VIDEO_SCALING_MODE, false) {
- @Override
- void process() {
- if (!isVideoScalingModeSupported(mode)) {
- final String msg = "Scaling mode " + mode + " is not supported";
- throw new IllegalArgumentException(msg);
- }
- PlayerMessage request = PlayerMessage.newBuilder()
- .addValues(Value.newBuilder()
- .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE))
- .addValues(Value.newBuilder().setInt32Value(mode))
- .build();
- invoke(request);
- }
- });
- }
+ private native void native_setVideoSurface(Surface surface);
@Override
public boolean cancelCommand(Object token) {
@@ -632,26 +470,6 @@
}
}
- private Object addTask(Task task) {
- synchronized (mTaskLock) {
- mPendingTasks.add(task);
- processPendingTask_l();
- }
- return task;
- }
-
- @GuardedBy("mTaskLock")
- private void processPendingTask_l() {
- if (mCurrentTask != null) {
- return;
- }
- if (!mPendingTasks.isEmpty()) {
- Task task = mPendingTasks.remove(0);
- mCurrentTask = task;
- mTaskHandler.post(task);
- }
- }
-
private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
throws IOException {
checkArgument(dsd != null, "the DataSourceDesc cannot be null");
@@ -875,9 +693,7 @@
boolean isCurrent, long srcId, Media2DataSource dataSource,
long startPos, long endPos);
- /**
- * @return true if there is a next data source, false otherwise.
- */
+ // return true if there is a next data source, false otherwise.
// This function should be always called on |mHandlerThread|.
private boolean prepareNextDataSource() {
if (Looper.myLooper() != mHandlerThread.getLooper()) {
@@ -975,30 +791,11 @@
private native void nativePlayNextDataSource(long srcId);
-
- private int getAudioStreamType() {
- if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
- mStreamType = _getAudioStreamType();
- }
- return mStreamType;
- }
-
- private native int _getAudioStreamType() throws IllegalStateException;
-
-
//--------------------------------------------------------------------------
// Explicit Routing
//--------------------
private AudioDeviceInfo mPreferredDevice = null;
- /**
- * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
- * the output from this MediaPlayer2.
- * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
- * If deviceInfo is null, default routing is restored.
- * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
- * does not correspond to a valid audio device.
- */
@Override
public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
if (deviceInfo != null && !deviceInfo.isSink()) {
@@ -1014,10 +811,6 @@
return status;
}
- /**
- * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
- * is not guaranteed to correspond to the actual device being used for playback.
- */
@Override
public AudioDeviceInfo getPreferredDevice() {
synchronized (this) {
@@ -1025,12 +818,6 @@
}
}
- /**
- * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
- * Note: The query is only valid if the MediaPlayer2 is currently playing.
- * If the player is not playing, the returned device can be null or correspond to previously
- * selected device when the player was last active.
- */
@Override
public AudioDeviceInfo getRoutedDevice() {
int deviceId = native_getRoutedDeviceId();
@@ -1047,130 +834,83 @@
return null;
}
- /*
- * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
- */
- @GuardedBy("mRoutingChangeListeners")
- private void enableNativeRoutingCallbacksLocked(boolean enabled) {
- if (mRoutingChangeListeners.size() == 0) {
- native_enableDeviceCallback(enabled);
- }
- }
-
- /**
- * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
- * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
- * by an app to receive (re)routing notifications.
- */
- @GuardedBy("mRoutingChangeListeners")
- private ArrayMap<AudioRouting.OnRoutingChangedListener,
- NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
-
- /**
- * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
- * changes on this MediaPlayer2.
- * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
- * notifications of rerouting events.
- * @param handler Specifies the {@link Handler} object for the thread on which to execute
- * the callback. If <code>null</code>, the handler on the main looper will be used.
- */
@Override
public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
Handler handler) {
- synchronized (mRoutingChangeListeners) {
- if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- enableNativeRoutingCallbacksLocked(true);
- mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : mTaskHandler));
- }
+ if (listener == null) {
+ throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL");
}
+ RoutingDelegate routingDelegate = new RoutingDelegate(this, listener, handler);
+ native_addDeviceCallback(routingDelegate);
}
- /**
- * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
- * to receive rerouting notifications.
- * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
- * to remove.
- */
@Override
public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
- synchronized (mRoutingChangeListeners) {
- if (mRoutingChangeListeners.containsKey(listener)) {
- mRoutingChangeListeners.remove(listener);
- enableNativeRoutingCallbacksLocked(false);
- }
+ if (listener == null) {
+ throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL");
}
+ native_removeDeviceCallback(listener);
}
private native final boolean native_setOutputDevice(int deviceId);
private native final int native_getRoutedDeviceId();
- private native final void native_enableDeviceCallback(boolean enabled);
+ private native void native_addDeviceCallback(RoutingDelegate rd);
+ private native void native_removeDeviceCallback(
+ AudioRouting.OnRoutingChangedListener listener);
- /**
- * Set the low-level power management behavior for this MediaPlayer2. This
- * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
- * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
- * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
- *
- * <p>This function has the MediaPlayer2 access the low-level power manager
- * service to control the device's power usage while playing is occurring.
- * The parameter is a combination of {@link android.os.PowerManager} wake flags.
- * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
- * permission.
- * By default, no attempt is made to keep the device awake during playback.
- *
- * @param context the Context to use
- * @param mode the power/wake mode to set
- * @see android.os.PowerManager
- * @hide
- */
@Override
- public void setWakeMode(Context context, int mode) {
- boolean washeld = false;
+ public Object setWakeMode(Context context, int mode) {
+ return addTask(new Task(CALL_COMPLETED_SET_WAKE_MODE, false) {
+ @Override
+ void process() {
+ boolean washeld = false;
- /* Disable persistant wakelocks in media player based on property */
- if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
- Log.w(TAG, "IGNORING setWakeMode " + mode);
- return;
- }
+ if (mWakeLock != null) {
+ if (mWakeLock.isHeld()) {
+ washeld = true;
+ mWakeLock.release();
+ }
+ mWakeLock = null;
+ }
- if (mWakeLock != null) {
- if (mWakeLock.isHeld()) {
- washeld = true;
- mWakeLock.release();
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ ActivityManager am =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List<RunningAppProcessInfo> runningAppsProcInfo = am.getRunningAppProcesses();
+ int pid = android.os.Process.myPid();
+ String name = "pid " + String.valueOf(pid);
+ if (runningAppsProcInfo != null) {
+ for (RunningAppProcessInfo procInfo : runningAppsProcInfo) {
+ if (procInfo.pid == pid) {
+ name = procInfo.processName;
+ break;
+ }
+ }
+ }
+ mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, name);
+ mWakeLock.setReferenceCounted(false);
+ if (washeld) {
+ mWakeLock.acquire();
+ }
}
- mWakeLock = null;
- }
-
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName());
- mWakeLock.setReferenceCounted(false);
- if (washeld) {
- mWakeLock.acquire();
- }
+ });
}
- /**
- * Control whether we should use the attached SurfaceHolder to keep the
- * screen on while video playback is occurring. This is the preferred
- * method over {@link #setWakeMode} where possible, since it doesn't
- * require that the application have permission for low-level wake lock
- * access.
- *
- * @param screenOn Supply true to keep the screen on, false to allow it
- * to turn off.
- * @hide
- */
@Override
- public void setScreenOnWhilePlaying(boolean screenOn) {
- if (mScreenOnWhilePlaying != screenOn) {
- if (screenOn && mSurfaceHolder == null) {
- Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
+ public Object setScreenOnWhilePlaying(boolean screenOn) {
+ return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) {
+ @Override
+ void process() {
+ if (mScreenOnWhilePlaying != screenOn) {
+ if (screenOn && mSurfaceHolder == null) {
+ Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective"
+ + " without a SurfaceHolder");
+ }
+ mScreenOnWhilePlaying = screenOn;
+ updateSurfaceScreenOn();
+ }
}
- mScreenOnWhilePlaying = screenOn;
- updateSurfaceScreenOn();
- }
+ });
}
private void stayAwake(boolean awake) {
@@ -1191,42 +931,11 @@
}
}
- /**
- * Returns the width of the video.
- *
- * @return the width of the video, or 0 if there is no video,
- * no display surface was set, or the width has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #setEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the width
- * is available.
- */
@Override
- public native int getVideoWidth();
+ public VideoSize getVideoSize() {
+ return mVideoSize;
+ }
- /**
- * Returns the height of the video.
- *
- * @return the height of the video, or 0 if there is no video,
- * no display surface was set, or the height has not been determined
- * yet. The {@code EventCallback} can be registered via
- * {@link #setEventCallback(Executor, EventCallback)} to provide a
- * notification {@code EventCallback.onVideoSizeChanged} when the height
- * is available.
- */
- @Override
- public native int getVideoHeight();
-
- /**
- * Return Metrics data about the current player.
- *
- * @return a {@link PersistableBundle} containing the set of attributes and values
- * available for the media being handled by this instance of MediaPlayer2
- * The attributes are descibed in {@link MetricsConstants}.
- *
- * Additional vendor-specific fields may also be present in
- * the return value.
- */
@Override
public PersistableBundle getMetrics() {
PersistableBundle bundle = native_getMetrics();
@@ -1235,27 +944,9 @@
private native PersistableBundle native_getMetrics();
- /**
- * Checks whether the MediaPlayer2 is playing.
- *
- * @return true if currently playing, false otherwise
- * @throws IllegalStateException if the internal player engine has not been
- * initialized or has been released.
- * @hide
- */
@Override
public native boolean isPlaying();
- /**
- * Gets the current buffering management params used by the source component.
- * Calling it only after {@code setDataSource} has been called.
- * Each type of data source might have different set of default params.
- *
- * @return the current buffering management params used by the source component.
- * @throws IllegalStateException if the internal player engine has not been
- * initialized, or {@code setDataSource} has not been called.
- * @hide
- */
@Override
@NonNull
public native BufferingParams getBufferingParams();
@@ -1905,7 +1596,6 @@
private static final int MEDIA_SUBTITLE_DATA = 201;
private static final int MEDIA_META_DATA = 202;
private static final int MEDIA_DRM_INFO = 210;
- private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private class TaskHandler extends Handler {
private MediaPlayer2Impl mMediaPlayer;
@@ -1944,80 +1634,175 @@
}
switch(msg.what) {
- case MEDIA_PREPARED:
- {
- if (dsd != null) {
+ case MEDIA_PREPARED:
+ {
+ if (dsd != null) {
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onInfo(
+ mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
+ }
+ });
+ }
+
+ synchronized (mSrcLock) {
+ Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+ + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
+
+ if (isCurrentSrcId) {
+ prepareNextDataSource();
+ } else if (isNextSrcId) {
+ mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+ if (mNextSourcePlayPending) {
+ playNextDataSource();
+ }
+ }
+ }
+
+ synchronized (mTaskLock) {
+ if (mCurrentTask != null
+ && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
+ && mCurrentTask.mDSD == dsd
+ && mCurrentTask.mNeedToWaitForEventToComplete) {
+ mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+ mCurrentTask = null;
+ processPendingTask_l();
+ }
+ }
+ return;
+ }
+
+ case MEDIA_DRM_INFO:
+ {
+ if (msg.obj == null) {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
+ } else if (msg.obj instanceof byte[]) {
+ // The PlayerMessage was parsed already in postEventFromNative
+ final DrmInfoImpl drmInfo;
+
+ synchronized (mDrmLock) {
+ if (mDrmInfoImpl != null) {
+ drmInfo = mDrmInfoImpl.makeCopy();
+ } else {
+ drmInfo = null;
+ }
+ }
+
+ // notifying the client outside the lock
+ if (drmInfo != null) {
+ sendDrmEvent(new DrmEventNotifier() {
+ @Override
+ public void notify(DrmEventCallback callback) {
+ callback.onDrmInfo(
+ mMediaPlayer, dsd, drmInfo);
+ }
+ });
+ }
+ } else {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
+ }
+ return;
+ }
+
+ case MEDIA_PLAYBACK_COMPLETE:
+ {
+ if (isCurrentSrcId) {
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onInfo(
+ mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
+ }
+ });
+ stayAwake(false);
+
+ synchronized (mSrcLock) {
+ mNextSourcePlayPending = true;
+
+ Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+ + ", currentSrcId=" + mCurrentSrcId
+ + ", nextSrcId=" + mNextSrcId);
+ }
+
+ playNextDataSource();
+ }
+
+ return;
+ }
+
+ case MEDIA_STOPPED:
+ case MEDIA_STARTED:
+ case MEDIA_PAUSED:
+ case MEDIA_SKIPPED:
+ case MEDIA_NOTIFY_TIME:
+ {
+ // Do nothing. The client should have enough information with
+ // {@link EventCallback#onMediaTimeDiscontinuity}.
+ break;
+ }
+
+ case MEDIA_BUFFERING_UPDATE:
+ {
+ final int percent = msg.arg1;
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
callback.onInfo(
- mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
+ mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
}
});
- }
- synchronized (mSrcLock) {
- Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
- + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
-
- if (isCurrentSrcId) {
- prepareNextDataSource();
- } else if (isNextSrcId) {
- mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
- if (mNextSourcePlayPending) {
- playNextDataSource();
+ synchronized (mSrcLock) {
+ if (isCurrentSrcId) {
+ mBufferedPercentageCurrent.set(percent);
+ } else if (isNextSrcId) {
+ mBufferedPercentageNext.set(percent);
}
}
+ return;
}
- synchronized (mTaskLock) {
- if (mCurrentTask != null
- && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
- && mCurrentTask.mDSD == dsd
- && mCurrentTask.mNeedToWaitForEventToComplete) {
- mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
- mCurrentTask = null;
- processPendingTask_l();
- }
- }
- return;
- }
-
- case MEDIA_DRM_INFO:
- {
- if (msg.obj == null) {
- Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
- } else if (msg.obj instanceof byte[]) {
- // The PlayerMessage was parsed already in postEventFromNative
- final DrmInfoImpl drmInfo;
-
- synchronized (mDrmLock) {
- if (mDrmInfoImpl != null) {
- drmInfo = mDrmInfoImpl.makeCopy();
- } else {
- drmInfo = null;
+ case MEDIA_SEEK_COMPLETE:
+ {
+ synchronized (mTaskLock) {
+ if (mCurrentTask != null
+ && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
+ && mCurrentTask.mNeedToWaitForEventToComplete) {
+ mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+ mCurrentTask = null;
+ processPendingTask_l();
}
}
-
- // notifying the client outside the lock
- if (drmInfo != null) {
- sendDrmEvent(new DrmEventNotifier() {
- @Override
- public void notify(DrmEventCallback callback) {
- callback.onDrmInfo(
- mMediaPlayer, dsd, drmInfo);
- }
- });
- }
- } else {
- Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
+ return;
}
- return;
- }
- case MEDIA_PLAYBACK_COMPLETE:
- {
- if (isCurrentSrcId) {
+ case MEDIA_SET_VIDEO_SIZE:
+ {
+ final int width = msg.arg1;
+ final int height = msg.arg2;
+
+ mVideoSize = new VideoSize(width, height);
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onVideoSizeChanged(
+ mMediaPlayer, dsd, mVideoSize);
+ }
+ });
+ return;
+ }
+
+ case MEDIA_ERROR:
+ {
+ Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onError(
+ mMediaPlayer, dsd, what, extra);
+ }
+ });
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
@@ -2026,231 +1811,127 @@
}
});
stayAwake(false);
-
- synchronized (mSrcLock) {
- mNextSourcePlayPending = true;
-
- Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
- + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
- }
-
- playNextDataSource();
+ return;
}
- return;
- }
-
- case MEDIA_STOPPED:
- case MEDIA_STARTED:
- case MEDIA_PAUSED:
- case MEDIA_SKIPPED:
- case MEDIA_NOTIFY_TIME:
- {
- // Do nothing. The client should have enough information with
- // {@link EventCallback#onMediaTimeDiscontinuity}.
- break;
- }
-
- case MEDIA_BUFFERING_UPDATE:
- {
- final int percent = msg.arg1;
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onInfo(
- mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
+ case MEDIA_INFO:
+ {
+ switch (msg.arg1) {
+ case MEDIA_INFO_VIDEO_TRACK_LAGGING:
+ Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
+ break;
}
- });
- synchronized (mSrcLock) {
- if (isCurrentSrcId) {
- mBufferedPercentageCurrent.set(percent);
- } else if (isNextSrcId) {
- mBufferedPercentageNext.set(percent);
- }
- }
- return;
- }
-
- case MEDIA_SEEK_COMPLETE:
- {
- synchronized (mTaskLock) {
- if (mCurrentTask != null
- && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
- && mCurrentTask.mNeedToWaitForEventToComplete) {
- mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
- mCurrentTask = null;
- processPendingTask_l();
- }
- }
- return;
- }
-
- case MEDIA_SET_VIDEO_SIZE:
- {
- final int width = msg.arg1;
- final int height = msg.arg2;
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onVideoSizeChanged(
- mMediaPlayer, dsd, width, height);
- }
- });
- return;
- }
-
- case MEDIA_ERROR:
- {
- Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onError(
- mMediaPlayer, dsd, what, extra);
- }
- });
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onInfo(
- mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
- }
- });
- stayAwake(false);
- return;
- }
-
- case MEDIA_INFO:
- {
- switch (msg.arg1) {
- case MEDIA_INFO_VIDEO_TRACK_LAGGING:
- Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
- break;
- }
-
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onInfo(
- mMediaPlayer, dsd, what, extra);
- }
- });
-
- if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
- if (isCurrentSrcId) {
- prepareNextDataSource();
- }
- }
-
- // No real default action so far.
- return;
- }
-
- case MEDIA_TIMED_TEXT:
- {
- final TimedText text;
- if (msg.obj instanceof byte[]) {
- PlayerMessage playerMsg;
- try {
- playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
- } catch (InvalidProtocolBufferException e) {
- Log.w(TAG, "Failed to parse timed text.", e);
- return;
- }
- text = TimedTextUtil.parsePlayerMessage(playerMsg);
- } else {
- text = null;
- }
-
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onTimedText(
- mMediaPlayer, dsd, text);
- }
- });
- return;
- }
-
- case MEDIA_SUBTITLE_DATA:
- {
- if (msg.obj instanceof byte[]) {
- PlayerMessage playerMsg;
- try {
- playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
- } catch (InvalidProtocolBufferException e) {
- Log.w(TAG, "Failed to parse subtitle data.", e);
- return;
- }
- Iterator<Value> in = playerMsg.getValuesList().iterator();
- SubtitleData data = new SubtitleData(
- in.next().getInt32Value(), // trackIndex
- in.next().getInt64Value(), // startTimeUs
- in.next().getInt64Value(), // durationUs
- in.next().getBytesValue().toByteArray()); // data
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
- callback.onSubtitleData(
+ callback.onInfo(
+ mMediaPlayer, dsd, what, extra);
+ }
+ });
+
+ if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
+ if (isCurrentSrcId) {
+ prepareNextDataSource();
+ }
+ }
+
+ // No real default action so far.
+ return;
+ }
+
+ case MEDIA_TIMED_TEXT:
+ {
+ final TimedText text;
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse timed text.", e);
+ return;
+ }
+ text = TimedTextUtil.parsePlayerMessage(playerMsg);
+ } else {
+ text = null;
+ }
+
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onTimedText(
+ mMediaPlayer, dsd, text);
+ }
+ });
+ return;
+ }
+
+ case MEDIA_SUBTITLE_DATA:
+ {
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse subtitle data.", e);
+ return;
+ }
+ Iterator<Value> in = playerMsg.getValuesList().iterator();
+ SubtitleData data = new SubtitleData(
+ in.next().getInt32Value(), // trackIndex
+ in.next().getInt64Value(), // startTimeUs
+ in.next().getInt64Value(), // durationUs
+ in.next().getBytesValue().toByteArray()); // data
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onSubtitleData(
+ mMediaPlayer, dsd, data);
+ }
+ });
+ }
+ return;
+ }
+
+ case MEDIA_META_DATA:
+ {
+ final TimedMetaData data;
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse timed meta data.", e);
+ return;
+ }
+ Iterator<Value> in = playerMsg.getValuesList().iterator();
+ data = new TimedMetaData(
+ in.next().getInt64Value(), // timestampUs
+ in.next().getBytesValue().toByteArray()); // metaData
+ } else {
+ data = null;
+ }
+
+ sendEvent(new EventNotifier() {
+ @Override
+ public void notify(EventCallback callback) {
+ callback.onTimedMetaDataAvailable(
mMediaPlayer, dsd, data);
}
});
- }
- return;
- }
-
- case MEDIA_META_DATA:
- {
- final TimedMetaData data;
- if (msg.obj instanceof byte[]) {
- PlayerMessage playerMsg;
- try {
- playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
- } catch (InvalidProtocolBufferException e) {
- Log.w(TAG, "Failed to parse timed meta data.", e);
- return;
- }
- Iterator<Value> in = playerMsg.getValuesList().iterator();
- data = new TimedMetaData(
- in.next().getInt64Value(), // timestampUs
- in.next().getBytesValue().toByteArray()); // metaData
- } else {
- data = null;
+ return;
}
- sendEvent(new EventNotifier() {
- @Override
- public void notify(EventCallback callback) {
- callback.onTimedMetaDataAvailable(
- mMediaPlayer, dsd, data);
- }
- });
- return;
- }
-
- case MEDIA_NOP: // interface test message - ignore
- {
- break;
- }
-
- case MEDIA_AUDIO_ROUTING_CHANGED:
- {
- AudioManager.resetAudioPortGeneration();
- synchronized (mRoutingChangeListeners) {
- for (NativeRoutingEventHandlerDelegate delegate
- : mRoutingChangeListeners.values()) {
- delegate.notifyClient();
- }
+ case MEDIA_NOP: // interface test message - ignore
+ {
+ break;
}
- return;
- }
- default:
- {
- Log.e(TAG, "Unknown message type " + msg.what);
- return;
- }
+ default:
+ {
+ Log.e(TAG, "Unknown message type " + msg.what);
+ return;
+ }
}
}
}
@@ -3388,13 +3069,6 @@
// Modular DRM end
- /*
- * Test whether a given video scaling mode is supported.
- */
- private boolean isVideoScalingModeSupported(int mode) {
- return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT ||
- mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
- }
private static class TimedTextUtil {
// These keys must be in sync with the keys in TextDescription2.h
@@ -3450,6 +3124,26 @@
}
}
+ private Object addTask(Task task) {
+ synchronized (mTaskLock) {
+ mPendingTasks.add(task);
+ processPendingTask_l();
+ }
+ return task;
+ }
+
+ @GuardedBy("mTaskLock")
+ private void processPendingTask_l() {
+ if (mCurrentTask != null) {
+ return;
+ }
+ if (!mPendingTasks.isEmpty()) {
+ Task task = mPendingTasks.remove(0);
+ mCurrentTask = task;
+ mTaskHandler.post(task);
+ }
+ }
+
private abstract class Task implements Runnable {
private final int mMediaCallType;
private final boolean mNeedToWaitForEventToComplete;
diff --git a/media/java/android/media/RoutingDelegate.java b/media/java/android/media/RoutingDelegate.java
new file mode 100644
index 0000000..2359813
--- /dev/null
+++ b/media/java/android/media/RoutingDelegate.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.media;
+
+import android.os.Handler;
+
+class RoutingDelegate implements AudioRouting.OnRoutingChangedListener {
+ private AudioRouting mAudioRouting;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ RoutingDelegate(final AudioRouting audioRouting,
+ final AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ mAudioRouting = audioRouting;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler;
+ }
+
+ public AudioRouting.OnRoutingChangedListener getListener() {
+ return mOnRoutingChangedListener;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ @Override
+ public void onRoutingChanged(AudioRouting router) {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mAudioRouting);
+ }
+ }
+}
diff --git a/media/java/android/media/VideoSize.java b/media/java/android/media/VideoSize.java
new file mode 100644
index 0000000..7e5cb1f
--- /dev/null
+++ b/media/java/android/media/VideoSize.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 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.media;
+
+/**
+ * Immutable class for describing width and height dimensions.
+ *
+ * @hide
+ */
+public final class VideoSize {
+ /**
+ * Create a new immutable VideoSize instance.
+ *
+ * @param width The width of the video size
+ * @param height The height of the video size
+ */
+ public VideoSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ /**
+ * Get the width of the video size
+ * @return width
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Get the height of the video size
+ * @return height
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Check if this video size is equal to another video size.
+ * <p>
+ * Two video sizes are equal if and only if both their widths and heights are
+ * equal.
+ * </p>
+ * <p>
+ * A video size object is never equal to any other type of object.
+ * </p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof VideoSize) {
+ VideoSize other = (VideoSize) obj;
+ return mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+ return false;
+ }
+
+ /**
+ * Return the video size represented as a string with the format {@code "WxH"}
+ *
+ * @return string representation of the video size
+ */
+ @Override
+ public String toString() {
+ return mWidth + "x" + mHeight;
+ }
+
+ private final int mWidth;
+ private final int mHeight;
+}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7cf8828..8637ada 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -543,7 +543,7 @@
import jav.util.Iterator;
HashMap<k, v> hm;
- Set<Entry<k, v> > s = hm.entrySet();
+ Set<Entry<k, v>> s = hm.entrySet();
Iterator i = s.iterator();
Entry e = s.next();
*/
@@ -613,10 +613,10 @@
}
static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
- List<Vector<uint8_t> > list) {
+ List<Vector<uint8_t>> list) {
jclass clazz = gFields.arraylistClassId;
jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
- List<Vector<uint8_t> >::iterator iter = list.begin();
+ List<Vector<uint8_t>>::iterator iter = list.begin();
while (iter != list.end()) {
jbyteArray byteArray = VectorToJByteArray(env, *iter);
env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
@@ -1216,7 +1216,7 @@
return NULL;
}
- List<Vector<uint8_t> > secureStops;
+ List<Vector<uint8_t>> secureStops;
status_t err = drm->getSecureStops(secureStops);
@@ -1237,7 +1237,7 @@
return NULL;
}
- List<Vector<uint8_t> > secureStopIds;
+ List<Vector<uint8_t>> secureStopIds;
status_t err = drm->getSecureStopIds(secureStopIds);
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 61c28ed..67005be 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -790,40 +790,6 @@
return (jint)mp->getState();
}
-static jint
-android_media_MediaPlayer2_getVideoWidth(JNIEnv *env, jobject thiz)
-{
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return 0;
- }
- int w;
- if (0 != mp->getVideoWidth(&w)) {
- ALOGE("getVideoWidth failed");
- w = 0;
- }
- ALOGV("getVideoWidth: %d", w);
- return (jint) w;
-}
-
-static jint
-android_media_MediaPlayer2_getVideoHeight(JNIEnv *env, jobject thiz)
-{
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return 0;
- }
- int h;
- if (0 != mp->getVideoHeight(&h)) {
- ALOGE("getVideoHeight failed");
- h = 0;
- }
- ALOGV("getVideoHeight: %d", h);
- return (jint) h;
-}
-
static jobject
android_media_MediaPlayer2_native_getMetrics(JNIEnv *env, jobject thiz)
{
@@ -893,20 +859,6 @@
process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
}
-static jint
-android_media_MediaPlayer2_getAudioStreamType(JNIEnv *env, jobject thiz)
-{
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return 0;
- }
- audio_stream_type_t streamtype;
- process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
- ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
- return (jint) streamtype;
-}
-
static jboolean
android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, jobject)
{
@@ -1372,15 +1324,30 @@
return mp->getRoutedDeviceId();
}
-static void android_media_MediaPlayer2_enableDeviceCallback(
- JNIEnv* env, jobject thiz, jboolean enabled)
+static void android_media_MediaPlayer2_addDeviceCallback(
+ JNIEnv* env, jobject thiz, jobject routingDelegate)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
return;
}
- status_t status = mp->enableAudioDeviceCallback(enabled);
+ status_t status = mp->addAudioDeviceCallback(routingDelegate);
+ if (status != NO_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ ALOGE("enable device callback failed: %d", status);
+ }
+}
+
+static void android_media_MediaPlayer2_removeDeviceCallback(
+ JNIEnv* env, jobject thiz, jobject listener)
+{
+ sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return;
+ }
+
+ status_t status = mp->removeAudioDeviceCallback(listener);
if (status != NO_ERROR) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
ALOGE("enable device callback failed: %d", status);
@@ -1467,14 +1434,12 @@
(void *)android_media_MediaPlayer2_handleDataSourceCallback
},
{"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
- {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
+ {"native_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
{"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
{"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"native_getState", "()I", (void *)android_media_MediaPlayer2_getState},
- {"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth},
- {"getVideoHeight", "()I", (void *)android_media_MediaPlayer2_getVideoHeight},
{"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer2_native_getMetrics},
{"_setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer2_setPlaybackParams},
{"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer2_getPlaybackParams},
@@ -1487,13 +1452,12 @@
{"getDuration", "()J", (void *)android_media_MediaPlayer2_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer2_release},
{"_reset", "()V", (void *)android_media_MediaPlayer2_reset},
- {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer2_getAudioStreamType},
{"setParameter", "(ILjava/lang/Object;)Z", (void *)android_media_MediaPlayer2_setParameter},
{"getParameter", "(I)Ljava/lang/Object;", (void *)android_media_MediaPlayer2_getParameter},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping},
- {"_setVolume", "(F)V", (void *)android_media_MediaPlayer2_setVolume},
- {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke},
+ {"native_setVolume", "(F)V", (void *)android_media_MediaPlayer2_setVolume},
+ {"native_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke},
{"native_init", "()V", (void *)android_media_MediaPlayer2_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer2_native_finalize},
@@ -1508,7 +1472,9 @@
// AudioRouting
{"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer2_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer2_getRoutedDeviceId},
- {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer2_enableDeviceCallback},
+ {"native_addDeviceCallback", "(Landroid/media/RoutingDelegate;)V", (void *)android_media_MediaPlayer2_addDeviceCallback},
+ {"native_removeDeviceCallback", "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V",
+ (void *)android_media_MediaPlayer2_removeDeviceCallback},
// StreamEventCallback for JAudioTrack
{"native_stream_event_onTearDown", "(JJ)V", (void *)android_media_MediaPlayer2_native_on_tear_down},
diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp
index 78ca0ab..a5bdba8 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/midi.cpp
@@ -338,7 +338,8 @@
numMessageBytes = std::min(maxBytes, numMessageBytes);
memcpy(buffer, readBuffer + 1, numMessageBytes);
if (timestampPtr != nullptr) {
- *timestampPtr = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
+ memcpy(timestampPtr, readBuffer + readCount - sizeof(uint64_t),
+ sizeof(*timestampPtr));
}
}
*numBytesReceivedPtr = numMessageBytes;
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 1b1bf8d..8f13497 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -30,7 +30,7 @@
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
- "android.car.user",
+ "android.car.userlib",
"androidx.car_car",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index ddc00e3..1136684 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -236,13 +236,13 @@
@NonNull ArrayList<CharSequence> smartReplies) {
Bundle signals = new Bundle();
+ if (!smartActions.isEmpty()) {
+ signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+ }
+ if (!smartReplies.isEmpty()) {
+ signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+ }
if (AUTO_DEMOTE_NOTIFICATIONS) {
- if (!smartActions.isEmpty()) {
- signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
- }
- if (!smartReplies.isEmpty()) {
- signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
- }
if (mNotificationCategorizer.shouldSilence(entry)) {
final int importance = entry.getImportance() < IMPORTANCE_LOW
? entry.getImportance() : IMPORTANCE_LOW;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
index 1eb423e..74c7b58 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.provider.Settings;
import android.util.Log;
/**
@@ -29,11 +30,11 @@
private static final String TAG = PackageInstalledReceiver.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final boolean APP_INSTALLED_NOTIFICATION_ENABLED = false;
@Override
public void onReceive(Context context, Intent intent) {
- if (!APP_INSTALLED_NOTIFICATION_ENABLED) {
+ if (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 0) {
return;
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 508adbd..e2a34f4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -21,35 +21,47 @@
<!-- Toast message when Wi-Fi cannot scan for networks -->
<string name="wifi_fail_to_scan">Can\'t scan for networks</string>
<!-- Do not translate. Concise terminology for wifi with WEP security -->
- <string name="wifi_security_short_wep">WEP</string>
+ <string name="wifi_security_short_wep" translatable="false">WEP</string>
<!-- Do not translate. Concise terminology for wifi with WPA security -->
- <string name="wifi_security_short_wpa">WPA</string>
+ <string name="wifi_security_short_wpa" translatable="false">WPA</string>
<!-- Do not translate. Concise terminology for wifi with WPA2 security -->
- <string name="wifi_security_short_wpa2">WPA2</string>
+ <string name="wifi_security_short_wpa2" translatable="false">WPA2</string>
<!-- Do not translate. Concise terminology for wifi with both WPA/WPA2 security -->
- <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
+ <string name="wifi_security_short_wpa_wpa2" translatable="false">WPA/WPA2</string>
<!-- Do not translate. Concise terminology for wifi with unknown PSK type -->
- <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
+ <string name="wifi_security_short_psk_generic" translatable="false">@string/wifi_security_short_wpa_wpa2</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_short_eap">802.1x</string>
+ <string name="wifi_security_short_eap" translatable="false">802.1x</string>
+ <!-- Do not translate. Concise terminology for wifi with WPA3 security -->
+ <string name="wifi_security_short_sae" translatable="false">WPA3</string>
+ <!-- Do not translate. Concise terminology for wifi with OWE security -->
+ <string name="wifi_security_short_owe" translatable="false">OWE</string>
+ <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security -->
+ <string name="wifi_security_short_eap_suiteb" translatable="false">Suite-B</string>
<!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
- <string name="wifi_security_none">None</string>
+ <string name="wifi_security_none" translatable="false">None</string>
<!-- Do not translate. Terminology for wifi with WEP security -->
- <string name="wifi_security_wep">WEP</string>
+ <string name="wifi_security_wep" translatable="false">WEP</string>
<!-- Do not translate. Terminology for wifi with WPA security -->
- <string name="wifi_security_wpa">WPA PSK</string>
+ <string name="wifi_security_wpa" translatable="false">WPA-Personal</string>
<!-- Do not translate. Terminology for wifi with WPA2 security -->
- <string name="wifi_security_wpa2">WPA2 PSK</string>
+ <string name="wifi_security_wpa2" translatable="false">WPA2-Personal</string>
<!-- Do not translate. Terminology for wifi with both WPA/WPA2 security, or unknown -->
- <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
+ <string name="wifi_security_wpa_wpa2" translatable="false">WPA/WPA2-Personal</string>
<!-- Do not translate. Terminology for wifi with unknown PSK type -->
- <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
+ <string name="wifi_security_psk_generic" translatable="false">@string/wifi_security_wpa_wpa2</string>
<!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
- <string name="wifi_security_eap">802.1x EAP</string>
+ <string name="wifi_security_eap" translatable="false">WPA/WPA2-Enterprise</string>
<!-- Do not translate. Concise terminology for Passpoint network -->
- <string name="wifi_security_passpoint">Passpoint</string>
+ <string name="wifi_security_passpoint" translatable="false">Passpoint</string>
+ <!-- Do not translate. Terminology for wifi with WPA3 security -->
+ <string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
+ <!-- Do not translate. Terminology for wifi with OWE security -->
+ <string name="wifi_security_owe" translatable="false">Enhanced Open</string>
+ <!-- Do not translate. Concise terminology for wifi with 802.1x EAP Suite-B security -->
+ <string name="wifi_security_eap_suiteb" translatable="false">WPA3-Enterprise</string>
<!-- Summary for the remembered network. -->
<string name="wifi_remembered">Saved</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index dd8bfda..92fd868 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -51,6 +51,8 @@
public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
public static final String CATEGORY_NIGHT_DISPLAY =
"com.android.settings.category.ia.night_display";
+ public static final String CATEGORY_PRIVACY =
+ "com.android.settings.category.ia.privacy";
public static final Map<String, String> KEY_COMPAT_MAP;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e950e8e..523361d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -158,9 +158,12 @@
* These values are matched in string arrays -- changes must be kept in sync
*/
public static final int SECURITY_NONE = 0;
- public static final int SECURITY_WEP = 1;
- public static final int SECURITY_PSK = 2;
- public static final int SECURITY_EAP = 3;
+ public static final int SECURITY_OWE = 1;
+ public static final int SECURITY_WEP = 2;
+ public static final int SECURITY_PSK = 3;
+ public static final int SECURITY_SAE = 4;
+ public static final int SECURITY_EAP = 5;
+ public static final int SECURITY_EAP_SUITE_B = 6;
private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1;
@@ -433,7 +436,7 @@
if (isConnectable()) {
builder.append(',').append("connectable");
}
- if (security != SECURITY_NONE) {
+ if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
builder.append(',').append(securityToString(security, pskType));
}
builder.append(",level=").append(getLevel());
@@ -720,6 +723,9 @@
case SECURITY_EAP:
return concise ? context.getString(R.string.wifi_security_short_eap) :
context.getString(R.string.wifi_security_eap);
+ case SECURITY_EAP_SUITE_B:
+ return concise ? context.getString(R.string.wifi_security_short_eap_suiteb) :
+ context.getString(R.string.wifi_security_eap_suiteb);
case SECURITY_PSK:
switch (pskType) {
case PSK_WPA:
@@ -739,6 +745,12 @@
case SECURITY_WEP:
return concise ? context.getString(R.string.wifi_security_short_wep) :
context.getString(R.string.wifi_security_wep);
+ case SECURITY_SAE:
+ return concise ? context.getString(R.string.wifi_security_short_sae) :
+ context.getString(R.string.wifi_security_sae);
+ case SECURITY_OWE:
+ return concise ? context.getString(R.string.wifi_security_short_owe) :
+ context.getString(R.string.wifi_security_owe);
case SECURITY_NONE:
default:
return concise ? "" : context.getString(R.string.wifi_security_none);
@@ -980,13 +992,20 @@
* Can only be called for unsecured networks.
*/
public void generateOpenNetworkConfig() {
- if (security != SECURITY_NONE)
+ if ((security != SECURITY_NONE) && (security != SECURITY_OWE)) {
throw new IllegalStateException();
+ }
if (mConfig != null)
return;
mConfig = new WifiConfiguration();
mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
- mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+
+ if (security == SECURITY_NONE) {
+ mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+ } else {
+ mConfig.allowedKeyManagement.set(KeyMgmt.OWE);
+ mConfig.requirePMF = true;
+ }
}
public void saveWifiState(Bundle savedState) {
@@ -1288,22 +1307,38 @@
private static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
+ } else if (result.capabilities.contains("SAE")) {
+ return SECURITY_SAE;
} else if (result.capabilities.contains("PSK")) {
return SECURITY_PSK;
+ } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+ return SECURITY_EAP_SUITE_B;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
+ } else if (result.capabilities.contains("OWE")) {
+ return SECURITY_OWE;
}
+
return SECURITY_NONE;
}
static int getSecurity(WifiConfiguration config) {
+ if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
+ return SECURITY_SAE;
+ }
if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
return SECURITY_PSK;
}
+ if (config.allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ return SECURITY_EAP_SUITE_B;
+ }
if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return SECURITY_EAP;
}
+ if (config.allowedKeyManagement.get(KeyMgmt.OWE)) {
+ return SECURITY_OWE;
+ }
return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
}
@@ -1321,6 +1356,12 @@
return "PSK";
} else if (security == SECURITY_EAP) {
return "EAP";
+ } else if (security == SECURITY_SAE) {
+ return "SAE";
+ } else if (security == SECURITY_EAP_SUITE_B) {
+ return "SUITE_B";
+ } else if (security == SECURITY_OWE) {
+ return "OWE";
}
return "NONE";
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index f3c43cc..db364a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -200,7 +200,8 @@
if (frictionImageView == null || mFrictionSld == null) {
return;
}
- if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+ if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+ && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
mFrictionSld.setState(STATE_SECURED);
} else if (mAccessPoint.isMetered()) {
mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 2d43762..b46c288 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1120,6 +1120,9 @@
dumpSetting(s, p,
Settings.Global.SHOW_FIRST_CRASH_DIALOG,
GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED,
+ GlobalSettingsProto.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED);
// Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
@@ -1127,6 +1130,9 @@
dumpSetting(s, p,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
+ GlobalSettingsProto.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED);
final long smartSelectToken = p.start(GlobalSettingsProto.SMART_SELECTION);
dumpSetting(s, p,
diff --git a/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml
new file mode 100644
index 0000000..8dd88b4
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<!-- Empty drawable as this is not displayed by default. Must be provided by resource overlay. -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
index 5bcce4d..12f9bb6 100644
--- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -37,6 +37,22 @@
android:text="@string/install_carrier_app_description_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- </LinearLayout>
+
+ <com.android.setupwizardlib.view.FillContentLayout
+ android:id="@+id/illo_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:visibility="gone">
+
+ <ImageView
+ android:src="@drawable/illo_sim_app_dialog"
+ style="@style/SuwContentIllustration"
+ android:contentDescription="@string/install_carrier_app_image_content_description"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ </com.android.setupwizardlib.view.FillContentLayout>
+</LinearLayout>
</com.android.setupwizardlib.GlifLayout>
diff --git a/packages/SimAppDialog/res/values/bools.xml b/packages/SimAppDialog/res/values/bools.xml
new file mode 100644
index 0000000..4953d5e
--- /dev/null
+++ b/packages/SimAppDialog/res/values/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!--
+ Whether to show an illustration on the screen asking the user to download the carrier app.
+ May be set to true in a resource overlay as long as a drawable asset with ID
+ illo_sim_app_dialog is provided, along with a content description for accessibility with
+ string ID install_carrier_app_image_content_description.
+ -->
+ <bool name="show_sim_app_dialog_illo">false</bool>
+</resources>
diff --git a/packages/SimAppDialog/res/values/strings.xml b/packages/SimAppDialog/res/values/strings.xml
index 87941cb..9e8359c 100644
--- a/packages/SimAppDialog/res/values/strings.xml
+++ b/packages/SimAppDialog/res/values/strings.xml
@@ -32,4 +32,6 @@
<string name="install_carrier_app_defer_action">Not now</string>
<!-- Name of the button for downloading the carrier app [CHAR LIMIT=25] -->
<string name="install_carrier_app_download_action">Download app</string>
-</resources>
\ No newline at end of file
+ <!-- Empty placeholder string for an illustration content description that is supplied via resource overlay. [DO NOT TRANSLATE] -->
+ <string name="install_carrier_app_image_content_description" translatable="false" />
+</resources>
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
index 9e9b80d..8e8d9f7 100644
--- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -65,6 +65,11 @@
Button downloadButton = findViewById(R.id.download_button);
downloadButton.setOnClickListener(this);
+ // Show/hide illo depending on whether one was provided in a resource overlay
+ boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo);
+ View illoContainer = findViewById(R.id.illo_container);
+ illoContainer.setVisibility(showIllo ? View.VISIBLE : View.GONE);
+
// Include carrier name in description text if its present in the intent
Intent intent = getIntent();
if (intent != null) {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b770d5c..a00baad 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -66,7 +66,7 @@
libs: [
"telephony-common",
"android.car",
- "android.car.user",
+ "android.car.userlib",
],
aaptflags: [
@@ -120,7 +120,7 @@
"android.test.runner",
"telephony-common",
"android.car",
- "android.car.user",
+ "android.car.userlib",
"android.test.base",
],
aaptflags: [
@@ -146,7 +146,7 @@
libs: [
"telephony-common",
"android.car",
- "android.car.user",
+ "android.car.userlib",
],
dxflags: ["--multi-dex"],
@@ -183,7 +183,7 @@
libs: [
"telephony-common",
"android.car",
- "android.car.user",
+ "android.car.userlib",
],
srcs: [
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
index 0d758df..dfa38ba 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
@@ -497,7 +497,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mSystemInsets.set(insets.getSystemWindowInsets());
+ mSystemInsets.set(insets.getSystemWindowInsetsAsRect());
mTaskStackView.setSystemInsets(mSystemInsets);
requestLayout();
return insets;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
new file mode 100644
index 0000000..dce02e1
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingPlugin.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Used to capture Falsing data (related to unlocking the screen).
+ *
+ * The intent is that the data can later be analyzed to validate the quality of the
+ * {@link com.android.systemui.classifier.FalsingManager}.
+ */
+@ProvidesInterface(action = FalsingPlugin.ACTION, version = FalsingPlugin.VERSION)
+public interface FalsingPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.FALSING_PLUGIN";
+ int VERSION = 1;
+
+ /**
+ * Called when there is data to be recorded.
+ *
+ * @param success Indicates whether the action is considered a success.
+ * @param data The raw data to be recorded for analysis.
+ */
+ void dataCollected(boolean success, byte[] data);
+}
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index d4dfdee..d041556 100644
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -21,6 +21,6 @@
<corners android:radius="1dp"
android:topLeftRadius="@dimen/biometric_dialog_corner_size"
android:topRightRadius="@dimen/biometric_dialog_corner_size"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"/>
+ android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
+ android:bottomRightRadius="@dimen/biometric_dialog_corner_size"/>
</shape>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index ec25e31..67c0adf 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -31,7 +31,8 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
<!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
on horizontal/portrait orientation -->
@@ -43,11 +44,13 @@
<LinearLayout
android:id="@+id/dialog"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:elevation="2dp"
- android:background="@drawable/biometric_dialog_bg">
+ android:background="@drawable/biometric_dialog_bg"
+ android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
+ android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
+ android:layout_marginRight="@dimen/biometric_dialog_border_padding">
<TextView
android:id="@+id/title"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c61b1d2..d8648fa 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -147,7 +147,7 @@
<!-- The number of milliseconds before the ambient notification auto-dismisses. This will
override the default pulse length. -->
- <integer name="ambient_notification_decay">6000</integer>
+ <integer name="ambient_notification_decay">10000</integer>
<!-- Minimum display time for a heads up notification, in milliseconds. -->
<integer name="ambient_notification_minimum_time">2000</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 525421a..3050e79 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -889,6 +889,7 @@
<dimen name="biometric_dialog_biometric_icon_size">64dp</dimen>
<dimen name="biometric_dialog_corner_size">4dp</dimen>
<dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
+ <dimen name="biometric_dialog_border_padding">4dp</dimen>
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7d09c00..6f5d657 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2131,7 +2131,7 @@
<string name="app_info">App info</string>
<!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] -->
- <string name="go_to_web">Go to web</string>
+ <string name="go_to_web">Go to browser</string>
<!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
<string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 2bc0e45c..e051317 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,54 +15,164 @@
*/
package com.android.keyguard;
-import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.DEFAULT_DISPLAY;
+import android.annotation.Nullable;
import android.app.Presentation;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
import android.graphics.Point;
+import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
-import android.util.Slog;
+import android.util.Log;
+import android.util.SparseArray;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
+import java.util.function.BooleanSupplier;
+
// TODO(multi-display): Support multiple external displays
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
private final ViewMediatorCallback mCallback;
+
private final MediaRouter mMediaRouter;
+ private final DisplayManager mDisplayService;
private final Context mContext;
- Presentation mPresentation;
private boolean mShowing;
+ private final SparseArray<Presentation> mPresentations = new SparseArray<>();
+
+ private final DisplayManager.DisplayListener mDisplayListener =
+ new DisplayManager.DisplayListener() {
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ final Display display = mDisplayService.getDisplay(displayId);
+ if (mShowing) {
+ notifyIfChanged(() -> showPresentation(display));
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == DEFAULT_DISPLAY) return;
+ final Display display = mDisplayService.getDisplay(displayId);
+ if (display != null && mShowing) {
+ final Presentation presentation = mPresentations.get(displayId);
+ if (presentation != null && !presentation.getDisplay().equals(display)) {
+ hidePresentation(displayId);
+ showPresentation(display);
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ notifyIfChanged(() -> hidePresentation(displayId));
+ }
+ };
+
public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
mContext = context;
mCallback = callback;
- mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mMediaRouter = mContext.getSystemService(MediaRouter.class);
+ mDisplayService = mContext.getSystemService(DisplayManager.class);
+ mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
+ }
+
+ /**
+ * @param display The display to show the presentation on.
+ * @return {@code true} if a presentation was added.
+ * {@code false} if the presentation cannot be added on that display or the presentation
+ * was already there.
+ */
+ private boolean showPresentation(Display display) {
+ if (display == null || display.getDisplayId() == DEFAULT_DISPLAY) return false;
+ if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
+ final int displayId = display.getDisplayId();
+ Presentation presentation = mPresentations.get(displayId);
+ if (presentation == null) {
+ presentation = new KeyguardPresentation(mContext, display);
+ presentation.setOnDismissListener(dialog -> {
+ if (null != mPresentations.get(displayId)) {
+ mPresentations.remove(displayId);
+ }
+ });
+ try {
+ presentation.show();
+ } catch (WindowManager.InvalidDisplayException ex) {
+ Log.w(TAG, "Invalid display:", ex);
+ presentation = null;
+ }
+ if (presentation != null) {
+ mPresentations.append(displayId, presentation);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param displayId The id of the display to hide the presentation off.
+ * @return {@code true} if the a presentation was removed.
+ * {@code false} if the presentation was not added before.
+ */
+ private boolean hidePresentation(int displayId) {
+ final Presentation presentation = mPresentations.get(displayId);
+ if (presentation != null) {
+ presentation.dismiss();
+ mPresentations.remove(displayId);
+ return true;
+ }
+ return false;
+ }
+
+ private void notifyIfChanged(BooleanSupplier updateMethod) {
+ if (updateMethod.getAsBoolean()) {
+ final int[] displayList = getPresentationDisplayIds();
+ mCallback.onSecondaryDisplayShowingChanged(displayList);
+ }
+ }
+
+ /**
+ * @return An array of displayId's on which a {@link KeyguardPresentation} is showing on.
+ */
+ @Nullable
+ private int[] getPresentationDisplayIds() {
+ final int size = mPresentations.size();
+ if (size == 0) return null;
+
+ final int[] displayIds = new int[size];
+ for (int i = mPresentations.size() - 1; i >= 0; i--) {
+ final Presentation presentation = mPresentations.valueAt(i);
+ if (presentation != null) {
+ displayIds[i] = presentation.getDisplay().getDisplayId();
+ }
+ }
+ return displayIds;
}
public void show() {
if (!mShowing) {
- if (DEBUG) Slog.v(TAG, "show");
+ if (DEBUG) Log.v(TAG, "show");
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
- updateDisplays(true);
+ notifyIfChanged(() -> updateDisplays(true /* showing */));
}
mShowing = true;
}
public void hide() {
if (mShowing) {
- if (DEBUG) Slog.v(TAG, "hide");
+ if (DEBUG) Log.v(TAG, "hide");
mMediaRouter.removeCallback(mMediaRouterCallback);
- updateDisplays(false);
+ notifyIfChanged(() -> updateDisplays(false /* showing */));
}
mShowing = false;
}
@@ -71,71 +181,38 @@
new MediaRouter.SimpleCallback() {
@Override
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
- if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
- updateDisplays(mShowing);
+ if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
+ notifyIfChanged(() -> updateDisplays(mShowing));
}
@Override
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
- if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
- updateDisplays(mShowing);
+ if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
+ notifyIfChanged(() -> updateDisplays(mShowing));
}
@Override
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
- if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
- updateDisplays(mShowing);
+ if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
+ notifyIfChanged(() -> updateDisplays(mShowing));
}
};
- private OnDismissListener mOnDismissListener = new OnDismissListener() {
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- mPresentation = null;
- }
- };
-
- protected void updateDisplays(boolean showing) {
- Presentation originalPresentation = mPresentation;
+ protected boolean updateDisplays(boolean showing) {
+ boolean changed = false;
if (showing) {
- MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
- MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
- boolean useDisplay = route != null
- && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
- Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
-
- if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
- if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
- mPresentation.dismiss();
- mPresentation = null;
- }
-
- if (mPresentation == null && presentationDisplay != null) {
- if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
- mPresentation = new KeyguardPresentation(mContext, presentationDisplay,
- R.style.keyguard_presentation_theme);
- mPresentation.setOnDismissListener(mOnDismissListener);
- try {
- mPresentation.show();
- } catch (WindowManager.InvalidDisplayException ex) {
- Slog.w(TAG, "Invalid display:", ex);
- mPresentation = null;
- }
+ final Display[] displays = mDisplayService.getDisplays();
+ for (Display display : displays) {
+ changed |= showPresentation(display);
}
} else {
- if (mPresentation != null) {
- mPresentation.dismiss();
- mPresentation = null;
+ changed = mPresentations.size() > 0;
+ for (int i = mPresentations.size() - 1; i >= 0; i--) {
+ mPresentations.valueAt(i).dismiss();
}
+ mPresentations.clear();
}
-
- // mPresentation is only updated when the display changes
- if (mPresentation != originalPresentation) {
- final int displayId = mPresentation != null
- ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
- mCallback.onSecondaryDisplayShowingChanged(displayId);
- }
+ return changed;
}
private final static class KeyguardPresentation extends Presentation {
@@ -157,9 +234,10 @@
}
};
- public KeyguardPresentation(Context context, Display display, int theme) {
- super(context, display, theme);
+ KeyguardPresentation(Context context, Display display) {
+ super(context, display, R.style.keyguard_presentation_theme);
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ setCancelable(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 50b98a1..79966f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -17,6 +17,8 @@
package com.android.keyguard;
import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
@@ -80,6 +82,7 @@
private float mDarkAmount = 0;
private LiveData<Slice> mLiveData;
+ private int mDisplayId = INVALID_DISPLAY;
private int mIconSize;
/**
* Runnable called whenever the view contents change.
@@ -129,6 +132,7 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mDisplayId = getDisplay().getDisplayId();
// Make sure we always have the most current slice
mLiveData.observeForever(this);
Dependency.get(ConfigurationController.class).addCallback(this);
@@ -138,7 +142,10 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mLiveData.removeObserver(this);
+ // TODO(b/117344873) Remove below work around after this issue be fixed.
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ mLiveData.removeObserver(this);
+ }
Dependency.get(ConfigurationController.class).removeCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 41b86a7..a07c5cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -96,9 +96,9 @@
int getBouncerPromptReason();
/**
- * Invoked when the secondary display showing a keyguard window changes.
+ * Invoked when the secondary displays showing a keyguard window changes.
*/
- void onSecondaryDisplayShowingChanged(int displayId);
+ void onSecondaryDisplayShowingChanged(int[] displayId);
/**
* Consumes a message that was enqueued to be displayed on the next time the bouncer shows up.
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 3fe9944..e3584cf 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -33,10 +33,11 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
+
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
@@ -604,13 +605,15 @@
}
// don't let items that can't be dismissed be dragged more than
// maxScrollDistance
- if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
+ if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(mCurrView,
+ delta > 0)) {
float size = getSize(mCurrView);
float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
if (absDelta >= size) {
delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
} else {
- delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
+ delta = maxScrollDistance * (float) Math.sin(
+ (delta / size) * (Math.PI / 2));
}
}
@@ -674,9 +677,11 @@
}
public boolean isDismissGesture(MotionEvent ev) {
+ float translation = getTranslation(mCurrView);
return ev.getActionMasked() == MotionEvent.ACTION_UP
+ && !mFalsingManager.isUnlockingDisabled()
&& !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough())
- && mCallback.canChildBeDismissed(mCurrView);
+ && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0);
}
public boolean isFalseGesture(MotionEvent ev) {
@@ -707,6 +712,16 @@
boolean canChildBeDismissed(View v);
+ /**
+ * Returns true if the provided child can be dismissed by a swipe in the given direction.
+ *
+ * @param isRightOrDown {@code true} if the swipe direction is right or down,
+ * {@code false} if it is left or up.
+ */
+ default boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+ return canChildBeDismissed(v);
+ }
+
boolean isAntiFalsingNeeded();
void onBeginDrag(View v);
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 69e347c9..46e004c 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -16,6 +16,9 @@
package com.android.systemui.analytics;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
+
import android.content.Context;
import android.database.ContentObserver;
import android.hardware.Sensor;
@@ -32,13 +35,15 @@
import android.view.MotionEvent;
import android.widget.Toast;
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.FalsingPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
-import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
-
/**
* Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked
* the data containing these events is saved to a file. This data is collected
@@ -53,6 +58,8 @@
private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches";
private static final String ALLOW_REJECTED_TOUCH_REPORTS =
"data_collector_allow_rejected_touch_reports";
+ private static final String DISABLE_UNLOCKING_FOR_FALSING_COLLECTION =
+ "data_collector_disable_unlocking";
private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
public static final boolean DEBUG = false;
@@ -65,14 +72,16 @@
private SensorLoggerSession mCurrentSession = null;
private boolean mEnableCollector = false;
- private boolean mTimeoutActive = false;
private boolean mCollectBadTouches = false;
private boolean mCornerSwiping = false;
private boolean mTrackingStarted = false;
private boolean mAllowReportRejectedTouch = false;
+ private boolean mDisableUnlocking = false;
private static DataCollector sInstance = null;
+ private FalsingPlugin mFalsingPlugin = null;
+
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -80,6 +89,16 @@
}
};
+ private final PluginListener mPluginListener = new PluginListener<FalsingPlugin>() {
+ public void onPluginConnected(FalsingPlugin plugin, Context context) {
+ mFalsingPlugin = plugin;
+ }
+
+ public void onPluginDisconnected(FalsingPlugin plugin) {
+ mFalsingPlugin = null;
+ }
+ };
+
private DataCollector(Context context) {
mContext = context;
@@ -98,7 +117,14 @@
mSettingsObserver,
UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(DISABLE_UNLOCKING_FOR_FALSING_COLLECTION), false,
+ mSettingsObserver,
+ UserHandle.USER_ALL);
+
updateConfiguration();
+
+ Dependency.get(PluginManager.class).addPluginListener(mPluginListener, FalsingPlugin.class);
}
public static DataCollector getInstance(Context context) {
@@ -118,6 +144,9 @@
mAllowReportRejectedTouch = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
mContext.getContentResolver(),
ALLOW_REJECTED_TOUCH_REPORTS, 0);
+ mDisableUnlocking = mEnableCollector && Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ DISABLE_UNLOCKING_FOR_FALSING_COLLECTION, 0);
}
private boolean sessionEntrypoint() {
@@ -144,7 +173,7 @@
SensorLoggerSession session = mCurrentSession;
mCurrentSession = null;
- if (mEnableCollector) {
+ if (mEnableCollector || mDisableUnlocking) {
session.end(System.currentTimeMillis(), result);
queueSession(session);
}
@@ -181,24 +210,28 @@
@Override
public void run() {
byte[] b = Session.toByteArray(currentSession.toProto());
- String dir = mContext.getFilesDir().getAbsolutePath();
- if (currentSession.getResult() != Session.SUCCESS) {
- if (!mCollectBadTouches) {
- return;
- }
- dir += "/bad_touches";
+
+ if (mFalsingPlugin != null) {
+ mFalsingPlugin.dataCollected(currentSession.getResult() == Session.SUCCESS, b);
} else {
- dir += "/good_touches";
- }
+ String dir = mContext.getFilesDir().getAbsolutePath();
+ if (currentSession.getResult() != Session.SUCCESS) {
+ if (!mDisableUnlocking && !mCollectBadTouches) {
+ return;
+ }
+ dir += "/bad_touches";
+ } else if (!mDisableUnlocking) {
+ dir += "/good_touches";
+ }
- File file = new File(dir);
- file.mkdir();
- File touch = new File(file, "trace_" + System.currentTimeMillis());
-
- try {
- new FileOutputStream(touch).write(b);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ File file = new File(dir);
+ file.mkdir();
+ File touch = new File(file, "trace_" + System.currentTimeMillis());
+ try {
+ new FileOutputStream(touch).write(b);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
});
@@ -208,19 +241,6 @@
public synchronized void onSensorChanged(SensorEvent event) {
if (isEnabled() && mCurrentSession != null) {
mCurrentSession.addSensorEvent(event, System.nanoTime());
- enforceTimeout();
- }
- }
-
- private void enforceTimeout() {
- if (mTimeoutActive) {
- if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
- > TIMEOUT_MILLIS) {
- onSessionEnd(Session.UNKNOWN);
- if (DEBUG) {
- Log.i(TAG, "Analytics timed out.");
- }
- }
}
}
@@ -233,9 +253,12 @@
* rejected touch report.
*/
public boolean isEnabled() {
- return mEnableCollector || mAllowReportRejectedTouch;
+ return mEnableCollector || mAllowReportRejectedTouch || mDisableUnlocking;
}
+ public boolean isUnlockingDisabled() {
+ return mDisableUnlocking;
+ }
/**
* @return true if the full data set for data gathering should be collected - including
* extensive sensor data, which is is not normally included with rejected touch reports.
@@ -450,7 +473,6 @@
}
mCurrentSession.addMotionEvent(event);
mCurrentSession.setTouchArea(width, height);
- enforceTimeout();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 7935115..1faae9d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -42,6 +42,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
/**
* Abstract base class. Shows a dialog for BiometricPrompt.
@@ -199,7 +200,10 @@
final Button negative = mLayout.findViewById(R.id.button2);
final Button positive = mLayout.findViewById(R.id.button1);
- mDialog.getLayoutParams().width = (int) mDialogWidth;
+ if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
+ mDialog.getLayoutParams().width = (int) mDialogWidth;
+ }
+
mLastState = STATE_NONE;
updateState(STATE_AUTHENTICATING);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 3d578c3..2c61da3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -201,6 +201,9 @@
return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
}
+ public boolean isUnlockingDisabled() {
+ return mDataCollector.isUnlockingDisabled();
+ }
/**
* @return true if the classifier determined that this is not a human interacting with the phone
*/
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 4988f07..fe1b356 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
@@ -95,6 +94,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Mediates requests related to the keyguard. This includes queries about the
@@ -246,8 +246,8 @@
// AOD is enabled and status bar is in AOD state.
private boolean mAodShowing;
- // display id of the secondary display on which we have put a keyguard window
- private int mSecondaryDisplayShowing = INVALID_DISPLAY;
+ // display ids of the external display on which we have put a keyguard window
+ private int[] mSecondaryDisplaysShowing;
/** Cached value of #isInputRestricted */
private boolean mInputRestricted;
@@ -700,9 +700,9 @@
}
@Override
- public void onSecondaryDisplayShowingChanged(int displayId) {
+ public void onSecondaryDisplayShowingChanged(int[] displayIds) {
synchronized (KeyguardViewMediator.this) {
- setShowingLocked(mShowing, mAodShowing, displayId, false);
+ setShowingLocked(mShowing, mAodShowing, displayIds, false);
}
}
};
@@ -749,10 +749,10 @@
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser()),
- mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */);
+ mAodShowing, mSecondaryDisplaysShowing, true /* forceCallbacks */);
} else {
// The system's keyguard is disabled or missing.
- setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true);
+ setShowingLocked(false, mAodShowing, mSecondaryDisplaysShowing, true);
}
mStatusBarKeyguardViewManager =
@@ -1776,11 +1776,11 @@
}
private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
- int secondaryDisplayShowing) {
+ int[] secondaryDisplaysShowing) {
mUiOffloadThread.submit(() -> {
try {
ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing,
- secondaryDisplayShowing);
+ secondaryDisplaysShowing);
} catch (RemoteException e) {
}
});
@@ -1895,7 +1895,8 @@
if (!mHiding) {
// Tell ActivityManager that we canceled the keyguardExitAnimation.
- setShowingLocked(mShowing, mAodShowing, mSecondaryDisplayShowing, true /* force */);
+ setShowingLocked(mShowing, mAodShowing, mSecondaryDisplaysShowing,
+ true /* force */);
return;
}
mHiding = false;
@@ -2164,22 +2165,23 @@
}
private void setShowingLocked(boolean showing, boolean aodShowing) {
- setShowingLocked(showing, aodShowing, mSecondaryDisplayShowing,
+ setShowingLocked(showing, aodShowing, mSecondaryDisplaysShowing,
false /* forceCallbacks */);
}
- private void setShowingLocked(boolean showing, boolean aodShowing, int secondaryDisplayShowing,
- boolean forceCallbacks) {
+ private void setShowingLocked(boolean showing, boolean aodShowing,
+ int[] secondaryDisplaysShowing, boolean forceCallbacks) {
final boolean notifyDefaultDisplayCallbacks = showing != mShowing
|| aodShowing != mAodShowing || forceCallbacks;
- if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) {
+ if (notifyDefaultDisplayCallbacks
+ || !Arrays.equals(secondaryDisplaysShowing, mSecondaryDisplaysShowing)) {
mShowing = showing;
mAodShowing = aodShowing;
- mSecondaryDisplayShowing = secondaryDisplayShowing;
+ mSecondaryDisplaysShowing = secondaryDisplaysShowing;
if (notifyDefaultDisplayCallbacks) {
notifyDefaultDisplayCallbacks(showing);
}
- updateActivityLockScreenState(showing, aodShowing, secondaryDisplayShowing);
+ updateActivityLockScreenState(showing, aodShowing, secondaryDisplaysShowing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 568a039..35ae899 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -399,8 +399,8 @@
if (b != null) {
mThermalService = IThermalService.Stub.asInterface(b);
try {
- mThermalService.registerThermalEventListener(
- new ThermalEventListener());
+ mThermalService.registerThermalEventListenerWithType(
+ new ThermalEventListener(), Temperature.TYPE_SKIN);
} catch (RemoteException e) {
// Should never happen.
}
@@ -552,7 +552,7 @@
// Thermal event received from vendor thermal management subsystem
private final class ThermalEventListener extends IThermalEventListener.Stub {
- @Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
+ @Override public void notifyThrottling(Temperature temp) {
// Trigger an update of the temperature warning. Only one
// callback can be enabled at a time, so remove any existing
// callback; updateTemperatureWarning will schedule another one.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 8526afd..8a86826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -128,7 +128,8 @@
}
return true;
case MotionEvent.ACTION_UP:
- if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild,
+ if (!mFalsingManager.isUnlockingDisabled() && !isFalseTouch()
+ && mDragDownCallback.onDraggedDown(mStartingChild,
(int) (y - mInitialTouchY))) {
if (mStartingChild == null) {
cancelExpansion();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a00eac4..960d221 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -51,6 +51,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -66,7 +67,7 @@
/**
* Controls the indications and error messages shown on the Keyguard
*/
-public class KeyguardIndicationController {
+public class KeyguardIndicationController implements StateListener {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -154,6 +155,19 @@
mContext.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_TIME_TICK), null,
Dependency.get(Dependency.TIME_TICK_HANDLER));
+
+ Dependency.get(StatusBarStateController.class).addListener(this);
+ }
+
+ /**
+ * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
+ * controller a chance to unregister itself as a receiver.
+ *
+ * //TODO: This can probably be converted to a fragment and not have to be manually recreated
+ */
+ public void destroy() {
+ mContext.unregisterReceiver(mTickReceiver);
+ Dependency.get(StatusBarStateController.class).removeListener(this);
}
/**
@@ -518,6 +532,16 @@
updateAlphas();
}
+ @Override
+ public void onStateChanged(int newState) {
+ // don't care
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
+
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
private int mLastSuccessiveErrorMessage = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 8994568..bc662e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
package com.android.systemui.statusbar;
import android.content.pm.UserInfo;
-import android.os.SystemProperties;
import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
@@ -26,8 +25,6 @@
String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
- boolean AUTO_DEMOTE_NOTIFICATIONS = SystemProperties.getBoolean("debug.demote_notifs", false);
-
boolean shouldAllowLockscreenRemoteInput();
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 0108469..e3bc5b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -49,6 +49,7 @@
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -293,7 +294,7 @@
return false;
}
boolean exceedsPriorityThreshold;
- if (AUTO_DEMOTE_NOTIFICATIONS) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)) {
exceedsPriorityThreshold =
getEntryManager().getNotificationData().getImportance(sbn.getKey())
>= IMPORTANCE_DEFAULT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index c35e1da..bc3638e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -21,6 +21,7 @@
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.util.Log;
+import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +36,6 @@
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.StatusBarState;
@@ -268,6 +268,14 @@
buildNavBarWindows();
buildNavBarContent();
attachNavBarWindows();
+
+ // Add external navigation bars if more than one displays exist.
+ final Display[] displays = mDisplayManager.getDisplays();
+
+ for (Display display : displays) {
+ // TODO(115978725): Add phone navigationBar for now
+ addExternalNavigationBar(display);
+ }
}
private void buildNavBarContent() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 66ba9e9..1f48c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar.notification;
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
+
import android.content.Context;
import android.graphics.Color;
+import android.provider.Settings;
import android.view.View;
import android.widget.ImageView;
@@ -68,4 +71,10 @@
context.getResources().getDisplayMetrics().density);
return (int) (dimensionPixelSize * factor);
}
+
+ /** Returns the value of the new interruption model setting. */
+ public static boolean useNewInterruptionModel(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 0) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index b5fbde1..5dfd5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -29,9 +29,11 @@
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.UiOffloadThread;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import java.util.ArrayList;
@@ -42,7 +44,7 @@
* Handles notification logging, in particular, logging which notifications are visible and which
* are not.
*/
-public class NotificationLogger {
+public class NotificationLogger implements StateListener {
private static final String TAG = "NotificationLogger";
/** The minimum delay in ms between reports of notification visibility. */
@@ -63,7 +65,7 @@
protected IStatusBarService mBarService;
private long mLastVisibilityReportUptimeMs;
private NotificationListContainer mListContainer;
- private Object mDozingLock = new Object();
+ private final Object mDozingLock = new Object();
private boolean mDozing;
protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
@@ -146,6 +148,8 @@
public NotificationLogger() {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ // Not expected to be destroyed, don't need to unsubscribe
+ Dependency.get(StatusBarStateController.class).addListener(this);
}
public void setUpWithContainer(NotificationListContainer listContainer) {
@@ -175,7 +179,7 @@
mNotificationLocationsChangedListener.onChildLocationsChanged();
}
- public void setDozing(boolean dozing) {
+ private void setDozing(boolean dozing) {
synchronized (mDozingLock) {
mDozing = dozing;
}
@@ -258,6 +262,16 @@
return mVisibilityReporter;
}
+ @Override
+ public void onStateChanged(int newState) {
+ // don't care about state change
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 7e60c4b..674c8ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,17 +16,8 @@
package com.android.systemui.statusbar.notification.row;
-import java.util.ArrayList;
-
import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -45,6 +36,15 @@
import android.widget.FrameLayout.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
+import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+
+import java.util.ArrayList;
+import java.util.List;
public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
ExpandableNotificationRow.LayoutListener {
@@ -70,7 +70,8 @@
private MenuItem mInfoItem;
private MenuItem mAppOpsItem;
private MenuItem mSnoozeItem;
- private ArrayList<MenuItem> mMenuItems;
+ private ArrayList<MenuItem> mLeftMenuItems;
+ private ArrayList<MenuItem> mRightMenuItems;
private OnMenuEventListener mMenuListener;
private ValueAnimator mFadeAnimator;
@@ -107,12 +108,13 @@
mContext = context;
mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear);
mHandler = new Handler(Looper.getMainLooper());
- mMenuItems = new ArrayList<>();
+ mLeftMenuItems = new ArrayList<>();
+ mRightMenuItems = new ArrayList<>();
}
@Override
public ArrayList<MenuItem> getMenuItems(Context context) {
- return mMenuItems;
+ return mOnLeft ? mLeftMenuItems : mRightMenuItems;
}
@Override
@@ -231,7 +233,8 @@
final Resources res = mContext.getResources();
mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
- mMenuItems.clear();
+ mLeftMenuItems.clear();
+ mRightMenuItems.clear();
// Construct the menu items based on the notification
if (mParent != null && mParent.getStatusBarNotification() != null) {
int flags = mParent.getStatusBarNotification().getNotification().flags;
@@ -239,24 +242,19 @@
if (!isForeground) {
// Only show snooze for non-foreground notifications
mSnoozeItem = createSnoozeItem(mContext);
- mMenuItems.add(mSnoozeItem);
+ mLeftMenuItems.add(mSnoozeItem);
+ mRightMenuItems.add(mSnoozeItem);
}
}
mInfoItem = createInfoItem(mContext);
- mMenuItems.add(mInfoItem);
+ mLeftMenuItems.add(mInfoItem);
+ mRightMenuItems.add(mInfoItem);
mAppOpsItem = createAppOpsItem(mContext);
- mMenuItems.add(mAppOpsItem);
+ mLeftMenuItems.add(mAppOpsItem);
+ mRightMenuItems.add(mAppOpsItem);
- // Construct the menu views
- if (mMenuContainer != null) {
- mMenuContainer.removeAllViews();
- } else {
- mMenuContainer = new FrameLayout(mContext);
- }
- for (int i = 0; i < mMenuItems.size(); i++) {
- addMenuView(mMenuItems.get(i), mMenuContainer);
- }
+ populateMenuViews();
if (resetState) {
resetState(false /* notify */);
} else {
@@ -268,6 +266,18 @@
}
}
+ private void populateMenuViews() {
+ if (mMenuContainer != null) {
+ mMenuContainer.removeAllViews();
+ } else {
+ mMenuContainer = new FrameLayout(mContext);
+ }
+ List<MenuItem> menuItems = mOnLeft ? mLeftMenuItems : mRightMenuItems;
+ for (int i = 0; i < menuItems.size(); i++) {
+ addMenuView(menuItems.get(i), mMenuContainer);
+ }
+ }
+
private void resetState(boolean notify) {
setMenuAlpha(0f);
mIconsPlaced = false;
@@ -386,10 +396,16 @@
if (appName == null) {
return;
}
+ setAppName(appName, mLeftMenuItems);
+ setAppName(appName, mRightMenuItems);
+ }
+
+ private void setAppName(String appName,
+ ArrayList<MenuItem> menuItems) {
Resources res = mContext.getResources();
- final int count = mMenuItems.size();
+ final int count = menuItems.size();
for (int i = 0; i < count; i++) {
- MenuItem item = mMenuItems.get(i);
+ MenuItem item = menuItems.get(i);
String description = String.format(
res.getString(R.string.notification_menu_accessibility),
appName, item.getContentDescription());
@@ -402,7 +418,9 @@
@Override
public void onParentHeightUpdate() {
- if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
+ if (mParent == null
+ || (mLeftMenuItems.isEmpty() && mRightMenuItems.isEmpty())
+ || mMenuContainer == null) {
return;
}
int parentHeight = mParent.getActualHeight();
@@ -443,13 +461,14 @@
}
v.getLocationOnScreen(mIconLocation);
mParent.getLocationOnScreen(mParentLocation);
- final int centerX = (int) (mHorizSpaceForIcon / 2);
+ final int centerX = mHorizSpaceForIcon / 2;
final int centerY = v.getHeight() / 2;
final int x = mIconLocation[0] - mParentLocation[0] + centerX;
final int y = mIconLocation[1] - mParentLocation[1] + centerY;
final int index = mMenuContainer.indexOfChild(v);
if (mMenuListener != null) {
- mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ mMenuListener.onMenuClicked(mParent, x, y,
+ (mOnLeft ? mLeftMenuItems : mRightMenuItems).get(index));
}
}
@@ -469,6 +488,11 @@
// Do nothing
return;
}
+ boolean wasOnLeft = mOnLeft;
+ mOnLeft = showOnLeft;
+ if (wasOnLeft != showOnLeft) {
+ populateMenuViews();
+ }
final int count = mMenuContainer.getChildCount();
for (int i = 0; i < count; i++) {
final View v = mMenuContainer.getChildAt(i);
@@ -476,7 +500,6 @@
final float right = mParent.getWidth() - (mHorizSpaceForIcon * (i + 1));
v.setX(showOnLeft ? left : right);
}
- mOnLeft = showOnLeft;
mIconsPlaced = true;
}
@@ -603,6 +626,7 @@
private void addMenuView(MenuItem item, ViewGroup parent) {
View menuView = item.getMenuView();
if (menuView != null) {
+ menuView.setAlpha(mAlpha);
parent.addView(menuView);
menuView.setOnClickListener(this);
FrameLayout.LayoutParams lp = (LayoutParams) menuView.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 003f158d..c3bf16e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1107,7 +1107,9 @@
mIsClipped = clipped;
}
- if (mAmbientState.isDarkAtAll()) {
+ if (mPulsing) {
+ setClipBounds(null);
+ } else if (mAmbientState.isDarkAtAll()) {
setClipBounds(mBackgroundAnimationRect);
} else if (clipped) {
setClipBounds(mRequestedClipBounds);
@@ -5641,6 +5643,11 @@
public boolean canChildBeDismissed(View v) {
return NotificationStackScrollLayout.this.canChildBeDismissed(v);
}
+
+ @Override
+ public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
+ return (isLayoutRtl() ? !isRightOrDown : isRightOrDown) && canChildBeDismissed(v);
+ }
};
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index a0597dc..94b2cde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -20,13 +20,17 @@
import android.os.Handler;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
/**
* Controller which handles all the doze animations of the scrims.
*/
-public class DozeScrimController {
+public class DozeScrimController implements StateListener {
private static final String TAG = "DozeScrimController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -83,8 +87,11 @@
public DozeScrimController(DozeParameters dozeParameters) {
mDozeParameters = dozeParameters;
+ //Never expected to be destroyed
+ Dependency.get(StatusBarStateController.class).addListener(this);
}
+ @VisibleForTesting
public void setDozing(boolean dozing) {
if (mDozing == dozing) return;
mDozing = dozing;
@@ -181,4 +188,14 @@
public ScrimController.Callback getScrimCallback() {
return mScrimCallback;
}
+
+ @Override
+ public void onStateChanged(int newState) {
+ // don't care
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 4a7bc3a..d8280ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -187,6 +187,7 @@
if (mPulsing) {
clockYDark -= mPulsingPadding;
}
+ clockYDark = MathUtils.max(0, clockYDark);
float clockYRegular = getExpandedClockPosition();
float clockYBouncer = -mKeyguardStatusHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index 462201c..b3d0bf8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -35,7 +35,7 @@
}
/**
- * Executes an action that requres the screen to be unlocked.
+ * Executes an action that requires the screen to be unlocked.
*
* <p>Must be called after {@link #setDismissHandler}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 329a33d..4406b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -55,7 +55,8 @@
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
-import android.view.IRotationWatcher.Stub;
+import android.view.Display;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -74,12 +75,12 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
import com.android.systemui.Dependency;
-import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
@@ -419,8 +420,12 @@
}
checkNavBarModes();
mStatusBar.touchAutoHide();
- mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
- true /* nbModeChanged */, mNavigationBarMode);
+
+ // TODO(115978725): Support light bar controller on external nav bars.
+ if (mLightBarController != null) {
+ mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
+ true /* nbModeChanged */, mNavigationBarMode);
+ }
}
@Override
@@ -452,8 +457,11 @@
}
}
- mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
- mNavigationBarMode);
+ // TODO(115978725): Support light bar controller on external nav bars.
+ if (mLightBarController != null) {
+ mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
+ mNavigationBarMode);
+ }
}
@Override
@@ -840,9 +848,17 @@
};
public static View create(Context context, FragmentListener listener) {
+ final int displayId = context.getDisplay().getDisplayId();
+ final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ final int height = isDefaultDisplay
+ ? LayoutParams.MATCH_PARENT
+ : context.getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ LayoutParams.MATCH_PARENT, height,
+ // TODO(b/117478341): Resolve one status bar/ navigation bar assumption
+ isDefaultDisplay
+ ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+ : WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -851,9 +867,13 @@
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
- lp.setTitle("NavigationBar");
+ lp.setTitle("NavigationBar" + displayId);
lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
+ if (!isDefaultDisplay) {
+ lp.flags |= LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ lp.gravity = Gravity.BOTTOM;
+ }
View navigationBarView = LayoutInflater.from(context).inflate(
R.layout.navigation_bar_window, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index c08366a..6b12dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,22 +16,24 @@
package com.android.systemui.statusbar.phone;
-import android.annotation.NonNull;
import android.app.Notification;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
-import androidx.annotation.Nullable;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -48,7 +50,7 @@
* A class to handle notifications and their corresponding groups.
*/
public class NotificationGroupManager implements OnHeadsUpChangedListener,
- OnAmbientChangedListener {
+ OnAmbientChangedListener, StateListener {
private static final String TAG = "NotificationGroupManager";
private static final long ALERT_TRANSFER_TIMEOUT = 300;
@@ -62,10 +64,8 @@
private boolean mIsUpdatingUnchangedGroup;
private HashMap<String, NotificationData.Entry> mPendingNotifications;
- private final StateListener mStateListener = this::setStatusBarState;
-
public NotificationGroupManager() {
- Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).addListener(this);
}
public void setOnGroupChangeListener(OnGroupChangeListener listener) {
@@ -185,6 +185,7 @@
* specific alert state logic based off when the state changes.
* @param isDozing if the device is dozing.
*/
+ @VisibleForTesting
public void setDozing(boolean isDozing) {
if (mIsDozing != isDozing) {
for (NotificationGroup group : mGroupMap.values()) {
@@ -732,6 +733,16 @@
mPendingNotifications = pendingNotifications;
}
+ @Override
+ public void onStateChanged(int newState) {
+ setStatusBarState(newState);
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
+
public static class NotificationGroup {
public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
public NotificationData.Entry summary;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f50e9a2..8e90f98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -20,7 +20,6 @@
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -50,7 +49,7 @@
public void onTuningChanged(String key, String newValue) {
if (key.equals(LOW_PRIORITY)) {
mShowLowPriority = "1".equals(newValue)
- || !NotificationLockscreenUserManager.AUTO_DEMOTE_NOTIFICATIONS;
+ || !NotificationUtils.useNewInterruptionModel(mContext);
if (mNotificationScrollLayout != null) {
updateStatusBarIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 31facb7..f4c2e27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -582,7 +582,7 @@
int stackScrollerPadding;
if (mBarState != StatusBarState.KEYGUARD) {
stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight
- + mQsNotificationTopPadding;
+ + mQsNotificationTopPadding;
} else {
int totalHeight = getHeight();
int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
@@ -754,7 +754,7 @@
mQsExpandImmediate = true;
mNotificationStackScroller.setShouldShowShelfOnly(true);
}
- if (isFullyCollapsed()){
+ if (isFullyCollapsed()) {
expand(true /* animate */);
} else {
flingSettings(0 /* velocity */, FLING_EXPAND);
@@ -921,7 +921,7 @@
}
private boolean flingExpandsQs(float vel) {
- if (isFalseTouch()) {
+ if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) {
return false;
}
if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -1046,11 +1046,11 @@
final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN
&& (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)
- || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+ || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN
&& (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
- || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+ || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
}
@@ -1321,12 +1321,12 @@
private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener =
new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
- updateHeaderKeyguardAlpha();
- }
- };
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue();
+ updateHeaderKeyguardAlpha();
+ }
+ };
private void animateKeyguardStatusBarIn(long duration) {
mKeyguardStatusBar.setVisibility(View.VISIBLE);
@@ -1382,7 +1382,7 @@
if (keyguardFadingAway) {
mKeyguardStatusView.animate()
.setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
- .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()/2)
+ .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
.start();
}
} else if (mBarState == StatusBarState.SHADE_LOCKED
@@ -1425,8 +1425,8 @@
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled
- ? View.VISIBLE
- : View.INVISIBLE);
+ ? View.VISIBLE
+ : View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
}
@@ -1459,7 +1459,8 @@
setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
- if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
+ if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded
+ && mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
@@ -2130,8 +2131,7 @@
}
}, null, true /* dismissShade */, false /* afterKeyguardGone */,
true /* deferred */);
- }
- else {
+ } else {
mKeyguardBottomArea.launchLeftAffordance();
}
} else {
@@ -2588,7 +2588,7 @@
x = Math.min(rightMost, Math.max(leftMost, x));
setVerticalPanelTranslation(x -
(mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
- }
+ }
private void resetVerticalPanelPosition() {
setVerticalPanelTranslation(0f);
@@ -2716,8 +2716,8 @@
String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
? null : resolveInfo.activityInfo.packageName;
return packageToLaunch != null &&
- (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
- !mAffordanceHelper.isSwipingInProgress();
+ (keyguardIsShowing || !isForegroundApp(packageToLaunch))
+ && !mAffordanceHelper.isSwipingInProgress();
}
/**
@@ -2884,13 +2884,14 @@
}
public void setStatusAccessibilityImportance(int mode) {
- mKeyguardStatusView.setImportantForAccessibility(mode);
+ mKeyguardStatusView.setImportantForAccessibility(mode);
}
/**
* TODO: this should be removed.
* It's not correct to pass this view forward because other classes will end up adding
* children to it. Theme will be out of sync.
+ *
* @return bottom area view
*/
public KeyguardBottomAreaView getKeyguardBottomAreaView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f29b7ca..021b430 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -670,6 +670,10 @@
* @return whether a fling should expands the panel; contracts otherwise
*/
protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+ if (mFalsingManager.isUnlockingDisabled()) {
+ return true;
+ }
+
if (isFalseTouch(x, y)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2337857..966a346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -22,6 +22,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -70,6 +71,8 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
@@ -96,6 +99,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
@@ -558,8 +562,37 @@
}
};
+ protected DisplayManager mDisplayManager;
+
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
+
+ /** A displayId - nav bar mapping */
+ private SparseArray<NavigationBarFragment> mExternalNavigationBarMap = new SparseArray<>();
+
+ // TODO(b/115978725): Move it to DisplayNavigationBarController
+ private final DisplayListener mDisplayListener = new DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ final Display display = mDisplayManager.getDisplay(displayId);
+ addExternalNavigationBar(display);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ final NavigationBarFragment navBar = mExternalNavigationBarMap.get(displayId);
+ if (navBar != null) {
+ final View navigationView = navBar.getView().getRootView();
+ WindowManagerGlobal.getInstance().removeView(navigationView, true);
+ mExternalNavigationBarMap.remove(displayId);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ }
+ };
+
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private boolean mVibrateOnOpening;
private VibratorHelper mVibratorHelper;
@@ -586,7 +619,6 @@
mNotificationLogger = Dependency.get(NotificationLogger.class);
mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
mNotificationListener = Dependency.get(NotificationListener.class);
- mGroupManager = Dependency.get(NotificationGroupManager.class);
mNetworkController = Dependency.get(NetworkController.class);
mUserSwitcherController = Dependency.get(UserSwitcherController.class);
mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
@@ -618,6 +650,9 @@
mDisplay = mWindowManager.getDefaultDisplay();
updateDisplaySize();
+ // get display service to detect display status
+ mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+
Resources res = mContext.getResources();
mVibrateOnOpening = mContext.getResources().getBoolean(
R.bool.config_vibrateOnIconAnimation);
@@ -660,6 +695,7 @@
// If the system process isn't there we're doomed anyway.
}
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
createAndAddWindows();
// Make sure we always have the most current wallpaper info.
@@ -864,6 +900,7 @@
}
});
+ // TODO(115978725): Support light bar controller on external nav bars.
mLightBarController = Dependency.get(LightBarController.class);
if (mNavigationBar != null) {
mNavigationBar.setLightBarController(mLightBarController);
@@ -1047,6 +1084,33 @@
}
mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
});
+
+ // Add external navigation bars if more than one displays exist.
+ final Display[] displays = mDisplayManager.getDisplays();
+ for (Display display : displays) {
+ addExternalNavigationBar(display);
+ }
+ }
+
+ /**
+ * Add a phone navigation bar on an external display if the display supports system decorations.
+ *
+ * @param display the display to add navigation bar on
+ */
+ protected void addExternalNavigationBar(Display display) {
+ if (display == null || display.getDisplayId() == DEFAULT_DISPLAY
+ || !display.supportsSystemDecorations()) {
+ return;
+ }
+
+ final int displayId = display.getDisplayId();
+ final Context externalDisplayContext = mContext.createDisplayContext(display);
+ NavigationBarFragment.create(externalDisplayContext,
+ (tag, fragment) -> {
+ final NavigationBarFragment navBar = (NavigationBarFragment) fragment;
+ navBar.setCurrentSysuiVisibility(mSystemUiVisibility);
+ mExternalNavigationBarMap.append(displayId, navBar);
+ });
}
/**
@@ -1096,6 +1160,9 @@
@Override
public void onThemeChanged() {
// Recreate Indication controller because internal references changed
+ if (mKeyguardIndicationController != null) {
+ mKeyguardIndicationController.destroy();
+ }
mKeyguardIndicationController =
SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
@@ -1104,7 +1171,6 @@
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
- mKeyguardIndicationController.setDozing(mDozing);
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.onThemeChanged();
}
@@ -2065,6 +2131,7 @@
}
}
+ // TODO(115978725): Support auto hide on external nav bars.
void touchAutoHide() {
// update transient bar autohide
if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
@@ -2104,6 +2171,7 @@
: MODE_OPAQUE;
}
+ // TODO(115978725): Support animations on external nav bars.
void checkBarModes() {
if (mDemoMode) return;
if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
@@ -2123,6 +2191,7 @@
transitions.transitionTo(mode, anim);
}
+ // TODO(115978725): Support animations on external nav bars.
private void finishBarAnimations() {
if (mStatusBarView != null) {
mStatusBarView.getBarTransitions().finishAnimations();
@@ -2856,6 +2925,16 @@
mWindowManager.removeViewImmediate(mNavigationBarView);
mNavigationBarView = null;
}
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ if (mExternalNavigationBarMap.size() > 0) {
+ for (int i = 0; i < mExternalNavigationBarMap.size(); i++) {
+ final View navigationWindow = mExternalNavigationBarMap.valueAt(i)
+ .getView().getRootView();
+ WindowManagerGlobal.getInstance()
+ .removeView(navigationWindow, true /* immediate */);
+ }
+ mExternalNavigationBarMap.clear();
+ }
mContext.unregisterReceiver(mBroadcastReceiver);
mContext.unregisterReceiver(mDemoReceiver);
mAssistManager.destroy();
@@ -2924,6 +3003,7 @@
"transparent".equals(mode) ? MODE_TRANSPARENT :
"warning".equals(mode) ? MODE_WARNING :
-1;
+ // TODO(115978725): Support external nav bar transitions
if (barMode != -1) {
boolean animate = true;
if (mStatusBarView != null) {
@@ -3157,6 +3237,7 @@
mDraggedDownRow = null;
}
+ // TODO(115978725): Support animations on external nav bars.
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
if (mNavigationBar != null) {
@@ -3247,12 +3328,8 @@
boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
|| (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard);
- mDozeScrimController.setDozing(mDozing);
- mKeyguardIndicationController.setDozing(mDozing);
mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation,
mDozeServiceHost.wasPassivelyInterrupted());
- mNotificationLogger.setDozing(mDozing);
- mGroupManager.setDozing(mDozing);
updateQsExpansionEnabled();
Trace.endSection();
}
@@ -3442,13 +3519,6 @@
updateQsExpansionEnabled();
mKeyguardViewMediator.setAodShowing(mDozing);
- //TODO: make these folks listeners of StatusBarStateController.onDozingChanged
- mStatusBarWindowController.setDozing(mDozing);
- mStatusBarKeyguardViewManager.setDozing(mDozing);
- if (mAmbientIndicationContainer instanceof DozeReceiver) {
- ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
- }
-
mEntryManager.updateNotifications();
updateDozingState();
updateScrimController();
@@ -4425,6 +4495,7 @@
}
// End Extra BaseStatusBarMethods.
+ // TODO(115978725): Handle dimming for external nav bars
private final Runnable mAutoDim = () -> {
if (mNavigationBar != null) {
mNavigationBar.getBarTransitions().setAutoDim(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index df99a9c..484fe11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -59,7 +59,8 @@
* which is in turn, reported to this class by the current
* {@link com.android.keyguard.KeyguardViewBase}.
*/
-public class StatusBarKeyguardViewManager implements RemoteInputController.Callback {
+public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
+ StatusBarStateController.StateListener {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -150,6 +151,7 @@
mLockPatternUtils = lockPatternUtils;
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
+ Dependency.get(StatusBarStateController.class).addListener(this);
}
public void registerStatusBar(StatusBar statusBar,
@@ -334,7 +336,7 @@
updateStates();
}
- public void setDozing(boolean dozing) {
+ private void setDozing(boolean dozing) {
if (mDozing != dozing) {
mDozing = dozing;
if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
@@ -781,6 +783,16 @@
}
}
+ @Override
+ public void onStateChanged(int newState) {
+ // Nothing
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
+
private static class DismissWithActionRequest {
final OnDismissAction dismissAction;
final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 0d37b55..11de941 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -76,7 +76,6 @@
private final State mCurrentState = new State();
private OtherwisedCollapsedListener mListener;
- private final StateListener mStateListener = this::setStatusBarState;
private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
public StatusBarWindowController(Context context) {
@@ -564,6 +563,18 @@
}
}
+ private final StateListener mStateListener = new StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ setStatusBarState(newState);
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ setDozing(isDozing);
+ }
+ };
+
/**
* Custom listener to pipe data back to plugins about whether or not the status bar would be
* collapsed if not for the plugin.
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 3744105..9077b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -539,9 +539,9 @@
if (value != volumeItem.progress) {
volumeItem.listItem.setProgress(value);
volumeItem.progress = value;
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
- show(Events.SHOW_REASON_VOLUME_CHANGED);
- }
+ }
+ if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+ show(Events.SHOW_REASON_VOLUME_CHANGED);
}
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index aac37a2..b32bf99 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -39,7 +39,7 @@
telephony-common \
android.test.base \
android.car \
- android.car.user
+ android.car.userlib
LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index b5f67c06..098fa62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -15,22 +15,13 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockitoSession;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -38,49 +29,34 @@
import android.animation.Animator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Rect;
import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Looper;
-import android.os.PowerManager;
import android.service.notification.StatusBarNotification;
-import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.UiThreadTest;
import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.View;
-import android.view.MotionEvent;
import com.android.systemui.SwipeHelper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationMenuRow;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.stubbing.Answer;
-import java.util.ArrayList;
-
/**
* Tests for {@link NotificationSwipeHelper}.
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
+@UiThreadTest
public class NotificationSwipeHelperTest extends SysuiTestCase {
private NotificationSwipeHelper mSwipeHelper;
@@ -96,7 +72,6 @@
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Before
- @UiThreadTest
public void setUp() throws Exception {
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
new file mode 100644
index 0000000..f8ad298
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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.systemui.statusbar.phone;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
+
+ private static final int SCREEN_HEIGHT = 2000;
+ private static final int EMPTY_MARGIN = 0;
+ private static final int EMPTY_HEIGHT = 0;
+ private static final boolean SECURE_LOCKED = false;
+ private static final boolean PULSING_NO = false;
+ private static final float ZERO_DRAG = 0.f;
+ private static final float OPAQUE = 1.f;
+ private static final float TRANSPARENT = 0.f;
+
+ private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
+ private KeyguardClockPositionAlgorithm.Result mClockPosition;
+ private int mNotificationStackHeight;
+ private float mPanelExpansion;
+ private int mKeyguardStatusHeight;
+ private float mDark;
+
+ @Before
+ public void setUp() {
+ mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
+ mClockPosition = new KeyguardClockPositionAlgorithm.Result();
+ }
+
+ @Test
+ public void clockPositionMiddleOfScreenOnAOD() {
+ // GIVEN on AOD and both stack scroll and clock have 0 height
+ givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2).
+ assertThat(mClockPosition.clockY).isEqualTo(1000);
+ // AND the clock is opaque and positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionAdjustsForKeyguardStatusOnAOD() {
+ // GIVEN on AOD with a clock of height 100
+ givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = 100;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position adjusts for the clock height (SCREEN_HEIGHT / 2 - 100).
+ assertThat(mClockPosition.clockY).isEqualTo(900);
+ // AND the clock is opaque and positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionLargeClockOnAOD() {
+ // GIVEN on AOD with a full screen clock
+ givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = SCREEN_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position doesn't overflow the screen.
+ assertThat(mClockPosition.clockY).isEqualTo(0);
+ // AND the clock is opaque and positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionMiddleOfScreenOnLockScreen() {
+ // GIVEN on lock screen with stack scroll and clock of 0 height
+ givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2).
+ assertThat(mClockPosition.clockY).isEqualTo(1000);
+ // AND the clock is opaque and positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionWithStackScrollExpandOnLockScreen() {
+ // GIVEN on lock screen with stack scroll of height 500
+ givenLockScreen();
+ mNotificationStackHeight = 500;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position adjusts for stack scroll height ( (SCREEN_HEIGHT - 500 ) / 2).
+ assertThat(mClockPosition.clockY).isEqualTo(750);
+ // AND the clock is opaque and positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionWithPartialDragOnLockScreen() {
+ // GIVEN dragging up on lock screen
+ givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ mPanelExpansion = 0.5f;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position adjusts with drag gesture.
+ assertThat(mClockPosition.clockY).isLessThan(1000);
+ // AND the clock is positioned on the left and not fully opaque.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ assertThat(mClockPosition.clockAlpha).isLessThan(OPAQUE);
+ }
+
+ @Test
+ public void clockPositionWithFullDragOnLockScreen() {
+ // GIVEN the lock screen is dragged up
+ givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ mPanelExpansion = 0.f;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock is transparent.
+ assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT);
+ }
+
+ @Test
+ public void largeClockOnLockScreenIsTransparent() {
+ // GIVEN on lock screen with a full screen clock
+ givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
+ mKeyguardStatusHeight = SCREEN_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock is transparent
+ assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT);
+ }
+
+ private void givenAOD() {
+ mPanelExpansion = 1.f;
+ mDark = 1.f;
+ }
+
+ private void givenLockScreen() {
+ mPanelExpansion = 1.f;
+ mDark = 0.f;
+ }
+
+ private void positionClock() {
+ mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
+ mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED,
+ PULSING_NO, ZERO_DRAG);
+ mClockPositionAlgorithm.run(mClockPosition);
+ }
+}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index ddd0c2c..a947ea1 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2832,7 +2832,7 @@
// ACTION: Logs the end to end time taken by all provisioning tasks.
PROVISIONING_TOTAL_TASK_TIME_MS = 627;
- // OPEN: Settings > Privacy
+ // OPEN: Settings > Security
// CATEGORY: SETTINGS
// OS: O
ENTERPRISE_PRIVACY_SETTINGS = 628;
@@ -6579,6 +6579,11 @@
// OS: Q
BIOMETRIC_ENROLL_ACTIVITY = 1586;
+ // OPEN: Settings > Privacy
+ // CATEGORY: SETTINGS
+ // OS: Q
+ TOP_LEVEL_PRIVACY = 1587;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java
new file mode 100644
index 0000000..9cab1ed
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.service.intelligence.IntelligenceService;
+import android.service.intelligence.InteractionContext;
+import android.service.intelligence.InteractionSessionId;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.AbstractRemoteService;
+import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks {
+
+ private static final String TAG = "ContentCaptureSession";
+
+ private final Object mLock;
+ private final IBinder mActivityToken;
+
+ private final IntelligencePerUserService mService;
+ private final RemoteIntelligenceService mRemoteService;
+ private final InteractionContext mInterationContext;
+ private final InteractionSessionId mId;
+
+ ContentCaptureSession(@NonNull Context context, int userId, @NonNull Object lock,
+ @NonNull IBinder activityToken, @NonNull IntelligencePerUserService service,
+ @NonNull ComponentName serviceComponentName, @NonNull ComponentName appComponentName,
+ int taskId, int displayId, @NonNull InteractionSessionId sessionId, int flags,
+ boolean bindInstantServiceAllowed, boolean verbose) {
+ mLock = lock;
+ mActivityToken = activityToken;
+ mService = service;
+ mId = Preconditions.checkNotNull(sessionId);
+ mRemoteService = new RemoteIntelligenceService(context,
+ IntelligenceService.SERVICE_INTERFACE, serviceComponentName, userId, this,
+ bindInstantServiceAllowed, verbose);
+ mInterationContext = new InteractionContext(appComponentName, taskId, displayId, flags);
+ }
+
+ /**
+ * Notifies the {@link IntelligenceService} that the service started.
+ */
+ @GuardedBy("mLock")
+ public void notifySessionStartedLocked() {
+ mRemoteService.onSessionLifecycleRequest(mInterationContext, mId);
+ }
+
+ /**
+ * Notifies the {@link IntelligenceService} of a batch of events.
+ */
+ public void sendEventsLocked(List<ContentCaptureEvent> events) {
+ mRemoteService.onContentCaptureEventsRequest(mId, events);
+ }
+
+ /**
+ * Cleans up the session and remove itself from the service.
+ *
+ * @param notifyRemoteService whether it should trigger a {@link
+ * IntelligenceService#onDestroyInteractionSession(InteractionSessionId)}
+ * request.
+ */
+ @GuardedBy("mLock")
+ public void removeSelfLocked(boolean notifyRemoteService) {
+ try {
+ if (notifyRemoteService) {
+ mRemoteService.onSessionLifecycleRequest(/* context= */ null, mId);
+ }
+ } finally {
+ mService.removeSessionLocked(mId);
+ }
+ }
+
+ @Override // from RemoteScreenObservationServiceCallbacks
+ public void onServiceDied(AbstractRemoteService service) {
+ // TODO(b/111276913): implement (remove session from PerUserSession?)
+ if (mService.isDebug()) {
+ Slog.d(TAG, "onServiceDied() for " + mId);
+ }
+ synchronized (mLock) {
+ removeSelfLocked(/* notifyRemoteService= */ false);
+ }
+ }
+
+ @Override // from RemoteScreenObservationServiceCallbacks
+ public void onFailureOrTimeout(boolean timedOut) {
+ // TODO(b/111276913): log metrics on whether timed out or not
+ if (mService.isDebug()) {
+ Slog.d(TAG, "onFailureOrTimeout(" + mId + "): timed out=" + timedOut);
+ }
+ synchronized (mLock) {
+ removeSelfLocked(/* notifyRemoteService= */ false);
+ }
+ }
+
+ @GuardedBy("mLock")
+ public void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix); pw.print("id: "); mId.dump(pw); pw.println();
+ pw.print(prefix); pw.print("context: "); mInterationContext.dump(pw); pw.println();
+ pw.print(prefix); pw.print("activity token: "); pw.println(mActivityToken);
+ }
+
+ @Override
+ public String toString() {
+ return "ContentCaptureSession[id=" + mId.getValue() + ", act=" + mActivityToken + "]";
+ }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java
new file mode 100644
index 0000000..43d4a44
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import static android.content.Context.INTELLIGENCE_MANAGER_SERVICE;
+
+import android.annotation.NonNull;
+import android.app.ActivityManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.UserManager;
+import android.service.intelligence.InteractionSessionId;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IIntelligenceManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.AbstractMasterSystemService;
+import com.android.server.LocalServices;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * A service used to observe the contents of the screen.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * contextual data in other areas of the system such as Autofill.
+ */
+public final class IntelligenceManagerService
+ extends AbstractMasterSystemService<IntelligencePerUserService> {
+
+ private static final String TAG = "IntelligenceManagerService";
+
+ @GuardedBy("mLock")
+ private ActivityManagerInternal mAm;
+
+ public IntelligenceManagerService(Context context) {
+ super(context, UserManager.DISALLOW_INTELLIGENCE_CAPTURE);
+ }
+
+ @Override // from MasterSystemService
+ protected String getServiceSettingsProperty() {
+ // TODO(b/111276913): STOPSHIP temporary settings, until it's set by resourcs + cmd
+ return "intel_service";
+ }
+
+ @Override // from MasterSystemService
+ protected IntelligencePerUserService newServiceLocked(int resolvedUserId,
+ boolean disabled) {
+ return new IntelligencePerUserService(this, mLock, resolvedUserId);
+ }
+
+ @Override // from SystemService
+ public void onStart() {
+ publishBinderService(INTELLIGENCE_MANAGER_SERVICE,
+ new IntelligenceManagerServiceStub());
+ }
+
+ private ActivityManagerInternal getAmInternal() {
+ synchronized (mLock) {
+ if (mAm == null) {
+ mAm = LocalServices.getService(ActivityManagerInternal.class);
+ }
+ }
+ return mAm;
+ }
+
+ final class IntelligenceManagerServiceStub extends IIntelligenceManager.Stub {
+
+ @Override
+ public void startSession(int userId, @NonNull IBinder activityToken,
+ @NonNull ComponentName componentName, @NonNull InteractionSessionId sessionId,
+ int flags, @NonNull IResultReceiver result) {
+ Preconditions.checkNotNull(activityToken);
+ Preconditions.checkNotNull(componentName);
+ Preconditions.checkNotNull(sessionId);
+
+ // TODO(b/111276913): refactor getTaskIdForActivity() to also return ComponentName,
+ // so we don't pass it on startSession (same for Autofill)
+ final int taskId = getAmInternal().getTaskIdForActivity(activityToken, false);
+
+ // TODO(b/111276913): get from AM as well
+ final int displayId = 0;
+
+ synchronized (mLock) {
+ final IntelligencePerUserService service = getServiceForUserLocked(userId);
+ service.startSessionLocked(activityToken, componentName, taskId, displayId,
+ sessionId, flags, result);
+ }
+ }
+
+ @Override
+ public void sendEvents(int userId, @NonNull InteractionSessionId sessionId,
+ @NonNull List<ContentCaptureEvent> events) {
+ Preconditions.checkNotNull(sessionId);
+ Preconditions.checkNotNull(events);
+
+ synchronized (mLock) {
+ final IntelligencePerUserService service = getServiceForUserLocked(userId);
+ service.sendEventsLocked(sessionId, events);
+ }
+ }
+
+ @Override
+ public void finishSession(int userId, @NonNull InteractionSessionId sessionId) {
+ Preconditions.checkNotNull(sessionId);
+
+ synchronized (mLock) {
+ final IntelligencePerUserService service = getServiceForUserLocked(userId);
+ service.finishSessionLocked(sessionId);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+
+ synchronized (mLock) {
+ dumpLocked("", pw);
+ }
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java
new file mode 100644
index 0000000..584b872
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.intelligence.InteractionSessionId;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+import android.view.intelligence.IntelligenceManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+import com.android.server.AbstractPerUserSystemService;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Per-user instance of {@link IntelligenceManagerService}.
+ */
+final class IntelligencePerUserService
+ extends AbstractPerUserSystemService<IntelligencePerUserService> {
+
+ private static final String TAG = "IntelligencePerUserService";
+
+ @GuardedBy("mLock")
+ private final ArrayMap<InteractionSessionId, ContentCaptureSession> mSessions =
+ new ArrayMap<>();
+
+ // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
+
+ protected IntelligencePerUserService(
+ IntelligenceManagerService master, Object lock, int userId) {
+ super(master, lock, userId);
+ }
+
+ @Override // from PerUserSystemService
+ protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent)
+ throws NameNotFoundException {
+
+ ServiceInfo si;
+ try {
+ // TODO(b/111276913): must check that either the service is from a system component,
+ // or it matches a service set by shell cmd (so it can be used on CTS tests and when
+ // OEMs are implementing the real service
+ si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+ PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e);
+ return null;
+ }
+ if (!Manifest.permission.BIND_INTELLIGENCE_SERVICE.equals(si.permission)) {
+ Slog.w(TAG, "IntelligenceService from '" + si.packageName
+ + "' does not require permission "
+ + Manifest.permission.BIND_INTELLIGENCE_SERVICE);
+ throw new SecurityException("Service does not require permission "
+ + Manifest.permission.BIND_INTELLIGENCE_SERVICE);
+ }
+ return si;
+ }
+
+ // TODO(b/111276913): log metrics
+ @GuardedBy("mLock")
+ public void startSessionLocked(@NonNull IBinder activityToken,
+ @NonNull ComponentName componentName, int taskId, int displayId,
+ @NonNull InteractionSessionId sessionId, int flags,
+ @NonNull IResultReceiver resultReceiver) {
+ final ComponentName serviceComponentName = getServiceComponentName();
+ if (serviceComponentName == null) {
+ // TODO(b/111276913): this happens when the system service is starting, we should
+ // probably handle it in a more elegant way (like waiting for boot_complete or
+ // something like that
+ Slog.w(TAG, "startSession(" + activityToken + "): hold your horses");
+ return;
+ }
+
+ ContentCaptureSession session = mSessions.get(sessionId);
+ if (session != null) {
+ if (mMaster.debug) {
+ Slog.d(TAG, "startSession(): reusing session " + sessionId + " for "
+ + componentName);
+ }
+ // TODO(b/111276913): check if local ids match and decide what to do if they don't
+ // TODO(b/111276913): should we call session.notifySessionStartedLocked() again??
+ // if not, move notifySessionStartedLocked() into session constructor
+ sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE);
+ return;
+ }
+
+ // TODO(b/117779333): get from mMaster once it's moved to superclass
+ final boolean bindInstantServiceAllowed = false;
+
+ session = new ContentCaptureSession(getContext(), mUserId, mLock, activityToken,
+ this, serviceComponentName, componentName, taskId, displayId, sessionId, flags,
+ bindInstantServiceAllowed, mMaster.verbose);
+ if (mMaster.verbose) {
+ Slog.v(TAG, "startSession(): new session for " + componentName + " and id "
+ + sessionId);
+ }
+ mSessions.put(sessionId, session);
+ session.notifySessionStartedLocked();
+ sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE);
+ }
+
+ // TODO(b/111276913): log metrics
+ @GuardedBy("mLock")
+ public void finishSessionLocked(@NonNull InteractionSessionId sessionId) {
+ final ContentCaptureSession session = mSessions.get(sessionId);
+ if (session == null) {
+ Slog.w(TAG, "finishSession(): no session with id" + sessionId);
+ return;
+ }
+ if (mMaster.verbose) {
+ Slog.v(TAG, "finishSession(): " + session);
+ }
+ session.removeSelfLocked(true);
+ }
+
+ @GuardedBy("mLock")
+ public void sendEventsLocked(@NonNull InteractionSessionId sessionId,
+ @NonNull List<ContentCaptureEvent> events) {
+ final ContentCaptureSession session = mSessions.get(sessionId);
+ if (session == null) {
+ Slog.w(TAG, "sendEvents(): no session for " + sessionId);
+ return;
+ }
+ if (mMaster.verbose) {
+ Slog.v(TAG, "sendEvents(): id=" + sessionId + "; events =" + events.size());
+ }
+ session.sendEventsLocked(events);
+ }
+
+ @GuardedBy("mLock")
+ public void removeSessionLocked(@NonNull InteractionSessionId sessionId) {
+ mSessions.remove(sessionId);
+ }
+
+ @Override
+ protected void dumpLocked(String prefix, PrintWriter pw) {
+ super.dumpLocked(prefix, pw);
+ if (mSessions.isEmpty()) {
+ pw.print(prefix); pw.println("no sessions");
+ } else {
+ final int size = mSessions.size();
+ pw.print(prefix); pw.print("number sessions: "); pw.println(size);
+ final String prefix2 = prefix + " ";
+ for (int i = 0; i < size; i++) {
+ pw.print(prefix); pw.print("session@"); pw.println(i);
+ final ContentCaptureSession session = mSessions.valueAt(i);
+ session.dumpLocked(prefix2, pw);
+ }
+ }
+ }
+
+ private static void sendToClient(@NonNull IResultReceiver resultReceiver, int value) {
+ try {
+ resultReceiver.send(value, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error async reporting result to client: " + e);
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java
new file mode 100644
index 0000000..9d241fb
--- /dev/null
+++ b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2018 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.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.service.intelligence.IIntelligenceService;
+import android.service.intelligence.InteractionContext;
+import android.service.intelligence.InteractionSessionId;
+import android.text.format.DateUtils;
+import android.util.Slog;
+import android.view.intelligence.ContentCaptureEvent;
+
+import com.android.server.AbstractRemoteService;
+
+import java.util.List;
+
+final class RemoteIntelligenceService extends AbstractRemoteService {
+
+ private static final String TAG = "RemoteIntelligenceService";
+
+ private static final long TIMEOUT_IDLE_BIND_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
+
+ private final RemoteIntelligenceServiceCallbacks mCallbacks;
+ private IIntelligenceService mService;
+
+ RemoteIntelligenceService(Context context, String serviceInterface,
+ ComponentName componentName, int userId,
+ RemoteIntelligenceServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
+ boolean verbose) {
+ super(context, serviceInterface, componentName, userId, callbacks,
+ bindInstantServiceAllowed, verbose);
+ mCallbacks = callbacks;
+ }
+
+ @Override // from RemoteService
+ protected IInterface getServiceInterface(@NonNull IBinder service) {
+ mService = IIntelligenceService.Stub.asInterface(service);
+ return mService;
+ }
+
+ // TODO(b/111276913): modify super class to allow permanent binding when value is 0 or negative
+ @Override // from RemoteService
+ protected long getTimeoutIdleBindMillis() {
+ // TODO(b/111276913): read from Settings so it can be changed in the field
+ return TIMEOUT_IDLE_BIND_MILLIS;
+ }
+
+ @Override // from RemoteService
+ protected long getRemoteRequestMillis() {
+ // TODO(b/111276913): read from Settings so it can be changed in the field
+ return TIMEOUT_REMOTE_REQUEST_MILLIS;
+ }
+
+ /**
+ * Called by {@link ContentCaptureSession} to generate a call to the
+ * {@link RemoteIntelligenceService} to indicate the session was created (when {@code context}
+ * is not {@code null} or destroyed (when {@code context} is {@code null}).
+ */
+ public void onSessionLifecycleRequest(@Nullable InteractionContext context,
+ @NonNull InteractionSessionId sessionId) {
+ cancelScheduledUnbind();
+ scheduleRequest(new PendingSessionLifecycleRequest(this, context, sessionId));
+ }
+
+ /**
+ * Called by {@link ContentCaptureSession} to send a batch of events to the service.
+ */
+ public void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId,
+ @NonNull List<ContentCaptureEvent> events) {
+ cancelScheduledUnbind();
+ scheduleRequest(new PendingOnContentCaptureEventsRequest(this, sessionId, events));
+ }
+
+
+ private abstract static class MyPendingRequest
+ extends PendingRequest<RemoteIntelligenceService> {
+ protected final InteractionSessionId mSessionId;
+
+ private MyPendingRequest(@NonNull RemoteIntelligenceService service,
+ @NonNull InteractionSessionId sessionId) {
+ super(service);
+ mSessionId = sessionId;
+ }
+
+ @Override // from PendingRequest
+ protected final void onTimeout(RemoteIntelligenceService remoteService) {
+ Slog.w(TAG, "timed out handling " + getClass().getSimpleName() + " for "
+ + mSessionId);
+ remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ true);
+ }
+
+ @Override // from PendingRequest
+ public final void run() {
+ final RemoteIntelligenceService remoteService = getService();
+ if (remoteService != null) {
+ try {
+ myRun(remoteService);
+ // We don't expect the service to call us back, so we finish right away.
+ finish();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for "
+ + mSessionId + ": " + e);
+ remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ false);
+ }
+ }
+ }
+
+ protected abstract void myRun(@NonNull RemoteIntelligenceService service)
+ throws RemoteException;
+
+ }
+
+ private static final class PendingSessionLifecycleRequest extends MyPendingRequest {
+
+ private final InteractionContext mContext;
+
+ protected PendingSessionLifecycleRequest(@NonNull RemoteIntelligenceService service,
+ @Nullable InteractionContext context, @NonNull InteractionSessionId sessionId) {
+ super(service, sessionId);
+ mContext = context;
+ }
+
+ @Override // from MyPendingRequest
+ public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException {
+ remoteService.mService.onSessionLifecycle(mContext, mSessionId);
+ }
+ }
+
+ private static final class PendingOnContentCaptureEventsRequest extends MyPendingRequest {
+
+ private final List<ContentCaptureEvent> mEvents;
+
+ protected PendingOnContentCaptureEventsRequest(@NonNull RemoteIntelligenceService service,
+ @NonNull InteractionSessionId sessionId,
+ @NonNull List<ContentCaptureEvent> events) {
+ super(service, sessionId);
+ mEvents = events;
+ }
+
+ @Override // from MyPendingRequest
+ public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException {
+ remoteService.mService.onContentCaptureEvents(mSessionId, mEvents);
+ }
+ }
+
+ public interface RemoteIntelligenceServiceCallbacks extends VultureCallback {
+ // To keep it simple, we use the same callback for all failures / timeouts.
+ void onFailureOrTimeout(boolean timedOut);
+ }
+}
diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java
index 1d3a34c..181d7fd 100644
--- a/services/core/java/com/android/server/AbstractRemoteService.java
+++ b/services/core/java/com/android/server/AbstractRemoteService.java
@@ -366,11 +366,12 @@
mCompleted = true;
}
- Slog.w(mTag, "timed out");
final S remoteService = mWeakService.get();
if (remoteService != null) {
- Slog.w(mTag, " timed out after " + service.getRemoteRequestMillis() + " ms");
+ Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
onTimeout(remoteService);
+ } else {
+ Slog.w(mTag, "timed out (no service)");
}
};
mServiceHandler.postAtTime(mTimeoutTrigger,
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index cd98263..32667b8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1210,13 +1210,29 @@
@Override
public void setMode(int code, int uid, String packageName, int mode) {
+ setMode(code, uid, packageName, mode, true, false);
+ }
+
+ /**
+ * Sets the mode for a certain op and uid.
+ *
+ * @param code The op code to set
+ * @param uid The UID for which to set
+ * @param packageName The package for which to set
+ * @param mode The new mode to set
+ * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
+ * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
+ * false})
+ */
+ private void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean verifyUid, boolean isPrivileged) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, true);
+ Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -1575,7 +1591,7 @@
&& uidState.opModes.indexOfKey(code) >= 0) {
return uidState.opModes.get(code);
}
- Op op = getOpLocked(code, uid, resolvedPackageName, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, false, true, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -1918,7 +1934,7 @@
}
ClientState client = (ClientState) token;
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
if (op == null) {
return;
}
@@ -2172,6 +2188,43 @@
return ops;
}
+ /**
+ * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
+ *
+ * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
+ *
+ * @param uid The uid the of the package
+ * @param packageName The package name for which to get the state for
+ * @param edit Iff {@code true} create the {@link Ops} object if not yet created
+ * @param isPrivileged Whether the package is privileged or not
+ *
+ * @return The {@link Ops state} of all ops for the package
+ */
+ private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
+ boolean edit, boolean isPrivileged) {
+ UidState uidState = getUidStateLocked(uid, edit);
+ if (uidState == null) {
+ return null;
+ }
+
+ if (uidState.pkgOps == null) {
+ if (!edit) {
+ return null;
+ }
+ uidState.pkgOps = new ArrayMap<>();
+ }
+
+ Ops ops = uidState.pkgOps.get(packageName);
+ if (ops == null) {
+ if (!edit) {
+ return null;
+ }
+ ops = new Ops(packageName, uidState, isPrivileged);
+ uidState.pkgOps.put(packageName, ops);
+ }
+ return ops;
+ }
+
private void scheduleWriteLocked() {
if (!mWriteScheduled) {
mWriteScheduled = true;
@@ -2188,9 +2241,29 @@
}
}
- private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
- Ops ops = getOpsRawLocked(uid, packageName, edit,
- false /* uidMismatchExpected */);
+ /**
+ * Get the state of an op for a uid.
+ *
+ * @param code The code of the op
+ * @param uid The uid the of the package
+ * @param packageName The package name for which to get the state for
+ * @param edit Iff {@code true} create the {@link Op} object if not yet created
+ * @param verifyUid Iff {@code true} check that the package belongs to the uid
+ * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
+ * == false})
+ *
+ * @return The {@link Op state} of the op
+ */
+ private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
+ boolean verifyUid, boolean isPrivileged) {
+ Ops ops;
+
+ if (verifyUid) {
+ ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
+ } else {
+ ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+ }
+
if (ops == null) {
return null;
}
@@ -3948,5 +4021,11 @@
mProfileOwners = owners;
}
}
+
+ @Override
+ public void setMode(int code, int uid, @NonNull String packageName, int mode,
+ boolean isPrivileged) {
+ AppOpsService.this.setMode(code, uid, packageName, mode, false, isPrivileged);
+ }
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 93bdcbb..90ad09e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -541,7 +541,7 @@
}
}
- private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
+ private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
PackageManager pm = mContext.getPackageManager();
String systemPackageName = mContext.getPackageName();
ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
@@ -646,16 +646,14 @@
that matches the signature of at least one package on this list.
*/
Resources resources = mContext.getResources();
- ArrayList<String> providerPackageNames = new ArrayList<>();
String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames);
if (D) {
Log.d(TAG, "certificates for location providers pulled from: " +
Arrays.toString(pkgs));
}
- if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
- ensureFallbackFusedProviderPresentLocked(providerPackageNames);
+ ensureFallbackFusedProviderPresentLocked(pkgs);
// bind to network provider
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
@@ -664,8 +662,7 @@
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames,
- mLocationHandler);
+ com.android.internal.R.array.config_locationProviderPackageNames);
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mProxyProviders.add(networkProvider);
@@ -681,8 +678,7 @@
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames,
- mLocationHandler);
+ com.android.internal.R.array.config_locationProviderPackageNames);
if (fusedLocationProvider != null) {
addProviderLocked(fusedLocationProvider);
mProxyProviders.add(fusedLocationProvider);
@@ -697,8 +693,7 @@
mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
com.android.internal.R.bool.config_enableGeocoderOverlay,
com.android.internal.R.string.config_geocoderProviderPackageName,
- com.android.internal.R.array.config_locationProviderPackageNames,
- mLocationHandler);
+ com.android.internal.R.array.config_locationProviderPackageNames);
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
@@ -708,7 +703,6 @@
mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
com.android.internal.R.string.config_geofenceProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
- mLocationHandler,
mGpsGeofenceProxy,
null);
if (provider == null) {
@@ -725,7 +719,6 @@
}
ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
mContext,
- mLocationHandler,
activityRecognitionHardwareIsSupported,
activityRecognitionHardware,
com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 42c836e..574f54a 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,8 +16,10 @@
package com.android.server;
-import android.annotation.NonNull;
+import android.annotation.MainThread;
import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -30,17 +32,21 @@
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -50,268 +56,54 @@
* Handles run-time package changes.
*/
public class ServiceWatcher implements ServiceConnection {
+
+ private static final String TAG = "ServiceWatcher";
private static final boolean D = false;
+
public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
- private final String mTag;
- private final Context mContext;
- private final PackageManager mPm;
- private final List<HashSet<Signature>> mSignatureSets;
- private final String mAction;
-
/**
- * If mServicePackageName is not null, only this package will be searched for the service that
- * implements mAction. When null, all packages in the system that matches one of the signature
- * in mSignatureSets are searched.
+ * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
*/
- private final String mServicePackageName;
- private final Runnable mNewServiceWork;
- private final Handler mHandler;
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private int mCurrentUserId = UserHandle.USER_SYSTEM;
-
- @GuardedBy("mLock")
- private IBinder mBoundService;
- @GuardedBy("mLock")
- private ComponentName mBoundComponent;
- @GuardedBy("mLock")
- private String mBoundPackageName;
- @GuardedBy("mLock")
- private int mBoundVersion = Integer.MIN_VALUE;
- @GuardedBy("mLock")
- private int mBoundUserId = UserHandle.USER_NULL;
+ public interface BinderRunner {
+ /**
+ * Runs on the retrieved binder.
+ *
+ * @param binder the binder retrieved from the {@link ServiceWatcher}.
+ */
+ void run(IBinder binder);
+ }
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
- List<String> initialPackageNames) {
+ String... packageNames) {
PackageManager pm = context.getPackageManager();
- ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
- for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
- String pkg = initialPackageNames.get(i);
+
+ ArrayList<HashSet<Signature>> signatureSets = new ArrayList<>(packageNames.length);
+ for (String packageName : packageNames) {
try {
- HashSet<Signature> set = new HashSet<Signature>();
- Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.GET_SIGNATURES).signatures;
- set.addAll(Arrays.asList(sigs));
- sigSets.add(set);
+ Signature[] signatures = pm.getPackageInfo(packageName,
+ PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.GET_SIGNATURES).signatures;
+
+ HashSet<Signature> set = new HashSet<>();
+ Collections.addAll(set, signatures);
+ signatureSets.add(set);
} catch (NameNotFoundException e) {
- Log.w("ServiceWatcher", pkg + " not found");
+ Log.w(TAG, packageName + " not found");
}
}
- return sigSets;
+ return signatureSets;
}
- public ServiceWatcher(Context context, String logTag, String action,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Runnable newServiceWork,
- Handler handler) {
- mContext = context;
- mTag = logTag;
- mAction = action;
- mPm = mContext.getPackageManager();
- mNewServiceWork = newServiceWork;
- mHandler = handler;
- Resources resources = context.getResources();
-
- // Whether to enable service overlay.
- boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
- ArrayList<String> initialPackageNames = new ArrayList<String>();
- if (enableOverlay) {
- // A list of package names used to create the signatures.
- String[] pkgs = resources.getStringArray(initialPackageNamesResId);
- if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
- mServicePackageName = null;
- if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
- } else {
- // The default package name that is searched for service implementation when overlay is
- // disabled.
- String servicePackageName = resources.getString(defaultServicePackageNameResId);
- if (servicePackageName != null) initialPackageNames.add(servicePackageName);
- mServicePackageName = servicePackageName;
- if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
- }
- mSignatureSets = getSignatureSets(context, initialPackageNames);
- }
-
- /**
- * Start this watcher, including binding to the current best match and
- * re-binding to any better matches down the road.
- * <p>
- * Note that if there are no matching encryption-aware services, we may not
- * bind to a real service until after the current user is unlocked.
- *
- * @returns {@code true} if a potential service implementation was found.
- */
- public boolean start() {
- if (isServiceMissing()) return false;
-
- synchronized (mLock) {
- bindBestPackageLocked(mServicePackageName, false);
- }
-
- // listen for user change
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL);
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- switchUser(userId);
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- unlockUser(userId);
- }
- }
- }, UserHandle.ALL, intentFilter, null, mHandler);
-
- // listen for relevant package changes if service overlay is enabled.
- if (mServicePackageName == null) {
- mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
- }
-
- return true;
- }
-
- /**
- * Check if any instance of this service is present on the device,
- * regardless of it being encryption-aware or not.
- */
- private boolean isServiceMissing() {
- final Intent intent = new Intent(mAction);
- final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty();
- }
-
- /**
- * Searches and binds to the best package, or do nothing if the best package
- * is already bound, unless force rebinding is requested.
- *
- * @param justCheckThisPackage Only consider this package, or consider all
- * packages if it is {@code null}.
- * @param forceRebind Force a rebinding to the best package if it's already
- * bound.
- * @returns {@code true} if a valid package was found to bind to.
- */
- @GuardedBy("mLock")
- private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
- Intent intent = new Intent(mAction);
- if (justCheckThisPackage != null) {
- intent.setPackage(justCheckThisPackage);
- }
- final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
- PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- mCurrentUserId);
- int bestVersion = Integer.MIN_VALUE;
- ComponentName bestComponent = null;
- boolean bestIsMultiuser = false;
- if (rInfos != null) {
- for (ResolveInfo rInfo : rInfos) {
- final ComponentName component = rInfo.serviceInfo.getComponentName();
- final String packageName = component.getPackageName();
-
- // check signature
- try {
- PackageInfo pInfo;
- pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
- if (!isSignatureMatch(pInfo.signatures)) {
- Log.w(mTag, packageName + " resolves service " + mAction
- + ", but has wrong signature, ignoring");
- continue;
- }
- } catch (NameNotFoundException e) {
- Log.wtf(mTag, e);
- continue;
- }
-
- // check metadata
- int version = Integer.MIN_VALUE;
- boolean isMultiuser = false;
- if (rInfo.serviceInfo.metaData != null) {
- version = rInfo.serviceInfo.metaData.getInt(
- EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
- isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
- }
-
- if (version > bestVersion) {
- bestVersion = version;
- bestComponent = component;
- bestIsMultiuser = isMultiuser;
- }
- }
-
- if (D) {
- Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
- (justCheckThisPackage == null ? ""
- : "(" + justCheckThisPackage + ") "), rInfos.size(),
- (bestComponent == null ? "no new best component"
- : "new best component: " + bestComponent)));
- }
- } else {
- if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
- }
-
- if (bestComponent == null) {
- Slog.w(mTag, "Odd, no component found for service " + mAction);
- unbindLocked();
- return false;
- }
-
- final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
- final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
- && bestVersion == mBoundVersion && userId == mBoundUserId;
- if (forceRebind || !alreadyBound) {
- unbindLocked();
- bindToPackageLocked(bestComponent, bestVersion, userId);
- }
- return true;
- }
-
- @GuardedBy("mLock")
- private void unbindLocked() {
- ComponentName component;
- component = mBoundComponent;
- mBoundComponent = null;
- mBoundPackageName = null;
- mBoundVersion = Integer.MIN_VALUE;
- mBoundUserId = UserHandle.USER_NULL;
- if (component != null) {
- if (D) Log.d(mTag, "unbinding " + component);
- mBoundService = null;
- mContext.unbindService(this);
- }
- }
-
- @GuardedBy("mLock")
- private void bindToPackageLocked(ComponentName component, int version, int userId) {
- Intent intent = new Intent(mAction);
- intent.setComponent(component);
- mBoundComponent = component;
- mBoundPackageName = component.getPackageName();
- mBoundVersion = version;
- mBoundUserId = userId;
- if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
- mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
- new UserHandle(userId));
- }
-
+ /** Checks if signatures match. */
public static boolean isSignatureMatch(Signature[] signatures,
List<HashSet<Signature>> sigSets) {
if (signatures == null) return false;
// build hashset of input to test against
- HashSet<Signature> inputSet = new HashSet<Signature>();
- for (Signature s : signatures) {
- inputSet.add(s);
- }
+ HashSet<Signature> inputSet = new HashSet<>();
+ Collections.addAll(inputSet, signatures);
// test input against each of the signature sets
for (HashSet<Signature> referenceSet : sigSets) {
@@ -322,124 +114,318 @@
return false;
}
- private boolean isSignatureMatch(Signature[] signatures) {
- return isSignatureMatch(signatures, mSignatureSets);
+ private final Context mContext;
+ private final String mTag;
+ private final String mAction;
+ private final String mServicePackageName;
+ private final List<HashSet<Signature>> mSignatureSets;
+
+ private final Handler mHandler;
+
+ // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after
+ // the new service initialization work has completed
+ private final Object mBindLock = new Object();
+
+ // read/write from handler thread
+ private int mCurrentUserId;
+
+ // read from any thread, write from handler thread
+ private volatile ComponentName mBestComponent;
+ private volatile int mBestVersion;
+ private volatile int mBestUserId;
+ private volatile IBinder mBestService;
+
+ public ServiceWatcher(Context context, String logTag, String action,
+ int overlaySwitchResId, int defaultServicePackageNameResId,
+ int initialPackageNamesResId, Handler handler) {
+ Resources resources = context.getResources();
+
+ mContext = context;
+ mTag = logTag;
+ mAction = action;
+
+ boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
+ if (enableOverlay) {
+ String[] pkgs = resources.getStringArray(initialPackageNamesResId);
+ mServicePackageName = null;
+ mSignatureSets = getSignatureSets(context, pkgs);
+ if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
+ } else {
+ mServicePackageName = resources.getString(defaultServicePackageNameResId);
+ mSignatureSets = getSignatureSets(context, mServicePackageName);
+ if (D) Log.d(mTag, "Overlay disabled, default package=" + mServicePackageName);
+ }
+
+ mHandler = handler;
+
+ mBestComponent = null;
+ mBestVersion = Integer.MIN_VALUE;
+ mBestUserId = UserHandle.USER_NULL;
+
+ mBestService = null;
}
- private final PackageMonitor mPackageMonitor = new PackageMonitor() {
- /**
- * Called when package has been reinstalled
- */
- @Override
- public void onPackageUpdateFinished(String packageName, int uid) {
- synchronized (mLock) {
- final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
- bindBestPackageLocked(null, forceRebind);
- }
- }
+ // called on handler thread
+ @GuardedBy("mBindLock")
+ protected void onBind() {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- synchronized (mLock) {
- final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
- bindBestPackageLocked(null, forceRebind);
- }
- }
+ }
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- synchronized (mLock) {
- final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
- bindBestPackageLocked(null, forceRebind);
- }
- }
+ // called on handler thread
+ @GuardedBy("mBindLock")
+ protected void onUnbind() {
- @Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- synchronized (mLock) {
- final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
- bindBestPackageLocked(null, forceRebind);
- }
- return super.onPackageChanged(packageName, uid, components);
- }
- };
+ }
- @Override
- public void onServiceConnected(ComponentName component, IBinder binder) {
- synchronized (mLock) {
- if (component.equals(mBoundComponent)) {
- if (D) Log.d(mTag, component + " connected");
- mBoundService = binder;
- if (mHandler !=null && mNewServiceWork != null) {
- mHandler.post(mNewServiceWork);
+ /**
+ * Start this watcher, including binding to the current best match and
+ * re-binding to any better matches down the road.
+ * <p>
+ * Note that if there are no matching encryption-aware services, we may not
+ * bind to a real service until after the current user is unlocked.
+ *
+ * @return {@code true} if a potential service implementation was found.
+ */
+ public final boolean start() {
+ // if we have to return false, do it before registering anything
+ if (isServiceMissing()) return false;
+
+ // listen for relevant package changes if service overlay is enabled on handler
+ if (mServicePackageName == null) {
+ new PackageMonitor() {
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
}
- } else {
- Log.w(mTag, "unexpected onServiceConnected: " + component);
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+ }
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+ return super.onPackageChanged(packageName, uid, components);
+ }
+ }.register(mContext, UserHandle.ALL, true, mHandler);
+ }
+
+ // listen for user change on handler
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mCurrentUserId = userId;
+ bindBestPackage(false);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ if (userId == mCurrentUserId) {
+ bindBestPackage(false);
+ }
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, mHandler);
+
+ mCurrentUserId = ActivityManager.getCurrentUser();
+
+ mHandler.post(() -> bindBestPackage(false));
+ return true;
+ }
+
+ /** Returns thje name of the currently connected package or null. */
+ @Nullable
+ public String getCurrentPackageName() {
+ ComponentName bestComponent = mBestComponent;
+ return bestComponent == null ? null : bestComponent.getPackageName();
+ }
+
+ public int getCurrentPackageVersion() {
+ return mBestVersion;
+ }
+
+ /**
+ * Runs the given BinderRunner if currently connected. Returns true if it was run, and false
+ * otherwise. All invocations to runOnBinder are run serially.
+ */
+ public final void runOnBinder(BinderRunner runner) {
+ synchronized (mBindLock) {
+ IBinder service = mBestService;
+ if (service != null) {
+ try {
+ runner.run(service);
+ } catch (Exception e) {
+ // remote exceptions cannot be allowed to crash system server
+ Log.e(TAG, "exception while while running " + runner + " on " + service
+ + " from " + mBestComponent.toShortString(), e);
+ }
}
}
}
+ private boolean isServiceMissing() {
+ return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.USER_SYSTEM).isEmpty();
+ }
+
+ /**
+ * Searches and binds to the best package, or do nothing if the best package
+ * is already bound, unless force rebinding is requested.
+ *
+ * @param forceRebind Force a rebinding to the best package if it's already
+ * bound.
+ */
+ @WorkerThread
+ private void bindBestPackage(boolean forceRebind) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ Intent intent = new Intent(mAction);
+ if (mServicePackageName != null) {
+ intent.setPackage(mServicePackageName);
+ }
+
+ List<ResolveInfo> rInfos = mContext.getPackageManager().queryIntentServicesAsUser(intent,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ mCurrentUserId);
+ if (rInfos == null) {
+ rInfos = Collections.emptyList();
+ }
+
+ ComponentName bestComponent = null;
+ int bestVersion = Integer.MIN_VALUE;
+ boolean bestIsMultiuser = false;
+
+ for (ResolveInfo rInfo : rInfos) {
+ ComponentName component = rInfo.serviceInfo.getComponentName();
+ String packageName = component.getPackageName();
+
+ // check signature
+ try {
+ PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_DIRECT_BOOT_AUTO);
+ if (!isSignatureMatch(pInfo.signatures, mSignatureSets)) {
+ Log.w(mTag, packageName + " resolves service " + mAction
+ + ", but has wrong signature, ignoring");
+ continue;
+ }
+ } catch (NameNotFoundException e) {
+ Log.wtf(mTag, e);
+ continue;
+ }
+
+ // check metadata
+ Bundle metadata = rInfo.serviceInfo.metaData;
+ int version = Integer.MIN_VALUE;
+ boolean isMultiuser = false;
+ if (metadata != null) {
+ version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
+ isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
+ }
+
+ if (version > bestVersion) {
+ bestComponent = component;
+ bestVersion = version;
+ bestIsMultiuser = isMultiuser;
+ }
+ }
+
+ if (D) {
+ Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
+ (mServicePackageName == null ? ""
+ : "(" + mServicePackageName + ") "), rInfos.size(),
+ (bestComponent == null ? "no new best component"
+ : "new best component: " + bestComponent)));
+ }
+
+ if (bestComponent == null) {
+ Slog.w(mTag, "Odd, no component found for service " + mAction);
+ unbind();
+ return;
+ }
+
+ int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
+ boolean alreadyBound = Objects.equals(bestComponent, mBestComponent)
+ && bestVersion == mBestVersion && userId == mBestUserId;
+ if (forceRebind || !alreadyBound) {
+ unbind();
+ bind(bestComponent, bestVersion, userId);
+ }
+ }
+
+ @WorkerThread
+ private void bind(ComponentName component, int version, int userId) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ Intent intent = new Intent(mAction);
+ intent.setComponent(component);
+
+ mBestComponent = component;
+ mBestVersion = version;
+ mBestUserId = userId;
+
+ if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
+ mContext.bindServiceAsUser(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
+ UserHandle.of(userId));
+ }
+
+ @WorkerThread
+ private void unbind() {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ if (mBestComponent != null) {
+ if (D) Log.d(mTag, "unbinding " + mBestComponent);
+ mContext.unbindService(this);
+ }
+
+ mBestComponent = null;
+ mBestVersion = Integer.MIN_VALUE;
+ mBestUserId = UserHandle.USER_NULL;
+ }
+
+ @MainThread
@Override
- public void onServiceDisconnected(ComponentName component) {
- synchronized (mLock) {
+ public final void onServiceConnected(ComponentName component, IBinder binder) {
+ mHandler.post(() -> {
+ if (D) Log.d(mTag, component + " connected");
+
+ // hold the lock so that mBestService cannot be used by runOnBinder until complete
+ synchronized (mBindLock) {
+ mBestService = binder;
+ onBind();
+ }
+ });
+ }
+
+ @MainThread
+ @Override
+ public final void onServiceDisconnected(ComponentName component) {
+ mHandler.post(() -> {
if (D) Log.d(mTag, component + " disconnected");
- if (component.equals(mBoundComponent)) {
- mBoundService = null;
+ mBestService = null;
+ synchronized (mBindLock) {
+ onUnbind();
}
- }
+ });
}
- public @Nullable String getBestPackageName() {
- synchronized (mLock) {
- return mBoundPackageName;
- }
- }
-
- public int getBestVersion() {
- synchronized (mLock) {
- return mBoundVersion;
- }
- }
-
- /**
- * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
- */
- public interface BinderRunner {
- /**
- * Runs on the retrieved binder.
- * @param binder the binder retrieved from the {@link ServiceWatcher}.
- */
- public void run(@NonNull IBinder binder);
- }
-
- /**
- * Retrieves the binder from {@link ServiceWatcher} and runs it.
- * @return whether a valid service exists.
- */
- public boolean runOnBinder(@NonNull BinderRunner runner) {
- synchronized (mLock) {
- if (mBoundService == null) {
- return false;
- } else {
- runner.run(mBoundService);
- return true;
- }
- }
- }
-
- public void switchUser(int userId) {
- synchronized (mLock) {
- mCurrentUserId = userId;
- bindBestPackageLocked(mServicePackageName, false);
- }
- }
-
- public void unlockUser(int userId) {
- synchronized (mLock) {
- if (userId == mCurrentUserId) {
- bindBestPackageLocked(mServicePackageName, false);
- }
- }
+ @Override
+ public String toString() {
+ ComponentName bestComponent = mBestComponent;
+ return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
}
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 793a177..bbb1d13 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1193,6 +1193,8 @@
if (i >= timings.length) {
if (repeatIndex >= 0) {
i = repeatIndex;
+ // prevent infinite loop
+ repeatIndex = -1;
} else {
break;
}
@@ -1258,8 +1260,6 @@
private final class VibratorShellCommand extends ShellCommand {
- private static final long MAX_VIBRATION_MS = 200;
-
private final IBinder mToken;
private VibratorShellCommand(IBinder token) {
@@ -1270,8 +1270,13 @@
public int onCommand(String cmd) {
if ("vibrate".equals(cmd)) {
return runVibrate();
+ } else if ("waveform".equals(cmd)) {
+ return runWaveform();
} else if ("prebaked".equals(cmd)) {
return runPrebaked();
+ } else if ("cancel".equals(cmd)) {
+ cancelVibrate(mToken);
+ return 0;
}
return handleDefaultCommands(cmd);
}
@@ -1303,9 +1308,6 @@
}
final long duration = Long.parseLong(getNextArgRequired());
- if (duration > MAX_VIBRATION_MS) {
- throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
- }
String description = getNextArg();
if (description == null) {
description = "Shell command";
@@ -1321,6 +1323,62 @@
}
}
+ private int runWaveform() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
+ try {
+ if (checkDoNotDisturb()) {
+ return 0;
+ }
+
+ String description = "Shell command";
+ int repeat = -1;
+ ArrayList<Integer> amplitudesList = null;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-d":
+ description = getNextArgRequired();
+ break;
+ case "-r":
+ repeat = Integer.parseInt(getNextArgRequired());
+ break;
+ case "-a":
+ if (amplitudesList == null) {
+ amplitudesList = new ArrayList<Integer>();
+ }
+ break;
+ }
+ }
+
+ ArrayList<Long> timingsList = new ArrayList<Long>();
+
+ String arg;
+ while ((arg = getNextArg()) != null) {
+ if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
+ amplitudesList.add(Integer.parseInt(arg));
+ } else {
+ timingsList.add(Long.parseLong(arg));
+ }
+ }
+
+ VibrationEffect effect;
+ long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
+ if (amplitudesList == null) {
+ effect = VibrationEffect.createWaveform(timings, repeat);
+ } else {
+ int[] amplitudes =
+ amplitudesList.stream().mapToInt(Integer::intValue).toArray();
+ effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
+ }
+ vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
+ "Shell Command", mToken);
+ return 0;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
private int runPrebaked() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
try {
@@ -1355,9 +1413,19 @@
pw.println(" vibrate duration [description]");
pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
pw.println(" (Do Not Disturb) mode.");
+ pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
+ pw.println(" Vibrates for durations and amplitudes in list;");
+ pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
+ pw.println(" If -r is provided, the waveform loops back to the specified");
+ pw.println(" index (e.g. 0 loops from the beginning)");
+ pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
+ pw.println(" otherwise, it accepts durations only and alternates off/on");
+ pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
pw.println(" prebaked effect-id [description]");
pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
pw.println(" (Do Not Disturb) mode.");
+ pw.println(" cancel");
+ pw.println(" Cancels any active vibration");
pw.println("");
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 9cc550d..d1b56e9 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -43,6 +43,7 @@
import com.android.internal.os.ZygoteConnectionConstants;
import com.android.server.am.ActivityManagerService;
+import com.android.server.wm.SurfaceAnimationThread;
import java.io.File;
import java.io.FileWriter;
@@ -280,6 +281,12 @@
// And the display thread.
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));
+ // And the animation thread.
+ mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
+ "animation thread", DEFAULT_TIMEOUT));
+ // And the surface animation thread.
+ mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
+ "surface animation thread", DEFAULT_TIMEOUT));
// Initialize monitor for Binder threads.
addMonitor(new BinderThreadMonitor());
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 52b0275..c52df2d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -127,6 +127,11 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
+import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -144,11 +149,6 @@
import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
-import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
-import static com.android.server.am.MemoryStatUtil.hasMemcg;
-import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
import android.Manifest;
import android.Manifest.permission;
@@ -1134,9 +1134,46 @@
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- String mProfileApp = null;
- ProcessRecord mProfileProc = null;
- ProfilerInfo mProfilerInfo = null;
+ class ProfileData {
+ private String mProfileApp = null;
+ private ProcessRecord mProfileProc = null;
+ private ProfilerInfo mProfilerInfo = null;
+
+ void setProfileApp(String profileApp) {
+ mProfileApp = profileApp;
+ if (mAtmInternal != null) {
+ mAtmInternal.setProfileApp(profileApp);
+ }
+ }
+
+ String getProfileApp() {
+ return mProfileApp;
+ }
+
+ void setProfileProc(ProcessRecord profileProc) {
+ mProfileProc = profileProc;
+ if (mAtmInternal != null) {
+ mAtmInternal.setProfileProc(
+ profileProc.getWindowProcessController());
+ }
+ }
+
+ ProcessRecord getProfileProc() {
+ return mProfileProc;
+ }
+
+ void setProfilerInfo(ProfilerInfo profilerInfo) {
+ mProfilerInfo = profilerInfo;
+ if (mAtmInternal != null) {
+ mAtmInternal.setProfilerInfo(profilerInfo);
+ }
+ }
+
+ ProfilerInfo getProfilerInfo() {
+ return mProfilerInfo;
+ }
+ }
+ final ProfileData mProfileData = new ProfileData();
/**
* Stores a map of process name -> agent string. When a process is started and mAgentAppMap
@@ -2225,8 +2262,7 @@
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mActivityTaskManager = atm;
- mActivityTaskManager.setActivityManagerService(this, mHandlerThread.getLooper(),
- mIntentFirewall, mPendingIntentController);
+ mActivityTaskManager.setActivityManagerService(mIntentFirewall, mPendingIntentController);
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mProcessCpuThread = new Thread("CpuTracker") {
@@ -3129,7 +3165,7 @@
}
}
- if (mProfileProc == app) {
+ if (mProfileData.getProfileProc() == app) {
clearProfilerLocked();
}
@@ -3852,7 +3888,7 @@
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- final int userId = UserHandle.getUserId(callingUid);
+ final int callingUserId = UserHandle.getUserId(callingUid);
final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
callingUid) == PackageManager.PERMISSION_GRANTED;
// Check REAL_GET_TASKS to see if they are allowed to access other uids
@@ -3870,11 +3906,17 @@
oomAdj = proc != null ? proc.setAdj : 0;
}
}
- if (!allUids || (!allUsers && (proc == null
- || UserHandle.getUserId(proc.uid) != userId))) {
- // The caller is not allow to get information about this other process...
- // just leave it empty.
- continue;
+ final int targetUid = (proc != null) ? proc.uid : -1;
+ final int targetUserId = (proc != null) ? UserHandle.getUserId(targetUid) : -1;
+
+ if (callingUid != targetUid) {
+ if (!allUids) {
+ continue; // Not allowed to see other UIDs.
+ }
+
+ if (!allUsers && (targetUserId != callingUserId)) {
+ continue; // Not allowed to see other users.
+ }
}
if (proc != null && proc.lastMemInfoTime >= lastNow && proc.lastMemInfo != null) {
// It hasn't been long enough that we want to take another sample; return
@@ -4410,16 +4452,18 @@
ProfilerInfo profilerInfo = null;
String preBindAgent = null;
- if (mProfileApp != null && mProfileApp.equals(processName)) {
- mProfileProc = app;
- if (mProfilerInfo != null) {
+ if (mProfileData.getProfileApp() != null
+ && mProfileData.getProfileApp().equals(processName)) {
+ mProfileData.setProfileProc(app);
+ if (mProfileData.getProfilerInfo() != null) {
// Send a profiler info object to the app if either a file is given, or
// an agent should be loaded at bind-time.
- boolean needsInfo = mProfilerInfo.profileFile != null
- || mProfilerInfo.attachAgentDuringBind;
- profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
- if (mProfilerInfo.agent != null) {
- preBindAgent = mProfilerInfo.agent;
+ boolean needsInfo = mProfileData.getProfilerInfo().profileFile != null
+ || mProfileData.getProfilerInfo().attachAgentDuringBind;
+ profilerInfo = needsInfo
+ ? new ProfilerInfo(mProfileData.getProfilerInfo()) : null;
+ if (mProfileData.getProfilerInfo().agent != null) {
+ preBindAgent = mProfileData.getProfilerInfo().agent;
}
}
} else if (instr != null && instr.mProfileFile != null) {
@@ -4443,7 +4487,8 @@
if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup();
- if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
+ if (TextUtils.equals(mProfileData.getProfileApp(), processName)
+ && mProfileData.getProfilerInfo() != null) {
clearProfilerLocked();
}
}
@@ -7320,13 +7365,6 @@
}
@Override
- public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
- int secondaryDisplayShowing) {
- mActivityTaskManager.setLockScreenShown(
- keyguardShowing, aodShowing, secondaryDisplayShowing);
- }
-
- @Override
public void notifyLockedProfile(@UserIdInt int userId) {
mAtmInternal.notifyLockedProfile(userId, mUserController.getCurrentUserId());
}
@@ -7451,17 +7489,17 @@
throw new SecurityException("Process not debuggable: " + app.packageName);
}
}
- mProfileApp = processName;
+ mProfileData.setProfileApp(processName);
- if (mProfilerInfo != null) {
- if (mProfilerInfo.profileFd != null) {
+ if (mProfileData.getProfilerInfo() != null) {
+ if (mProfileData.getProfilerInfo().profileFd != null) {
try {
- mProfilerInfo.profileFd.close();
+ mProfileData.getProfilerInfo().profileFd.close();
} catch (IOException e) {
}
}
}
- mProfilerInfo = new ProfilerInfo(profilerInfo);
+ mProfileData.setProfilerInfo(new ProfilerInfo(profilerInfo));
mProfileType = 0;
}
}
@@ -9978,20 +10016,25 @@
pw.println(" mTrackAllocationApp=" + mTrackAllocationApp);
}
}
- if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
- (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
- if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
+ if (mProfileData.getProfileApp() != null || mProfileData.getProfileProc() != null
+ || (mProfileData.getProfilerInfo() != null &&
+ (mProfileData.getProfilerInfo().profileFile != null
+ || mProfileData.getProfilerInfo().profileFd != null))) {
+ if (dumpPackage == null || dumpPackage.equals(mProfileData.getProfileApp())) {
if (needSep) {
pw.println();
needSep = false;
}
- pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
- if (mProfilerInfo != null) {
- pw.println(" mProfileFile=" + mProfilerInfo.profileFile + " mProfileFd=" +
- mProfilerInfo.profileFd);
- pw.println(" mSamplingInterval=" + mProfilerInfo.samplingInterval +
- " mAutoStopProfiler=" + mProfilerInfo.autoStopProfiler +
- " mStreamingOutput=" + mProfilerInfo.streamingOutput);
+ pw.println(" mProfileApp=" + mProfileData.getProfileApp()
+ + " mProfileProc=" + mProfileData.getProfileProc());
+ if (mProfileData.getProfilerInfo() != null) {
+ pw.println(" mProfileFile=" + mProfileData.getProfilerInfo().profileFile
+ + " mProfileFd=" + mProfileData.getProfilerInfo().profileFd);
+ pw.println(" mSamplingInterval="
+ + mProfileData.getProfilerInfo().samplingInterval +
+ " mAutoStopProfiler="
+ + mProfileData.getProfilerInfo().autoStopProfiler +
+ " mStreamingOutput=" + mProfileData.getProfilerInfo().streamingOutput);
pw.println(" mProfileType=" + mProfileType);
}
}
@@ -10271,19 +10314,26 @@
if (mTrackAllocationApp != null) {
if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
- proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP,
+ mTrackAllocationApp);
}
}
- if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
- (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
- if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
+ if (mProfileData.getProfileApp() != null || mProfileData.getProfileProc() != null
+ || (mProfileData.getProfilerInfo() != null &&
+ (mProfileData.getProfilerInfo().profileFile != null
+ || mProfileData.getProfilerInfo().profileFd != null))) {
+ if (dumpPackage == null || dumpPackage.equals(mProfileData.getProfileApp())) {
final long token = proto.start(ActivityManagerServiceDumpProcessesProto.PROFILE);
- proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME, mProfileApp);
- mProfileProc.writeToProto(proto,ActivityManagerServiceDumpProcessesProto.Profile.PROC);
- if (mProfilerInfo != null) {
- mProfilerInfo.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Profile.INFO);
- proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE, mProfileType);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME,
+ mProfileData.getProfileApp());
+ mProfileData.getProfileProc().writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.Profile.PROC);
+ if (mProfileData.getProfilerInfo() != null) {
+ mProfileData.getProfilerInfo().writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.Profile.INFO);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE,
+ mProfileType);
}
proto.end(token);
}
@@ -18040,8 +18090,8 @@
}
private void stopProfilerLocked(ProcessRecord proc, int profileType) {
- if (proc == null || proc == mProfileProc) {
- proc = mProfileProc;
+ if (proc == null || proc == mProfileData.getProfileProc()) {
+ proc = mProfileData.getProfileProc();
profileType = mProfileType;
clearProfilerLocked();
}
@@ -18056,15 +18106,16 @@
}
void clearProfilerLocked() {
- if (mProfilerInfo !=null && mProfilerInfo.profileFd != null) {
+ if (mProfileData.getProfilerInfo() != null
+ && mProfileData.getProfilerInfo().profileFd != null) {
try {
- mProfilerInfo.profileFd.close();
+ mProfileData.getProfilerInfo().profileFd.close();
} catch (IOException e) {
}
}
- mProfileApp = null;
- mProfileProc = null;
- mProfilerInfo = null;
+ mProfileData.setProfileApp(null);
+ mProfileData.setProfileProc(null);
+ mProfileData.setProfilerInfo(null);
}
public boolean profileControl(String process, int userId, boolean start,
@@ -18096,7 +18147,7 @@
if (start) {
stopProfilerLocked(null, 0);
setProfileApp(proc.info, proc.processName, profilerInfo);
- mProfileProc = proc;
+ mProfileData.setProfileProc(proc);
mProfileType = profileType;
ParcelFileDescriptor fd = profilerInfo.profileFd;
try {
@@ -18108,10 +18159,10 @@
proc.thread.profilerControl(start, profilerInfo, profileType);
fd = null;
try {
- mProfilerInfo.profileFd.close();
+ mProfileData.getProfilerInfo().profileFd.close();
} catch (IOException e) {
}
- mProfilerInfo.profileFd = null;
+ mProfileData.getProfilerInfo().profileFd = null;
if (proc.pid == MY_PID) {
// When profiling the system server itself, avoid closing the file
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bb87ad0..8a3f139 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1123,8 +1123,9 @@
@Override
public void clearProfilerIfNeeded() {
synchronized (mService) {
- if (mService.mProfileProc == null || mService.mProfilerInfo == null
- || mService.mProfileProc != this) {
+ if (mService.mProfileData.getProfileProc() == null
+ || mService.mProfileData.getProfilerInfo() == null
+ || mService.mProfileData.getProfileProc() != this) {
return;
}
mService.clearProfilerLocked();
@@ -1198,32 +1199,15 @@
}
@Override
- public ProfilerInfo onStartActivity(int topProcessState) {
+ public void onStartActivity(int topProcessState, boolean setProfileProc) {
synchronized (mService) {
- ProfilerInfo profilerInfo = null;
- if (mService.mProfileApp != null && mService.mProfileApp.equals(processName)) {
- if (mService.mProfileProc == null || mService.mProfileProc == this) {
- mService.mProfileProc = this;
- final ProfilerInfo profilerInfoSvc = mService.mProfilerInfo;
- if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
- if (profilerInfoSvc.profileFd != null) {
- try {
- profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
- } catch (IOException e) {
- profilerInfoSvc.closeFd();
- }
- }
-
- profilerInfo = new ProfilerInfo(profilerInfoSvc);
- }
- }
+ if (setProfileProc) {
+ mService.mProfileData.setProfileProc(this);
}
hasShownUi = true;
setPendingUiClean(true);
forceProcessStateUpTo(topProcessState);
-
- return profilerInfo;
}
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index f96f6e8..6596d27 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -94,7 +94,7 @@
final boolean hasIPv4Address =
(nai.linkProperties != null) && nai.linkProperties.hasIPv4Address();
final boolean skip464xlat =
- (nai.networkMisc != null) && nai.networkMisc.skip464xlat;
+ (nai.netMisc() != null) && nai.netMisc().skip464xlat;
return supported && connected && !hasIPv4Address && !skip464xlat;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 505480e..262184b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -266,6 +266,10 @@
return mConnService;
}
+ public NetworkMisc netMisc() {
+ return networkMisc;
+ }
+
public Handler handler() {
return mHandler;
}
diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
index f82b976..22fabb2 100644
--- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
@@ -16,59 +16,26 @@
package com.android.server.location;
-import com.android.server.ServiceWatcher;
-
import android.content.Context;
import android.hardware.location.ActivityRecognitionHardware;
import android.hardware.location.IActivityRecognitionHardwareClient;
import android.hardware.location.IActivityRecognitionHardwareWatcher;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.ServiceWatcher;
+
/**
* Proxy class to bind GmsCore to the ActivityRecognitionHardware.
*
* @hide
*/
public class ActivityRecognitionProxy {
+
private static final String TAG = "ActivityRecognitionProxy";
- private final ServiceWatcher mServiceWatcher;
- private final boolean mIsSupported;
- private final ActivityRecognitionHardware mInstance;
-
- private ActivityRecognitionProxy(
- Context context,
- Handler handler,
- boolean activityRecognitionHardwareIsSupported,
- ActivityRecognitionHardware activityRecognitionHardware,
- int overlaySwitchResId,
- int defaultServicePackageNameResId,
- int initialPackageNameResId) {
- mIsSupported = activityRecognitionHardwareIsSupported;
- mInstance = activityRecognitionHardware;
-
- Runnable newServiceWork = new Runnable() {
- @Override
- public void run() {
- bindProvider();
- }
- };
-
- // prepare the connection to the provider
- mServiceWatcher = new ServiceWatcher(
- context,
- TAG,
- "com.android.location.service.ActivityRecognitionProvider",
- overlaySwitchResId,
- defaultServicePackageNameResId,
- initialPackageNameResId,
- newServiceWork,
- handler);
- }
-
/**
* Creates an instance of the proxy and binds it to the appropriate FusedProvider.
*
@@ -76,7 +43,6 @@
*/
public static ActivityRecognitionProxy createAndBind(
Context context,
- Handler handler,
boolean activityRecognitionHardwareIsSupported,
ActivityRecognitionHardware activityRecognitionHardware,
int overlaySwitchResId,
@@ -84,74 +50,69 @@
int initialPackageNameResId) {
ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy(
context,
- handler,
activityRecognitionHardwareIsSupported,
activityRecognitionHardware,
overlaySwitchResId,
defaultServicePackageNameResId,
initialPackageNameResId);
- // try to bind the provider
- if (!activityRecognitionProxy.mServiceWatcher.start()) {
- Log.e(TAG, "ServiceWatcher could not start.");
+ if (activityRecognitionProxy.mServiceWatcher.start()) {
+ return activityRecognitionProxy;
+ } else {
return null;
}
- return activityRecognitionProxy;
}
- /**
- * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
- */
- private void bindProvider() {
- if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- String descriptor;
- try {
- descriptor = binder.getInterfaceDescriptor();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to get interface descriptor.", e);
- return;
- }
+ private final ServiceWatcher mServiceWatcher;
+ private final boolean mIsSupported;
+ private final ActivityRecognitionHardware mInstance;
- if (IActivityRecognitionHardwareWatcher.class.getCanonicalName()
- .equals(descriptor)) {
- IActivityRecognitionHardwareWatcher watcher =
- IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
- if (watcher == null) {
- Log.e(TAG, "No watcher found on connection.");
- return;
- }
- if (mInstance == null) {
- // to keep backwards compatibility do not update the watcher when there is
- // no instance available, or it will cause an NPE
- Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
- return;
- }
- try {
- watcher.onInstanceChanged(mInstance);
- } catch (RemoteException e) {
- Log.e(TAG, "Error delivering hardware interface to watcher.", e);
- }
- } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
- .equals(descriptor)) {
- IActivityRecognitionHardwareClient client =
- IActivityRecognitionHardwareClient.Stub.asInterface(binder);
- if (client == null) {
- Log.e(TAG, "No client found on connection.");
- return;
- }
- try {
- client.onAvailabilityChanged(mIsSupported, mInstance);
- } catch (RemoteException e) {
- Log.e(TAG, "Error delivering hardware interface to client.", e);
- }
- } else {
- Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
- }
+ private ActivityRecognitionProxy(
+ Context context,
+ boolean activityRecognitionHardwareIsSupported,
+ ActivityRecognitionHardware activityRecognitionHardware,
+ int overlaySwitchResId,
+ int defaultServicePackageNameResId,
+ int initialPackageNameResId) {
+ mIsSupported = activityRecognitionHardwareIsSupported;
+ mInstance = activityRecognitionHardware;
+
+ mServiceWatcher = new ServiceWatcher(
+ context,
+ TAG,
+ "com.android.location.service.ActivityRecognitionProvider",
+ overlaySwitchResId,
+ defaultServicePackageNameResId,
+ initialPackageNameResId,
+ BackgroundThread.getHandler()) {
+ @Override
+ protected void onBind() {
+ runOnBinder(ActivityRecognitionProxy.this::initializeService);
}
- })) {
- Log.e(TAG, "Null binder found on connection.");
+ };
+ }
+
+ private void initializeService(IBinder binder) {
+ try {
+ String descriptor = binder.getInterfaceDescriptor();
+
+ if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(
+ descriptor)) {
+ IActivityRecognitionHardwareWatcher watcher =
+ IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
+ if (mInstance != null) {
+ watcher.onInstanceChanged(mInstance);
+ }
+ } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
+ .equals(descriptor)) {
+ IActivityRecognitionHardwareClient client =
+ IActivityRecognitionHardwareClient.Stub.asInterface(binder);
+ client.onAvailabilityChanged(mIsSupported, mInstance);
+ } else {
+ Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
}
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 6423470..002d4e1 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -211,6 +211,10 @@
@Override
public boolean registerIntent(PendingIntent pendingIntent, long nanoAppId) {
ContextHubServiceUtil.checkPermissions(mContext);
+ if (mClientManager.isPendingIntentRegistered(pendingIntent)) {
+ Log.e(TAG, "Failed to register PendingIntent: already registered");
+ return false;
+ }
boolean success = false;
synchronized (this) {
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index 72879dd..fe93a1a 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -24,7 +24,6 @@
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
-import android.os.RemoteException;
import android.util.Log;
import java.util.concurrent.ConcurrentHashMap;
@@ -204,6 +203,20 @@
}
/**
+ * @param pendingIntent the PendingIntent to check
+ * @return true if the given PendingIntent is registered by a client, false otherwise
+ */
+ /* package */ boolean isPendingIntentRegistered(PendingIntent pendingIntent) {
+ for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+ if (broker.hasPendingIntent(pendingIntent)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Creates a new ContextHubClientBroker object for a client and registers it with the client
* manager.
*
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 9ad4aa1..f1de371 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -20,12 +20,12 @@
import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
-import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.os.BackgroundThread;
import com.android.server.ServiceWatcher;
+
import java.util.List;
/**
@@ -36,14 +36,13 @@
private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
- private final Context mContext;
private final ServiceWatcher mServiceWatcher;
public static GeocoderProxy createAndBind(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler) {
+ int initialPackageNamesResId) {
GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, handler);
+ defaultServicePackageNameResId, initialPackageNamesResId);
if (proxy.bind()) {
return proxy;
} else {
@@ -53,34 +52,30 @@
private GeocoderProxy(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler) {
- mContext = context;
-
- mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, null, handler);
+ int initialPackageNamesResId) {
+ mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
+ defaultServicePackageNameResId, initialPackageNamesResId,
+ BackgroundThread.getHandler());
}
- private boolean bind () {
+ private boolean bind() {
return mServiceWatcher.start();
}
public String getConnectedPackageName() {
- return mServiceWatcher.getBestPackageName();
+ return mServiceWatcher.getCurrentPackageName();
}
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[] {"Service not Available"};
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocation(
- latitude, longitude, maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ final String[] result = new String[]{"Service not Available"};
+ mServiceWatcher.runOnBinder(binder -> {
+ IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+ try {
+ result[0] = provider.getFromLocation(
+ latitude, longitude, maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
return result[0];
@@ -90,18 +85,15 @@
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[] {"Service not Available"};
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ final String[] result = new String[]{"Service not Available"};
+ mServiceWatcher.runOnBinder(binder -> {
+ IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+ try {
+ result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
return result[0];
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index eb47b2f..ca4f7fe 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -15,61 +15,60 @@
*/
package com.android.server.location;
+import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.hardware.location.GeofenceHardwareService;
import android.hardware.location.IGeofenceHardware;
+import android.location.IFusedGeofenceHardware;
import android.location.IGeofenceProvider;
import android.location.IGpsGeofenceHardware;
-import android.location.IFusedGeofenceHardware;
-import android.content.Context;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
+
+import com.android.internal.os.BackgroundThread;
import com.android.server.ServiceWatcher;
/**
* @hide
*/
public final class GeofenceProxy {
+
private static final String TAG = "GeofenceProxy";
- private static final String SERVICE_ACTION =
- "com.android.location.service.GeofenceProvider";
- private final ServiceWatcher mServiceWatcher;
+ private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider";
+
private final Context mContext;
+ private final ServiceWatcher mServiceWatcher;
+
+ @Nullable
private final IGpsGeofenceHardware mGpsGeofenceHardware;
+ @Nullable
private final IFusedGeofenceHardware mFusedGeofenceHardware;
- private final Object mLock = new Object();
+ private volatile IGeofenceHardware mGeofenceHardware;
- // Access to mGeofenceHardware needs to be synchronized by mLock.
- private IGeofenceHardware mGeofenceHardware;
-
- private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
- private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
- private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
- private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
- private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
-
- private Runnable mRunnable = new Runnable() {
- @Override
- public void run() {
- mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
+ private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> {
+ IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
+ try {
+ provider.setGeofenceHardware(mGeofenceHardware);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
};
public static GeofenceProxy createAndBind(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
- IFusedGeofenceHardware fusedGeofenceHardware) {
+ int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
+ @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence,
- fusedGeofenceHardware);
- if (proxy.bindGeofenceProvider()) {
+ defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence,
+ fusedGeofenceHardware);
+
+ if (proxy.bind()) {
return proxy;
} else {
return null;
@@ -78,111 +77,56 @@
private GeofenceProxy(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence,
- IFusedGeofenceHardware fusedGeofenceHardware) {
+ int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence,
+ @Nullable IFusedGeofenceHardware fusedGeofenceHardware) {
mContext = context;
mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
- defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
+ defaultServicePackageNameResId, initialPackageNamesResId,
+ BackgroundThread.getHandler()) {
+ @Override
+ protected void onBind() {
+ runOnBinder(mUpdateGeofenceHardware);
+ }
+ };
+
mGpsGeofenceHardware = gpsGeofence;
mFusedGeofenceHardware = fusedGeofenceHardware;
- bindHardwareGeofence();
+
+ mGeofenceHardware = null;
}
- private boolean bindGeofenceProvider() {
- return mServiceWatcher.start();
+ private boolean bind() {
+ if (mServiceWatcher.start()) {
+ mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
+ new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE,
+ UserHandle.SYSTEM);
+ return true;
+ }
+
+ return false;
}
- private void bindHardwareGeofence() {
- mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
- mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
- }
+ private class GeofenceProxyServiceConnection implements ServiceConnection {
- private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
- mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+ IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service);
+
+ try {
+ geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
+ geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
+
+ mGeofenceHardware = geofenceHardware;
+ mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
+ } catch (Exception e) {
+ Log.w(TAG, e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
- synchronized (mLock) {
- mGeofenceHardware = null;
- mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
- }
- }
- };
-
- private void setGeofenceHardwareInProviderLocked() {
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
- try {
- provider.setGeofenceHardware(mGeofenceHardware);
- } catch (RemoteException e) {
- Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
- }
- }
- });
- }
-
- private void setGpsGeofenceLocked() {
- try {
- if (mGpsGeofenceHardware != null) {
- mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error while connecting to GeofenceHardwareService");
+ mGeofenceHardware = null;
+ mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
}
}
-
- private void setFusedGeofenceLocked() {
- try {
- mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
- } catch(RemoteException e) {
- Log.e(TAG, "Error while connecting to GeofenceHardwareService");
- }
- }
-
- // This needs to be reworked, when more services get added,
- // Might need a state machine or add a framework utility class,
- private Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case GEOFENCE_PROVIDER_CONNECTED:
- synchronized (mLock) {
- if (mGeofenceHardware != null) {
- setGeofenceHardwareInProviderLocked();
- }
- // else: the geofence provider will be notified when the connection to
- // GeofenceHardwareService is established.
- }
- break;
- case GEOFENCE_HARDWARE_CONNECTED:
- synchronized (mLock) {
- // Theoretically this won't happen because once the GeofenceHardwareService
- // is connected to, we won't lose connection to it because it's a system
- // service. But this check does make the code more robust.
- if (mGeofenceHardware != null) {
- setGpsGeofenceLocked();
- setFusedGeofenceLocked();
- setGeofenceHardwareInProviderLocked();
- }
- }
- break;
- case GEOFENCE_HARDWARE_DISCONNECTED:
- synchronized (mLock) {
- if (mGeofenceHardware == null) {
- setGeofenceHardwareInProviderLocked();
- }
- }
- break;
- }
- }
- };
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 16eae62..bb86b48 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -16,26 +16,28 @@
package com.android.server.location;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-
+import android.annotation.Nullable;
import android.content.Context;
import android.location.LocationProvider;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
-import com.android.internal.location.ProviderProperties;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ILocationProvider;
+import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.TransferPipe;
import com.android.server.LocationManagerService;
import com.android.server.ServiceWatcher;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+
/**
* Proxy for ILocationProvider implementations.
*/
@@ -43,25 +45,36 @@
private static final String TAG = "LocationProviderProxy";
private static final boolean D = LocationManagerService.D;
- private final Context mContext;
- private final String mName;
private final ServiceWatcher mServiceWatcher;
- private Object mLock = new Object();
+ private final String mName;
- // cached values set by the location manager, synchronized on mLock
- private ProviderProperties mProperties;
- private boolean mEnabled = false;
- private ProviderRequest mRequest = null;
- private WorkSource mWorksource = new WorkSource();
+ // used to ensure that updates to mRequest and mWorkSource are atomic
+ private final Object mRequestLock = new Object();
+
+ private volatile boolean mEnabled = false;
+ @Nullable
+ private volatile ProviderProperties mProperties;
+
+ @GuardedBy("mRequestLock")
+ @Nullable
+ private ProviderRequest mRequest;
+ @GuardedBy("mRequestLock")
+ private WorkSource mWorkSource;
+
+ /**
+ * Creates a new LocationProviderProxy and immediately begins binding to the best applicable
+ * service.
+ */
+ @Nullable
public static LocationProviderProxy createAndBind(
Context context, String name, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler) {
- LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
- overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId,
- handler);
+ int initialPackageNamesResId) {
+ LocationProviderProxy proxy = new LocationProviderProxy(context, name,
+ action, overlaySwitchResId, defaultServicePackageNameResId,
+ initialPackageNamesResId);
if (proxy.bind()) {
return proxy;
} else {
@@ -69,78 +82,66 @@
}
}
- private LocationProviderProxy(Context context, String name, String action,
- int overlaySwitchResId, int defaultServicePackageNameResId,
- int initialPackageNamesResId, Handler handler) {
- mContext = context;
- mName = name;
- mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId,
+ private LocationProviderProxy(Context context, String name,
+ String action, int overlaySwitchResId, int defaultServicePackageNameResId,
+ int initialPackageNamesResId) {
+
+ mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId,
- mNewServiceWork, handler);
+ BackgroundThread.getHandler()) {
+ @Override
+ protected void onBind() {
+ runOnBinder(LocationProviderProxy.this::initializeService);
+ }
+ };
+ mName = name;
+
+ mProperties = null;
+ mRequest = null;
+ mWorkSource = new WorkSource();
}
- private boolean bind () {
+ private boolean bind() {
return mServiceWatcher.start();
}
- public String getConnectedPackageName() {
- return mServiceWatcher.getBestPackageName();
+ private void initializeService(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ if (D) Log.d(TAG, "applying state to connected service");
+
+ ProviderProperties[] properties = new ProviderProperties[1];
+ ProviderRequest request;
+ WorkSource source;
+ synchronized (mRequestLock) {
+ request = mRequest;
+ source = mWorkSource;
+ }
+
+ try {
+ // load properties from provider
+ properties[0] = service.getProperties();
+ if (properties[0] == null) {
+ Log.e(TAG, mServiceWatcher.getCurrentPackageName()
+ + " has invalid location provider properties");
+ }
+
+ // apply current state to new service
+ if (mEnabled) {
+ service.enable();
+ if (request != null) {
+ service.setRequest(request, source);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ }
+
+ mProperties = properties[0];
}
- /**
- * Work to apply current state to a newly connected provider.
- * Remember we can switch the service that implements a providers
- * at run-time, so need to apply current state.
- */
- private Runnable mNewServiceWork = new Runnable() {
- @Override
- public void run() {
- if (D) Log.d(TAG, "applying state to connected service");
-
- boolean enabled;
- final ProviderProperties[] properties = new ProviderProperties[1];
- ProviderRequest request;
- WorkSource source;
- synchronized (mLock) {
- enabled = mEnabled;
- request = mRequest;
- source = mWorksource;
- }
-
-
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- // load properties from provider
- properties[0] = service.getProperties();
- if (properties[0] == null) {
- Log.e(TAG, mServiceWatcher.getBestPackageName() +
- " has invalid location provider properties");
- }
-
- // apply current state to new service
- if (enabled) {
- service.enable();
- if (request != null) {
- service.setRequest(request, source);
- }
- }
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
- }
- });
-
- synchronized (mLock) {
- mProperties = properties[0];
- }
- }
- };
+ public String getConnectedPackageName() {
+ return mServiceWatcher.getCurrentPackageName();
+ }
@Override
public String getName() {
@@ -149,78 +150,52 @@
@Override
public ProviderProperties getProperties() {
- synchronized (mLock) {
- return mProperties;
- }
+ return mProperties;
}
@Override
public void enable() {
- synchronized (mLock) {
- mEnabled = true;
- }
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.enable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mEnabled = true;
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.enable();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
}
@Override
public void disable() {
- synchronized (mLock) {
- mEnabled = false;
- }
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.disable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mEnabled = false;
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.disable();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
}
@Override
public boolean isEnabled() {
- synchronized (mLock) {
- return mEnabled;
- }
+ return mEnabled;
}
@Override
public void setRequest(ProviderRequest request, WorkSource source) {
- synchronized (mLock) {
+ synchronized (mRequestLock) {
mRequest = request;
- mWorksource = source;
+ mWorkSource = source;
}
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.setRequest(request, source);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.setRequest(request, source);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
}
@@ -229,39 +204,28 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("REMOTE SERVICE");
pw.append(" name=").append(mName);
- pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
- pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
+ pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName());
+ pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion()));
pw.append('\n');
- if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- TransferPipe.dumpAsync(service.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- pw.println("Failed to dump location provider: " + e);
- }
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ TransferPipe.dumpAsync(service.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ pw.println("Failed to dump location provider: " + e);
}
- })) {
- pw.println("service down (null)");
- }
+ });
}
@Override
public int getStatus(Bundle extras) {
- final int[] result = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- result[0] = service.getStatus(extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE};
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.getStatus(extras);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
return result[0];
@@ -269,19 +233,13 @@
@Override
public long getStatusUpdateTime() {
- final long[] result = new long[] {0L};
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- result[0] = service.getStatusUpdateTime();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ long[] result = new long[]{0L};
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.getStatusUpdateTime();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
return result[0];
@@ -289,21 +247,15 @@
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
- final boolean[] result = new boolean[] {false};
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
- @Override
- public void run(IBinder binder) {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- result[0] = service.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ boolean[] result = new boolean[]{false};
+ mServiceWatcher.runOnBinder(binder -> {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.sendExtraCommand(command, extras);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
}
});
return result[0];
}
- }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 404f152..275f3dc 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -77,7 +77,6 @@
*/
public class LauncherAppsService extends SystemService {
- private static final boolean SHOW_HIDDEN_APP_ENABLED = false;
private final LauncherAppsImpl mLauncherAppsImpl;
public LauncherAppsService(Context context) {
@@ -310,22 +309,28 @@
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(packageName),
user);
- if (!SHOW_HIDDEN_APP_ENABLED) {
+ if (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 0) == 0) {
return launcherActivities;
}
final int callingUid = injectBinderCallingUid();
final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
if (packageName != null) {
- // If target package has launcher activities, then return those launcher
- // activities. Otherwise, return hidden activity that forwards user to app
- // details page.
+ // If this hidden app should not be shown, return the original list.
+ // Otherwise, inject hidden activity that forwards user to app details page.
if (result.size() > 0) {
return launcherActivities;
}
- ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
- if (info != null) {
- result.add(info);
+ ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
+ callingUid, user.getIdentifier());
+ if (shouldShowHiddenApp(appInfo)) {
+ ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
+ if (info != null) {
+ result.add(info);
+ }
}
return new ParceledListSlice<>(result);
}
@@ -336,8 +341,6 @@
for (ResolveInfo info : result) {
visiblePackages.add(info.activityInfo.packageName);
}
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0,
user.getIdentifier(), callingUid);
for (ApplicationInfo applicationInfo : installedPackages) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0b32d1a..1a5b86c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -58,7 +58,6 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -108,7 +107,9 @@
import java.util.Objects;
import java.util.Random;
-public class PackageInstallerService extends IPackageInstaller.Stub {
+/** The service responsible for installing packages. */
+public class PackageInstallerService extends IPackageInstaller.Stub implements
+ PackageSessionProvider {
private static final String TAG = "PackageInstaller";
private static final boolean LOGD = false;
@@ -297,6 +298,7 @@
in.setInput(fis, StandardCharsets.UTF_8.name());
int type;
+ PackageInstallerSession currentSession = null;
while ((type = in.next()) != END_DOCUMENT) {
if (type == START_TAG) {
final String tag = in.getName();
@@ -304,8 +306,10 @@
final PackageInstallerSession session;
try {
session = PackageInstallerSession.readFromXml(in, mInternalCallback,
- mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
+ mContext, mPm, mInstallThread.getLooper(), mSessionsDir, this);
+ currentSession = session;
} catch (Exception e) {
+ currentSession = null;
Slog.e(TAG, "Could not read session", e);
continue;
}
@@ -330,6 +334,10 @@
addHistoricalSessionLocked(session);
}
mAllocatedSessions.put(session.sessionId, true);
+ } else if (currentSession != null
+ && PackageInstallerSession.TAG_CHILD_SESSION.equals(tag)) {
+ currentSession.addChildSessionIdInternal(
+ PackageInstallerSession.readChildSessionIdFromXml(in));
}
}
}
@@ -437,70 +445,72 @@
}
}
- // Only system components can circumvent runtime permissions when installing.
- if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
- && mContext.checkCallingOrSelfPermission(Manifest.permission
- .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException("You need the "
- + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
- + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
- }
-
- if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
- || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- throw new IllegalArgumentException(
- "New installs into ASEC containers no longer supported");
- }
-
- // Defensively resize giant app icons
- if (params.appIcon != null) {
- final ActivityManager am = (ActivityManager) mContext.getSystemService(
- Context.ACTIVITY_SERVICE);
- final int iconSize = am.getLauncherLargeIconSize();
- if ((params.appIcon.getWidth() > iconSize * 2)
- || (params.appIcon.getHeight() > iconSize * 2)) {
- params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
- true);
- }
- }
-
- switch (params.mode) {
- case SessionParams.MODE_FULL_INSTALL:
- case SessionParams.MODE_INHERIT_EXISTING:
- break;
- default:
- throw new IllegalArgumentException("Invalid install mode: " + params.mode);
- }
-
- // If caller requested explicit location, sanity check it, otherwise
- // resolve the best internal or adopted location.
- if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- if (!PackageHelper.fitsOnInternal(mContext, params)) {
- throw new IOException("No suitable internal storage available");
+ if (!params.isMultiPackage) {
+ // Only system components can circumvent runtime permissions when installing.
+ if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
+ && mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException("You need the "
+ + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
- } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
- if (!PackageHelper.fitsOnExternal(mContext, params)) {
- throw new IOException("No suitable external storage available");
+ if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+ || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ throw new IllegalArgumentException(
+ "New installs into ASEC containers no longer supported");
}
- } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
- // For now, installs to adopted media are treated as internal from
- // an install flag point-of-view.
- params.setInstallFlagsInternal();
+ // Defensively resize giant app icons
+ if (params.appIcon != null) {
+ final ActivityManager am = (ActivityManager) mContext.getSystemService(
+ Context.ACTIVITY_SERVICE);
+ final int iconSize = am.getLauncherLargeIconSize();
+ if ((params.appIcon.getWidth() > iconSize * 2)
+ || (params.appIcon.getHeight() > iconSize * 2)) {
+ params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
+ true);
+ }
+ }
- } else {
- // For now, installs to adopted media are treated as internal from
- // an install flag point-of-view.
- params.setInstallFlagsInternal();
+ switch (params.mode) {
+ case SessionParams.MODE_FULL_INSTALL:
+ case SessionParams.MODE_INHERIT_EXISTING:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid install mode: " + params.mode);
+ }
- // Resolve best location for install, based on combination of
- // requested install flags, delta size, and manifest settings.
- final long ident = Binder.clearCallingIdentity();
- try {
- params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ // If caller requested explicit location, sanity check it, otherwise
+ // resolve the best internal or adopted location.
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ if (!PackageHelper.fitsOnInternal(mContext, params)) {
+ throw new IOException("No suitable internal storage available");
+ }
+
+ } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ if (!PackageHelper.fitsOnExternal(mContext, params)) {
+ throw new IOException("No suitable external storage available");
+ }
+
+ } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) {
+ // For now, installs to adopted media are treated as internal from
+ // an install flag point-of-view.
+ params.setInstallFlagsInternal();
+
+ } else {
+ // For now, installs to adopted media are treated as internal from
+ // an install flag point-of-view.
+ params.setInstallFlagsInternal();
+
+ // Resolve best location for install, based on combination of
+ // requested install flags, delta size, and manifest settings.
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -526,17 +536,19 @@
// We're staging to exactly one location
File stageDir = null;
String stageCid = null;
- if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- final boolean isInstant =
- (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
- } else {
- stageCid = buildExternalStageCid(sessionId);
+ if (!params.isMultiPackage) {
+ if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+ final boolean isInstant =
+ (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+ stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
+ } else {
+ stageCid = buildExternalStageCid(sessionId);
+ }
}
-
- session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
- mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
- params, createdMillis, stageDir, stageCid, false, false);
+ session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
+ mInstallThread.getLooper(), sessionId, userId, installerPackageName,
+ callingUid, params, createdMillis, stageDir, stageCid, false, false, null,
+ SessionInfo.INVALID_ID);
synchronized (mSessions) {
mSessions.put(sessionId, session);
@@ -646,8 +658,8 @@
}
try {
- Os.mkdir(stageDir.getAbsolutePath(), 0755);
- Os.chmod(stageDir.getAbsolutePath(), 0755);
+ Os.mkdir(stageDir.getAbsolutePath(), 0775);
+ Os.chmod(stageDir.getAbsolutePath(), 0775);
} catch (ErrnoException e) {
// This purposefully throws if directory already exists
throw new IOException("Failed to prepare session dir: " + stageDir, e);
@@ -679,7 +691,7 @@
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.userId == userId) {
+ if (session.userId == userId && !session.hasParentSessionId()) {
result.add(session.generateInfo(false));
}
}
@@ -700,7 +712,7 @@
SessionInfo info = session.generateInfo(false);
if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
- && session.userId == userId) {
+ && session.userId == userId && !session.hasParentSessionId()) {
result.add(info);
}
}
@@ -782,6 +794,13 @@
mCallbacks.unregister(callback);
}
+ @Override
+ public PackageInstallerSession getSession(int sessionId) {
+ synchronized (mSessions) {
+ return mSessions.get(sessionId);
+ }
+ }
+
private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
int installerUid) {
int count = 0;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 51225a7..26f6e96 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -43,9 +43,12 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.apex.IApexService;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
@@ -68,6 +71,7 @@
import android.os.FileBridge;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -75,6 +79,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -88,6 +93,7 @@
import android.util.ExceptionUtils;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.GuardedBy;
@@ -128,6 +134,7 @@
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
+ static final String TAG_CHILD_SESSION = "childSession";
private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
private static final String ATTR_SESSION_ID = "sessionId";
private static final String ATTR_USER_ID = "userId";
@@ -138,6 +145,8 @@
private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
private static final String ATTR_PREPARED = "prepared";
private static final String ATTR_SEALED = "sealed";
+ private static final String ATTR_MULTI_PACKAGE = "multiPackage";
+ private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
private static final String ATTR_MODE = "mode";
private static final String ATTR_INSTALL_FLAGS = "installFlags";
private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -155,6 +164,7 @@
private static final String ATTR_INSTALL_REASON = "installRason";
private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
+ private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
// TODO: enforce INSTALL_ALLOW_TEST
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
@@ -163,6 +173,7 @@
private final Context mContext;
private final PackageManagerService mPm;
private final Handler mHandler;
+ private final PackageSessionProvider mSessionProvider;
final int sessionId;
final int userId;
@@ -234,6 +245,10 @@
private long mVersionCode;
@GuardedBy("mLock")
private PackageParser.SigningDetails mSigningDetails;
+ @GuardedBy("mLock")
+ private SparseIntArray mChildSessionIds = new SparseIntArray();
+ @GuardedBy("mLock")
+ private int mParentSessionId;
/**
* Path to the validated base APK for this session, which may point at an
@@ -370,12 +385,16 @@
}
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
- Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
+ Context context, PackageManagerService pm,
+ PackageSessionProvider sessionProvider, Looper looper,
+ int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
- File stageDir, String stageCid, boolean prepared, boolean sealed) {
+ File stageDir, String stageCid, boolean prepared, boolean sealed,
+ @Nullable int[] childSessionIds, int parentSessionId) {
mCallback = callback;
mContext = context;
mPm = pm;
+ mSessionProvider = sessionProvider;
mHandler = new Handler(looper, mHandlerCallback);
this.sessionId = sessionId;
@@ -387,8 +406,14 @@
this.createdMillis = createdMillis;
this.stageDir = stageDir;
this.stageCid = stageCid;
+ if (childSessionIds != null) {
+ for (int childSessionId : childSessionIds) {
+ mChildSessionIds.put(childSessionId, 0);
+ }
+ }
+ this.mParentSessionId = parentSessionId;
- if ((stageDir == null) == (stageCid == null)) {
+ if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
throw new IllegalArgumentException(
"Exactly one of stageDir or stageCid stage must be set");
}
@@ -437,6 +462,12 @@
info.referrerUri = params.referrerUri;
info.grantedRuntimePermissions = params.grantedRuntimePermissions;
info.installFlags = params.installFlags;
+ info.isMultiPackage = params.isMultiPackage;
+ info.parentSessionId = mParentSessionId;
+ info.childSessionIds = mChildSessionIds.copyKeys();
+ if (info.childSessionIds == null) {
+ info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
+ }
}
return info;
}
@@ -760,6 +791,92 @@
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
+ if (!markAsCommitted(statusReceiver, forTransfer /* enforce */)) {
+ return;
+ }
+ if (isMultiPackage()) {
+
+ final SparseIntArray remainingSessions = mChildSessionIds.clone();
+ final ChildStatusIntentReceiver localIntentReceiver =
+ new ChildStatusIntentReceiver(remainingSessions, statusReceiver);
+ for (int childSessionId : getChildSessionIds()) {
+ mSessionProvider.getSession(childSessionId)
+ .markAsCommitted(localIntentReceiver.getIntentSender(), forTransfer);
+ }
+ }
+ mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
+ }
+
+ private class ChildStatusIntentReceiver {
+ private final SparseIntArray mChildSessionsRemaining;
+ private final IntentSender mStatusReceiver;
+ private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+ statusUpdate(intent);
+ }
+ };
+
+ private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
+ IntentSender statusReceiver) {
+ this.mChildSessionsRemaining = remainingSessions;
+ this.mStatusReceiver = statusReceiver;
+ }
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public void statusUpdate(Intent intent) {
+ mHandler.post(() -> {
+ if (mChildSessionsRemaining.size() == 0) {
+ return;
+ }
+ final int sessionId = intent.getIntExtra(
+ PackageInstaller.EXTRA_SESSION_ID, 0);
+ final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
+ if (PackageInstaller.STATUS_SUCCESS == status) {
+ mChildSessionsRemaining.removeAt(sessionIndex);
+ if (mChildSessionsRemaining.size() == 0) {
+ try {
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+ PackageInstallerSession.this.sessionId);
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ }
+ } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
+ try {
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ } else {
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
+ PackageInstallerSession.this.sessionId);
+ mChildSessionsRemaining.clear(); // we're done. Don't send any more.
+ try {
+ mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
+ } catch (IntentSender.SendIntentException ignore) {
+ }
+ }
+ });
+ }
+ }
+
+
+ /**
+ * Do everything but actually commit the session. If this was not already called, the session
+ * will be sealed and marked as committed. The caller of this method is responsible for
+ * subsequently submitting this session for processing.
+ *
+ * This method may be called multiple times to update the status receiver validate caller
+ * permissions.
+ */
+ public boolean markAsCommitted(
+ @NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
final boolean wasSealed;
@@ -784,6 +901,12 @@
}
}
+ // After validations and updating the observer, we can skip re-sealing, etc. because we
+ // have already marked ourselves as committed.
+ if (mCommitted) {
+ return true;
+ }
+
wasSealed = mSealed;
if (!mSealed) {
try {
@@ -794,7 +917,7 @@
// Do now throw an exception here to stay compatible with O and older
destroyInternal();
dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
- return;
+ return false;
}
}
@@ -807,7 +930,6 @@
mActiveCount.incrementAndGet();
mCommitted = true;
- mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
if (!wasSealed) {
@@ -816,6 +938,7 @@
// the session lock, since otherwise it's a lock inversion.
mCallback.onSessionSealedBlocking(this);
}
+ return true;
}
/**
@@ -831,29 +954,37 @@
assertNoWriteFileTransfersOpenLocked();
assertPreparedAndNotDestroyedLocked("sealing of session");
- final PackageInfo pkgInfo = mPm.getPackageInfo(
- params.appPackageName, PackageManager.GET_SIGNATURES
- | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
-
- resolveStageDirLocked();
-
mSealed = true;
- // Verify that stage looks sane with respect to existing application.
- // This currently only ensures packageName, versionCode, and certificate
- // consistency.
- try {
- validateInstallLocked(pkgInfo);
- } catch (PackageManagerException e) {
- throw e;
- } catch (Throwable e) {
- // Convert all exceptions into package manager exceptions as only those are handled
- // in the code above
- throw new PackageManagerException(e);
- }
-
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information.
+ if (!params.isMultiPackage) {
+ final PackageInfo pkgInfo = mPm.getPackageInfo(
+ params.appPackageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
+
+ resolveStageDirLocked();
+
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ try {
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ validateApexInstallLocked(pkgInfo);
+ } else {
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ validateApkInstallLocked(pkgInfo);
+ }
+ } catch (PackageManagerException e) {
+ throw e;
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above
+ throw new PackageManagerException(e);
+ }
+ }
}
@Override
@@ -911,10 +1042,83 @@
@GuardedBy("mLock")
private void commitLocked()
throws PackageManagerException {
- if (mRelinquished) {
- Slog.d(TAG, "Ignoring commit after previous commit relinquished control");
+ final PackageManagerService.ActiveInstallSession committingSession =
+ makeSessionActiveLocked();
+ if (committingSession == null) {
return;
}
+ if (isMultiPackage()) {
+ final int[] childSessionIds = getChildSessionIds();
+ List<PackageManagerService.ActiveInstallSession> childSessions =
+ new ArrayList<>(childSessionIds.length);
+ boolean success = true;
+ PackageManagerException failure = null;
+ for (int childSessionId : getChildSessionIds()) {
+ final PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
+ try {
+ final PackageManagerService.ActiveInstallSession activeSession =
+ session.makeSessionActiveLocked();
+ if (activeSession != null) {
+ if ((activeSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_APEX) != 0) {
+ // TODO(b/118865310): Add exception to this case for staged installs
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ "Atomic install is not supported for APEX packages.");
+ }
+ childSessions.add(activeSession);
+ }
+ } catch (PackageManagerException e) {
+ failure = e;
+ success = false;
+ }
+ }
+ if (!success) {
+ try {
+ mRemoteObserver.onPackageInstalled(
+ null, failure.error, failure.getLocalizedMessage(), null);
+ } catch (RemoteException ignored) {
+ }
+ return;
+ }
+ mPm.installStage(childSessions);
+ } else {
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ commitApexLocked();
+ } else {
+ mPm.installStage(committingSession);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitApexLocked() throws PackageManagerException {
+ try {
+ IApexService apex = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ apex.stagePackage(mResolvedBaseFile.toString());
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above
+ throw new PackageManagerException(e);
+ } finally {
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
+ }
+ }
+
+ /**
+ * Stages this session for install and returns a
+ * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
+ * in case permissions need to be requested before install can proceed.
+ */
+ @GuardedBy("mLock")
+ private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
+ throws PackageManagerException {
+ if (mRelinquished) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session relinquished");
+ }
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
}
@@ -922,83 +1126,86 @@
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
- Preconditions.checkNotNull(mPackageName);
- Preconditions.checkNotNull(mSigningDetails);
- Preconditions.checkNotNull(mResolvedBaseFile);
+ if (!params.isMultiPackage) {
+ Preconditions.checkNotNull(mPackageName);
+ Preconditions.checkNotNull(mSigningDetails);
+ Preconditions.checkNotNull(mResolvedBaseFile);
- if (needToAskForPermissionsLocked()) {
- // User needs to confirm installation; give installer an intent they can use to involve
- // user.
- final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
- intent.setPackage(mPm.getPackageInstallerPackageName());
- intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
- try {
- mRemoteObserver.onUserActionRequired(intent);
- } catch (RemoteException ignored) {
- }
-
- // Commit was keeping session marked as active until now; release
- // that extra refcount so session appears idle.
- closeInternal(false);
- return;
- }
-
- // Inherit any packages and native libraries from existing install that
- // haven't been overridden.
- if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
- try {
- final List<File> fromFiles = mResolvedInheritedFiles;
- final File toDir = resolveStageDirLocked();
-
- if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
- if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
- throw new IllegalStateException("mInheritedFilesBase == null");
+ if (needToAskForPermissionsLocked()) {
+ // User needs to confirm installation;
+ // give installer an intent they can use to involve
+ // user.
+ final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
+ intent.setPackage(mPm.getPackageInstallerPackageName());
+ intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ try {
+ mRemoteObserver.onUserActionRequired(intent);
+ } catch (RemoteException ignored) {
}
- if (isLinkPossible(fromFiles, toDir)) {
- if (!mResolvedInstructionSets.isEmpty()) {
- final File oatDir = new File(toDir, "oat");
- createOatDirs(mResolvedInstructionSets, oatDir);
+ // Commit was keeping session marked as active until now; release
+ // that extra refcount so session appears idle.
+ closeInternal(false);
+ return null;
+ }
+
+ // Inherit any packages and native libraries from existing install that
+ // haven't been overridden.
+ if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+ try {
+ final List<File> fromFiles = mResolvedInheritedFiles;
+ final File toDir = resolveStageDirLocked();
+
+ if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
+ if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
+ throw new IllegalStateException("mInheritedFilesBase == null");
}
- // pre-create lib dirs for linking if necessary
- if (!mResolvedNativeLibPaths.isEmpty()) {
- for (String libPath : mResolvedNativeLibPaths) {
- // "/lib/arm64" -> ["lib", "arm64"]
- final int splitIndex = libPath.lastIndexOf('/');
- if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
- Slog.e(TAG, "Skipping native library creation for linking due to "
- + "invalid path: " + libPath);
- continue;
- }
- final String libDirPath = libPath.substring(1, splitIndex);
- final File libDir = new File(toDir, libDirPath);
- if (!libDir.exists()) {
- NativeLibraryHelper.createNativeLibrarySubdir(libDir);
- }
- final String archDirPath = libPath.substring(splitIndex + 1);
- NativeLibraryHelper.createNativeLibrarySubdir(
- new File(libDir, archDirPath));
+
+ if (isLinkPossible(fromFiles, toDir)) {
+ if (!mResolvedInstructionSets.isEmpty()) {
+ final File oatDir = new File(toDir, "oat");
+ createOatDirs(mResolvedInstructionSets, oatDir);
}
+ // pre-create lib dirs for linking if necessary
+ if (!mResolvedNativeLibPaths.isEmpty()) {
+ for (String libPath : mResolvedNativeLibPaths) {
+ // "/lib/arm64" -> ["lib", "arm64"]
+ final int splitIndex = libPath.lastIndexOf('/');
+ if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
+ Slog.e(TAG,
+ "Skipping native library creation for linking due to "
+ + "invalid path: " + libPath);
+ continue;
+ }
+ final String libDirPath = libPath.substring(1, splitIndex);
+ final File libDir = new File(toDir, libDirPath);
+ if (!libDir.exists()) {
+ NativeLibraryHelper.createNativeLibrarySubdir(libDir);
+ }
+ final String archDirPath = libPath.substring(splitIndex + 1);
+ NativeLibraryHelper.createNativeLibrarySubdir(
+ new File(libDir, archDirPath));
+ }
+ }
+ linkFiles(fromFiles, toDir, mInheritedFilesBase);
+ } else {
+ // TODO: this should delegate to DCS so the system process
+ // avoids holding open FDs into containers.
+ copyFiles(fromFiles, toDir);
}
- linkFiles(fromFiles, toDir, mInheritedFilesBase);
- } else {
- // TODO: this should delegate to DCS so the system process
- // avoids holding open FDs into containers.
- copyFiles(fromFiles, toDir);
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Failed to inherit existing install", e);
}
- } catch (IOException e) {
- throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Failed to inherit existing install", e);
}
+
+ // TODO: surface more granular state from dexopt
+ mInternalProgress = 0.5f;
+ computeProgressLocked(true);
+
+ // Unpack native libraries
+ extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
}
-
- // TODO: surface more granular state from dexopt
- mInternalProgress = 0.5f;
- computeProgressLocked(true);
-
- // Unpack native libraries
- extractNativeLibraries(mResolvedStageDir, params.abiOverride, mayInheritNativeLibs());
-
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@@ -1023,8 +1230,11 @@
}
mRelinquished = true;
- mPm.installStage(mPackageName, stageDir, localObserver, params,
- mInstallerPackageName, mInstallerUid, user, mSigningDetails);
+ final PackageManagerService.ActiveInstallSession activeInstallSession =
+ new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
+ localObserver, params, mInstallerPackageName, mInstallerUid, user,
+ mSigningDetails);
+ return activeInstallSession;
}
private static void maybeRenameFile(File from, File to) throws PackageManagerException {
@@ -1047,6 +1257,57 @@
(params.installFlags & PackageManager.DONT_KILL_APP) != 0;
}
+ @GuardedBy("mLock")
+ private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
+ throws PackageManagerException {
+ mResolvedStagedFiles.clear();
+ mResolvedInheritedFiles.clear();
+
+ try {
+ resolveStageDirLocked();
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+ "Failed to resolve stage location", e);
+ }
+
+ final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+ if (ArrayUtils.isEmpty(addedFiles)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
+
+ if (addedFiles.length > 1) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Only one APEX file at a time might be installed");
+ }
+ File addedFile = addedFiles[0];
+ final ApkLite apk;
+ try {
+ apk = PackageParser.parseApkLite(
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+
+ mPackageName = apk.packageName;
+ mVersionCode = apk.getLongVersionCode();
+ mSigningDetails = apk.signingDetails;
+ mResolvedBaseFile = addedFile;
+
+ assertApkConsistentLocked(String.valueOf(addedFile), apk);
+
+ if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+ try {
+ // STOPSHIP: For APEX we should also implement proper APK Signature verification.
+ mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
+ pkgInfo.applicationInfo.sourceDir,
+ PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+ } catch (PackageParserException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Couldn't obtain signatures from base APK");
+ }
+ }
+ }
+
/**
* Validate install by confirming that all application packages are have
* consistent package name, version code, and signing certificates.
@@ -1060,7 +1321,7 @@
* {@link PackageManagerService}.
*/
@GuardedBy("mLock")
- private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
+ private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
throws PackageManagerException {
ApkLite baseApk = null;
mPackageName = null;
@@ -1475,6 +1736,14 @@
}
}
+ /**
+ * Adds a child session ID without any safety / sanity checks. This should only be used to
+ * build a session from XML or similar.
+ */
+ void addChildSessionIdInternal(int sessionId) {
+ mChildSessionIds.put(sessionId, 0);
+ }
+
public void open() throws IOException {
if (mActiveCount.getAndIncrement() == 0) {
mCallback.onSessionActiveChanged(this, true);
@@ -1486,6 +1755,8 @@
if (!mPrepared) {
if (stageDir != null) {
prepareStageDir(stageDir);
+ } else if (params.isMultiPackage) {
+ // it's all ok
} else {
throw new IllegalArgumentException("stageDir must be set");
}
@@ -1534,6 +1805,81 @@
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
}
+ @Override
+ public boolean isMultiPackage() {
+ return params.isMultiPackage;
+ }
+
+ @Override
+ public int[] getChildSessionIds() {
+ final int[] childSessionIds = mChildSessionIds.copyKeys();
+ if (childSessionIds != null) {
+ return childSessionIds;
+ }
+ return EMPTY_CHILD_SESSION_ARRAY;
+ }
+
+ @Override
+ public void addChildSessionId(int sessionId) {
+ final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+ if (session == null) {
+ throw new RemoteException("Unable to add child.",
+ new PackageManagerException("Child session " + sessionId + " does not exist"),
+ false, true).rethrowAsRuntimeException();
+ }
+ synchronized (mLock) {
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (indexOfSession >= 0) {
+ return;
+ }
+ session.setParentSessionId(this.sessionId);
+ addChildSessionIdInternal(sessionId);
+ }
+ }
+
+ @Override
+ public void removeChildSessionId(int sessionId) {
+ final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
+ synchronized (mLock) {
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (session != null) {
+ session.setParentSessionId(SessionInfo.INVALID_ID);
+ }
+ if (indexOfSession < 0) {
+ // not added in the first place; no-op
+ return;
+ }
+ mChildSessionIds.removeAt(indexOfSession);
+ }
+ }
+
+ /**
+ * Sets the parent session ID if not already set.
+ * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
+ */
+ void setParentSessionId(int parentSessionId) {
+ synchronized (mLock) {
+ if (parentSessionId != SessionInfo.INVALID_ID
+ && mParentSessionId != SessionInfo.INVALID_ID) {
+ throw new RemoteException("Unable to set parent session.",
+ new PackageManagerException(
+ "The parent of " + sessionId + " is" + " already set to "
+ + mParentSessionId), false,
+ true).rethrowAsRuntimeException();
+ }
+ this.mParentSessionId = parentSessionId;
+ }
+ }
+
+ boolean hasParentSessionId() {
+ return mParentSessionId != SessionInfo.INVALID_ID;
+ }
+
+ @Override
+ public int getParentSessionId() {
+ return mParentSessionId;
+ }
+
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
final IPackageInstallObserver2 observer;
final String packageName;
@@ -1623,6 +1969,7 @@
pw.printPair("mBridges", mBridges.size());
pw.printPair("mFinalStatus", mFinalStatus);
pw.printPair("mFinalMessage", mFinalMessage);
+ pw.printPair("params.isMultiPackage", params.isMultiPackage);
pw.println();
pw.decreaseIndent();
@@ -1673,6 +2020,10 @@
writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
writeBooleanAttribute(out, ATTR_SEALED, isSealed());
+ writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
+ // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
+ // we've read all sessions.
+ writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
writeIntAttribute(out, ATTR_MODE, params.mode);
writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
@@ -1707,6 +2058,12 @@
params.appIconLastModified = appIconFile.lastModified();
}
+ final int[] childSessionIds = getChildSessionIds();
+ for (int childSessionId : childSessionIds) {
+ out.startTag(null, TAG_CHILD_SESSION);
+ writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
+ out.endTag(null, TAG_CHILD_SESSION);
+ }
}
out.endTag(null, TAG_SESSION);
@@ -1751,11 +2108,15 @@
* @param installerThread Thread to be used for callbacks of this session
* @param sessionsDir The directory the sessions are stored in
*
+ * @param sessionProvider
* @return The newly created session
*/
+ // TODO(patb,109941548): modify readFromXml to consume to the next tag session tag so we
+ // can have a complete session for the constructor
public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
@NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
- @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
+ @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir,
+ @NonNull PackageSessionProvider sessionProvider)
throws IOException, XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
final int userId = readIntAttribute(in, ATTR_USER_ID);
@@ -1768,9 +2129,12 @@
final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
+ final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
+ SessionInfo.INVALID_ID);
final SessionParams params = new SessionParams(
SessionParams.MODE_INVALID);
+ params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
params.mode = readIntAttribute(in, ATTR_MODE);
params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
@@ -1793,9 +2157,16 @@
params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
params.appIconLastModified = appIconFile.lastModified();
}
-
- return new PackageInstallerSession(callback, context, pm,
+ return new PackageInstallerSession(callback, context, pm, sessionProvider,
installerThread, sessionId, userId, installerPackageName, installerUid,
- params, createdMillis, stageDir, stageCid, prepared, sealed);
+ params, createdMillis, stageDir, stageCid, prepared, sealed,
+ EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+ }
+
+ /**
+ * Reads the session ID from a child session tag stored in the provided {@link XmlPullParser}
+ */
+ static int readChildSessionIdFromXml(@NonNull XmlPullParser in) {
+ return readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9210d46..ed5b33b6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,6 +60,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -85,6 +86,11 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.isApkFile;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -234,7 +240,6 @@
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
-import android.permission.PermissionManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.security.KeyStore;
@@ -366,6 +371,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
@@ -2090,6 +2096,28 @@
}
}
+ @GuardedBy("mPackages")
+ private void setupBuiltinSharedLibraryDependenciesLocked() {
+ // Builtin libraries don't have versions.
+ long version = SharedLibraryInfo.VERSION_UNDEFINED;
+
+ SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ANDROID_HIDL_MANAGER, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_HIDL_BASE, version));
+ }
+
+ libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_RUNNER, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version));
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+ }
+
+ libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+ }
+ }
+
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
@@ -2205,6 +2233,9 @@
addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}
+ // Builtin libraries cannot encode their dependency where they are
+ // defined, so fix that now.
+ setupBuiltinSharedLibraryDependenciesLocked();
SELinuxMMAC.readInstallPolicy();
@@ -2899,60 +2930,6 @@
checkDefaultBrowser();
- // If a granted permission is split, all new permissions should be granted too
- if (mIsUpgrade) {
- final int callingUid = getCallingUid();
-
- final List<PermissionManager.SplitPermissionInfo> splitPermissions =
- mContext.getSystemService(PermissionManager.class).getSplitPermissions();
- final int numSplitPerms = splitPermissions.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- final PermissionManager.SplitPermissionInfo splitPerm =
- splitPermissions.get(splitPermNum);
- final String rootPerm = splitPerm.getSplitPermission();
-
- if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
- continue;
- }
-
- final int numPackages = mPackages.size();
- for (int packageNum = 0; packageNum < numPackages; packageNum++) {
- final PackageParser.Package pkg = mPackages.valueAt(packageNum);
-
- if (pkg.applicationInfo.targetSdkVersion >= splitPerm.getTargetSdk()
- || !pkg.requestedPermissions.contains(rootPerm)) {
- continue;
- }
-
- final int userId = UserHandle.getUserId(pkg.applicationInfo.uid);
- final String pkgName = pkg.packageName;
-
- if (checkPermission(rootPerm, pkgName, userId) == PERMISSION_DENIED) {
- continue;
- }
-
- final List<String> newPerms = splitPerm.getNewPermissions();
-
- final int numNewPerms = newPerms.size();
- for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
- final String newPerm = newPerms.get(newPermNum);
- if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
- continue;
- }
-
- if (DEBUG_PERMISSIONS) {
- Slog.v(TAG, "Granting " + newPerm + " to " + pkgName
- + " as the root permission " + rootPerm
- + " is already granted");
- }
-
- mPermissionManager.grantRuntimePermission(newPerm, pkgName, true,
- callingUid, userId, null);
- }
- }
- }
- }
-
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
@@ -4867,7 +4844,10 @@
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), libInfo.getDeclaringPackage(),
- getPackagesUsingSharedLibraryLPr(libInfo, flags, userId));
+ getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+ (libInfo.getDependencies() == null
+ ? null
+ : new ArrayList(libInfo.getDependencies())));
if (result == null) {
result = new ArrayList<>();
@@ -9598,16 +9578,34 @@
}
@GuardedBy("mPackages")
- private void addSharedLibraryLPr(Set<String> usesLibraryFiles,
- SharedLibraryInfo file,
- PackageParser.Package changingLib) {
+ private void applyDefiningSharedLibraryUpdateLocked(
+ PackageParser.Package pkg, SharedLibraryInfo libInfo,
+ BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
+ if (pkg.isLibrary()) {
+ if (pkg.staticSharedLibName != null) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+ action.accept(definedLibrary, libInfo);
+ } else {
+ for (String libraryName : pkg.libraryNames) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+ action.accept(definedLibrary, libInfo);
+ }
+ }
+ }
+ }
- if (file.getPath() != null) {
- usesLibraryFiles.add(file.getPath());
+ @GuardedBy("mPackages")
+ private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
+ SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+
+ if (libInfo.getPath() != null) {
+ usesLibraryFiles.add(libInfo.getPath());
return;
}
- PackageParser.Package p = mPackages.get(file.getPackageName());
- if (changingLib != null && changingLib.packageName.equals(file.getPackageName())) {
+ PackageParser.Package p = mPackages.get(libInfo.getPackageName());
+ if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
// If we are doing this while in the middle of updating a library apk,
// then we need to make sure to use that new apk for determining the
// dependencies here. (We haven't yet finished committing the new apk
@@ -9618,6 +9616,10 @@
}
if (p != null) {
usesLibraryFiles.addAll(p.getAllCodePaths());
+ // If the package provides libraries, add the dependency to them.
+ applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
+ definingLibrary.addDependency(dependency);
+ });
if (p.usesLibraryFiles != null) {
Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
}
@@ -9630,6 +9632,12 @@
if (pkg == null) {
return;
}
+
+ // If the package provides libraries, clear their old dependencies.
+ // This method will set them up again.
+ applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
+ definingLibrary.clearDependencies();
+ });
// The collection used here must maintain the order of addition (so
// that libraries are searched in the correct order) and must have no
// duplicates.
@@ -9656,7 +9664,7 @@
// usesLibraryFiles while eliminating duplicates.
Set<String> usesLibraryFiles = new LinkedHashSet<>();
for (SharedLibraryInfo libInfo : usesLibraryInfos) {
- addSharedLibraryLPr(usesLibraryFiles, libInfo, changingLib);
+ addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
}
pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
} else {
@@ -11201,7 +11209,7 @@
}
SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name,
version, type, new VersionedPackage(declaringPackageName, declaringVersionCode),
- null);
+ null, null);
versionedLib.put(version, libraryInfo);
return true;
}
@@ -12067,8 +12075,7 @@
void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
mComponentResolver.removeAllComponents(pkg, chatty);
- final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
- mPermissionManager.removeAllPermissions(pkg, allPackageNames, mPermissionCallback, chatty);
+ mPermissionManager.removeAllPermissions(pkg, chatty);
final int instrumentationSize = pkg.instrumentation.size();
StringBuilder r = null;
@@ -12296,28 +12303,15 @@
return installReason;
}
- void installStage(String packageName, File stagedDir,
- IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
- String installerPackageName, int installerUid, UserHandle user,
- PackageParser.SigningDetails signingDetails) {
+ void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
- if ((sessionParams.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + packageName);
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
- final VerificationInfo verificationInfo = new VerificationInfo(
- sessionParams.originatingUri, sessionParams.referrerUri,
- sessionParams.originatingUid, installerUid);
-
- final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
-
final Message msg = mHandler.obtainMessage(INIT_COPY);
- final int installReason = fixUpInstallReason(installerPackageName, installerUid,
- sessionParams.installReason);
- final InstallParams params = new InstallParams(origin, null, observer,
- sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
- verificationInfo, user, sessionParams.abiOverride,
- sessionParams.grantedRuntimePermissions, signingDetails, installReason);
+ final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12329,6 +12323,22 @@
mHandler.sendMessage(msg);
}
+ void installStage(List<ActiveInstallSession> children)
+ throws PackageManagerException {
+ final Message msg = mHandler.obtainMessage(INIT_COPY);
+ final MultiPackageInstallParams params =
+ new MultiPackageInstallParams(UserHandle.ALL, children);
+ params.setTraceMethod("installStageMultiPackage")
+ .setTraceCookie(System.identityHashCode(params));
+ msg.obj = params;
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+ System.identityHashCode(msg.obj));
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+ mHandler.sendMessage(msg);
+ }
+
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -13506,88 +13516,113 @@
}
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- // Result object to be returned
- PackageInstalledInfo res = new PackageInstalledInfo();
- res.setReturnCode(currentStatus);
- res.uid = -1;
- res.pkg = null;
- res.removedInfo = null;
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- args.doPreInstall(res.returnCode);
- synchronized (mInstallLock) {
- installPackageTracedLI(args, res);
- }
- args.doPostInstall(res.returnCode, res.uid);
+ if (args.mMultiPackageInstallParams != null) {
+ args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
+ } else {
+ PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
+ processInstallRequestsAsync(
+ res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+ }
+ }
+
+ // Queue up an async operation since the package installation may take a little while.
+ private void processInstallRequestsAsync(boolean success,
+ List<InstallRequest> installRequests) {
+ mHandler.post(() -> {
+ if (success) {
+ for (InstallRequest request : installRequests) {
+ request.args.doPreInstall(request.installResult.returnCode);
}
-
- // A restore should be performed at this point if (a) the install
- // succeeded, (b) the operation is not an update, and (c) the new
- // package has not opted out of backup participation.
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
- final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
- boolean doRestore = !update
- && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
-
- // Set up the post-install work request bookkeeping. This will be used
- // and cleaned up by the post-install event handling regardless of whether
- // there's a restore pass performed. Token values are >= 1.
- int token;
- if (mNextInstallToken < 0) mNextInstallToken = 1;
- token = mNextInstallToken++;
-
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
- if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
-
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
- // Pass responsibility to the Backup Manager. It will perform a
- // restore if appropriate, then pass responsibility back to the
- // Package Manager to run the post-install observer callbacks
- // and broadcasts.
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (bm != null) {
- if (DEBUG_INSTALL) Log.v(TAG, "token " + token
- + " to BM for possible restore");
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- try {
- // TODO: http://b/22388012
- if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
- } else {
- doRestore = false;
- }
- } catch (RemoteException e) {
- // can't happen; the backup manager is local
- } catch (Exception e) {
- Slog.e(TAG, "Exception trying to enqueue restore", e);
- doRestore = false;
- }
- } else {
- Slog.e(TAG, "Backup Manager not found!");
- doRestore = false;
- }
+ synchronized (mInstallLock) {
+ installPackagesTracedLI(installRequests);
}
-
- if (!doRestore) {
- // No restore possible, or the Backup Manager was mysteriously not
- // available -- just fire the post-install work request directly.
- if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
-
- Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
-
- Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
- mHandler.sendMessage(msg);
+ for (InstallRequest request : installRequests) {
+ request.args.doPostInstall(
+ request.installResult.returnCode, request.installResult.uid);
}
}
+ for (InstallRequest request : installRequests) {
+ resolvePackageInstalledInfo(request.args,
+ request.installResult);
+ }
});
}
+ private PackageInstalledInfo createPackageInstalledInfo(
+ int currentStatus) {
+ PackageInstalledInfo res = new PackageInstalledInfo();
+ res.setReturnCode(currentStatus);
+ res.uid = -1;
+ res.pkg = null;
+ res.removedInfo = null;
+ return res;
+ }
+
+ private void resolvePackageInstalledInfo(InstallArgs args, PackageInstalledInfo res) {
+ // A restore should be performed at this point if (a) the install
+ // succeeded, (b) the operation is not an update, and (c) the new
+ // package has not opted out of backup participation.
+ final boolean update = res.removedInfo != null
+ && res.removedInfo.removedPackage != null;
+ final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+ boolean doRestore = !update
+ && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
+
+ // Set up the post-install work request bookkeeping. This will be used
+ // and cleaned up by the post-install event handling regardless of whether
+ // there's a restore pass performed. Token values are >= 1.
+ int token;
+ if (mNextInstallToken < 0) mNextInstallToken = 1;
+ token = mNextInstallToken++;
+
+ PostInstallData data = new PostInstallData(args, res);
+ mRunningInstalls.put(token, data);
+ if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+ // Pass responsibility to the Backup Manager. It will perform a
+ // restore if appropriate, then pass responsibility back to the
+ // Package Manager to run the post-install observer callbacks
+ // and broadcasts.
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ if (DEBUG_INSTALL) {
+ Log.v(TAG, "token " + token + " to BM for possible restore");
+ }
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
+ try {
+ // TODO: http://b/22388012
+ if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
+ bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+ } else {
+ doRestore = false;
+ }
+ } catch (RemoteException e) {
+ // can't happen; the backup manager is local
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception trying to enqueue restore", e);
+ doRestore = false;
+ }
+ } else {
+ Slog.e(TAG, "Backup Manager not found!");
+ doRestore = false;
+ }
+ }
+
+ if (!doRestore) {
+ // No restore possible, or the Backup Manager was mysteriously not
+ // available -- just fire the post-install work request directly.
+ if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+
+ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ mHandler.sendMessage(msg);
+ }
+ }
+
/**
* Callback from PackageSettings whenever an app is first transitioned out of the
* 'stopped' state. Normally we just issue the broadcast, but we can't do that if
@@ -13775,7 +13810,83 @@
}
}
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ class MultiPackageInstallParams extends HandlerParams {
+
+ private int mRet = INSTALL_SUCCEEDED;
+ @NonNull
+ private final ArrayList<InstallParams> mChildParams;
+ @NonNull
+ private final Map<InstallArgs, Integer> mVerifiedState;
+
+ MultiPackageInstallParams(
+ @NonNull UserHandle user,
+ @NonNull List<ActiveInstallSession> activeInstallSessions)
+ throws PackageManagerException {
+ super(user);
+ if (activeInstallSessions.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = new ArrayList<>(activeInstallSessions.size());
+ for (int i = 0; i < activeInstallSessions.size(); i++) {
+ final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
+ childParams.mParentInstallParams = this;
+ this.mChildParams.add(childParams);
+ }
+ this.mVerifiedState = new ArrayMap<>(mChildParams.size());
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (InstallParams params : mChildParams) {
+ params.handleStartCopy();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ break;
+ }
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (InstallParams params : mChildParams) {
+ params.handleReturnCode();
+ if (params.mRet != INSTALL_SUCCEEDED) {
+ mRet = params.mRet;
+ break;
+ }
+ }
+ }
+
+ void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+ mVerifiedState.put(args, currentStatus);
+ boolean success = true;
+ if (mVerifiedState.size() != mChildParams.size()) {
+ return;
+ }
+ for (Integer status : mVerifiedState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ success = false;
+ break;
+ }
+ }
+ final List<InstallRequest> installRequests = new ArrayList<>(mVerifiedState.size());
+ for (Map.Entry<InstallArgs, Integer> entry : mVerifiedState.entrySet()) {
+ installRequests.add(new InstallRequest(entry.getKey(),
+ createPackageInstalledInfo(entry.getValue())));
+ }
+ processInstallRequestsAsync(success, installRequests);
+ }
+ }
+
class InstallParams extends HandlerParams {
+ // TODO: see if we can collapse this into ActiveInstallSession
+
final OriginInfo origin;
final MoveInfo move;
final IPackageInstallObserver2 observer;
@@ -13783,17 +13894,20 @@
final String installerPackageName;
final String volumeUuid;
private InstallArgs mArgs;
- private int mRet;
+ int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final VerificationInfo verificationInfo;
final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable
+ MultiPackageInstallParams mParentInstallParams;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, PackageParser.SigningDetails signingDetails, int installReason) {
+ String[] grantedPermissions, PackageParser.SigningDetails signingDetails,
+ int installReason) {
super(user);
this.origin = origin;
this.move = move;
@@ -13808,6 +13922,34 @@
this.installReason = installReason;
}
+ InstallParams(ActiveInstallSession activeInstallSession) {
+ super(activeInstallSession.getUser());
+ if (DEBUG_INSTANT) {
+ if ((activeInstallSession.getSessionParams().installFlags
+ & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
+ }
+ }
+ verificationInfo = new VerificationInfo(
+ activeInstallSession.getSessionParams().originatingUri,
+ activeInstallSession.getSessionParams().referrerUri,
+ activeInstallSession.getSessionParams().originatingUid,
+ activeInstallSession.getInstallerUid());
+ origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+ move = null;
+ installReason = fixUpInstallReason(activeInstallSession.getInstallerPackageName(),
+ activeInstallSession.getInstallerUid(),
+ activeInstallSession.getSessionParams().installReason);
+ observer = activeInstallSession.getObserver();
+ installFlags = activeInstallSession.getSessionParams().installFlags;
+ installerPackageName = activeInstallSession.getInstallerPackageName();
+ volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
+ packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
+ grantedRuntimePermissions =
+ activeInstallSession.getSessionParams().grantedRuntimePermissions;
+ signingDetails = activeInstallSession.getSigningDetails();
+ }
+
@Override
public String toString() {
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
@@ -14229,6 +14371,7 @@
final int traceCookie;
final PackageParser.SigningDetails signingDetails;
final int installReason;
+ @Nullable final MultiPackageInstallParams mMultiPackageInstallParams;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -14239,8 +14382,9 @@
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
- String traceMethod, int traceCookie, PackageParser.SigningDetails signingDetails,
- int installReason) {
+ String traceMethod, int traceCookie, SigningDetails signingDetails,
+ int installReason,
+ MultiPackageInstallParams multiPackageInstallParams) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -14255,6 +14399,7 @@
this.traceCookie = traceCookie;
this.signingDetails = signingDetails;
this.installReason = installReason;
+ this.mMultiPackageInstallParams = multiPackageInstallParams;
}
abstract int copyApk();
@@ -14350,7 +14495,7 @@
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason);
+ params.installReason, params.mParentInstallParams);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -14360,7 +14505,7 @@
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN);
+ PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -14552,7 +14697,7 @@
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie, params.signingDetails,
- params.installReason);
+ params.installReason, params.mParentInstallParams);
}
int copyApk() {
@@ -14957,10 +15102,10 @@
}
@GuardedBy({"mInstallLock", "mPackages"})
- private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo installResult) {
+ private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
- installPackagesLI(Collections.singletonList(new InstallRequest(args, installResult)));
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+ installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -15153,14 +15298,8 @@
pkgList.add(oldPackage.applicationInfo.packageName);
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
-
- clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE
- | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
-
-
// Update the in-memory copy of the previous code paths.
PackageSetting ps1 = mSettings.mPackages.get(
reconciledPkg.prepareResult.existingPackage.packageName);
@@ -15306,7 +15445,7 @@
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.packageName
- + " in atomic install request.");
+ + " in multi-package install request.");
return;
}
}
@@ -15364,7 +15503,8 @@
/**
* On successful install, executes remaining steps after commit completes and the package lock
- * is released.
+ * is released. These are typically more expensive or require calls to installd, which often
+ * locks on {@link #mPackages}.
*/
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
@@ -16093,7 +16233,6 @@
try {
final PackageParser.Package existingPackage;
String renamedPackage = null;
- boolean clearCodeCache = false;
boolean sysPkg = false;
String targetVolumeUuid = volumeUuid;
int targetScanFlags = scanFlags;
@@ -16314,7 +16453,6 @@
Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + oldPackage);
}
- clearCodeCache = true;
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
@@ -16370,7 +16508,7 @@
shouldCloseFreezerBeforeReturn = false;
return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
- clearCodeCache, sysPkg, renamedPackage, freezer);
+ replace /* clearCodeCache */, sysPkg, renamedPackage, freezer);
} finally {
if (shouldCloseFreezerBeforeReturn) {
freezer.close();
@@ -23379,6 +23517,62 @@
return mProtectedPackages.isPackageStateProtected(userId, packageName);
}
+
+ static class ActiveInstallSession {
+ private final String mPackageName;
+ private final File mStagedDir;
+ private final IPackageInstallObserver2 mObserver;
+ private final PackageInstaller.SessionParams mSessionParams;
+ private final String mInstallerPackageName;
+ private final int mInstallerUid;
+ private final UserHandle mUser;
+ private final SigningDetails mSigningDetails;
+
+ ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, String installerPackageName,
+ int installerUid, UserHandle user, SigningDetails signingDetails) {
+ mPackageName = packageName;
+ mStagedDir = stagedDir;
+ mObserver = observer;
+ mSessionParams = sessionParams;
+ mInstallerPackageName = installerPackageName;
+ mInstallerUid = installerUid;
+ mUser = user;
+ mSigningDetails = signingDetails;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public File getStagedDir() {
+ return mStagedDir;
+ }
+
+ public IPackageInstallObserver2 getObserver() {
+ return mObserver;
+ }
+
+ public PackageInstaller.SessionParams getSessionParams() {
+ return mSessionParams;
+ }
+
+ public String getInstallerPackageName() {
+ return mInstallerPackageName;
+ }
+
+ public int getInstallerUid() {
+ return mInstallerUid;
+ }
+
+ public UserHandle getUser() {
+ return mUser;
+ }
+
+ public SigningDetails getSigningDetails() {
+ return mSigningDetails;
+ }
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e25cca4..31711e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -173,6 +173,8 @@
return runSetInstallLocation();
case "get-install-location":
return runGetInstallLocation();
+ case "install-add-session":
+ return runInstallAddSession();
case "move-package":
return runMovePackage();
case "move-primary-storage":
@@ -920,7 +922,10 @@
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
- if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+ final boolean isApex =
+ (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+ String splitName = "base." + (isApex ? "apex" : "apk");
+ if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
@@ -980,6 +985,23 @@
return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
}
+ private int runInstallAddSession() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final int parentSessionId = Integer.parseInt(getNextArg());
+
+ List<Integer> otherSessionIds = new ArrayList<>();
+ String opt;
+ while ((opt = getNextArg()) != null) {
+ otherSessionIds.add(Integer.parseInt(opt));
+ }
+ if (otherSessionIds.size() == 0) {
+ pw.println("Error: At least two sessions are required.");
+ return 1;
+ }
+ return doInstallAddSession(parentSessionId, ArrayUtils.convertToIntArray(otherSessionIds),
+ true /*logSuccess*/);
+ }
+
private int runInstallRemove() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
@@ -2262,6 +2284,12 @@
case "--force-sdk":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
break;
+ case "--apex":
+ sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+ break;
+ case "--multi-package":
+ sessionParams.setMultiPackage();
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -2494,6 +2522,30 @@
}
}
+ private int doInstallAddSession(int parentId, int[] sessionIds, boolean logSuccess)
+ throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(
+ mInterface.getPackageInstaller().openSession(parentId));
+ if (!session.isMultiPackage()) {
+ getErrPrintWriter().println(
+ "Error: parent session ID is not a multi-package session");
+ return 1;
+ }
+ for (int i = 0; i < sessionIds.length; i++) {
+ session.addChildSessionId(sessionIds[i]);
+ }
+ if (logSuccess) {
+ pw.println("Success");
+ }
+ return 0;
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
@@ -2515,24 +2567,26 @@
}
}
- private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
+ private int doCommitSession(int sessionId, boolean logSuccess)
+ throws RemoteException {
+
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
-
- // Sanity check that all .dm files match an apk.
- // (The installer does not support standalone .dm files and will not process them.)
- try {
- DexMetadataHelper.validateDexPaths(session.getNames());
- } catch (IllegalStateException | IOException e) {
- pw.println("Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+ if (!session.isMultiPackage()) {
+ // Sanity check that all .dm files match an apk.
+ // (The installer does not support standalone .dm files and will not process them.)
+ try {
+ DexMetadataHelper.validateDexPaths(session.getNames());
+ } catch (IllegalStateException | IOException e) {
+ pw.println(
+ "Warning [Could not validate the dex paths: " + e.getMessage() + "]");
+ }
}
-
final LocalIntentReceiver receiver = new LocalIntentReceiver();
session.commit(receiver.getIntentSender());
-
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
@@ -2803,6 +2857,7 @@
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+ pw.println(" [--multi-package]");
pw.println(" Like \"install\", but starts an install session. Use \"install-write\"");
pw.println(" to push data into the session, and \"install-commit\" to finish.");
pw.println("");
@@ -2811,6 +2866,9 @@
pw.println(" will be read from stdin. Options are:");
pw.println(" -S: size in bytes of package, required for stdin");
pw.println("");
+ pw.println(" install-add-session MULTI_PACKAGE_SESSION_ID CHILD_SESSION_IDs");
+ pw.println(" Add one or more session IDs to a multi-package session.");
+ pw.println("");
pw.println(" install-commit SESSION_ID");
pw.println(" Commit the given active install session, installing the app.");
pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageSessionProvider.java b/services/core/java/com/android/server/pm/PackageSessionProvider.java
new file mode 100644
index 0000000..af11e77
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageSessionProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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;
+
+/** Provides access to individual sessions managed by the install service */
+public interface PackageSessionProvider {
+
+ /**
+ * Get the sessions for the provided session IDs. Null will be returned for session IDs that
+ * do not exist.
+ */
+ PackageInstallerSession getSession(int sessionId);
+
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e2818b7..4c93441 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -256,6 +257,7 @@
private static final String ATTR_USER_SET = "set";
private static final String ATTR_USER_FIXED = "fixed";
private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+ private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
// Flag mask of restored permission grants that are applied at install time
private static final int USER_RUNTIME_GRANT_MASK =
@@ -5011,6 +5013,9 @@
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
pw.print(" revoke_on_upgrade");
}
+ if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ pw.print(" revoke_when_requested");
+ }
pw.println();
}
}
@@ -5326,6 +5331,11 @@
if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
}
+ if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
+ != 0) {
+ serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
+ "true");
+ }
serializer.endTag(null, TAG_PERMISSION_ENTRY);
}
serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
@@ -5512,6 +5522,10 @@
if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
+ if ("true".equals(parser.getAttributeValue(null,
+ ATTR_REVOKE_WHEN_REQUESTED))) {
+ permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ }
if (isGranted || permBits != 0) {
rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 392d4d8..753c283 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -30,6 +30,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;
@@ -74,7 +75,7 @@
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
"pm.dexopt.priv-apps-oob-list";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
@@ -192,6 +193,16 @@
String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
classLoaderNames, classPaths);
+ // A null classLoaderContexts means that there are unsupported class loaders in the
+ // chain.
+ if (classLoaderContexts == null) {
+ if (DEBUG) {
+ Slog.i(TAG, loadingAppInfo.packageName +
+ " uses unsupported class loader in " + classLoaderNames);
+ }
+ return;
+ }
+
int dexPathIndex = 0;
for (String dexPath : dexPathsToRegister) {
// Find the owning package name.
@@ -219,14 +230,10 @@
}
// 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
+ // or UsedByOtherApps), 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.
- // A null classLoaderContexts means that there are unsupported class loaders in the
- // chain.
- String classLoaderContext = classLoaderContexts == null
- ? PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT
- : classLoaderContexts[dexPathIndex];
+ String classLoaderContext = classLoaderContexts[dexPathIndex];
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
loadingAppInfo.packageName, classLoaderContext)) {
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 602ce3b..86f7380 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -21,6 +21,7 @@
import android.os.Build;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastPrintWriter;
import com.android.server.pm.AbstractStatsBase;
import com.android.server.pm.PackageManagerServiceUtils;
@@ -78,14 +79,16 @@
// skip optimizations on that dex files.
/*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT =
"=VariableClassLoaderContext=";
- // The marker used for unsupported class loader contexts.
- /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
- "=UnsupportedClassLoaderContext=";
// The markers used for unknown class loader contexts. This can happen if the dex file was
// recorded in a previous version and we didn't have a chance to update its usage.
/*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT =
"=UnknownClassLoaderContext=";
+ // The marker used for unsupported class loader contexts (no longer written, may occur in old
+ // files so discarded on read).
+ private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
+ "=UnsupportedClassLoaderContext=";
+
// 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.).
@@ -365,6 +368,12 @@
Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
String classLoaderContext = maybeReadClassLoaderContext(in, version);
+ if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) {
+ // We used to record use of unsupported class loaders, but we no longer do.
+ // Discard such entries; they will be deleted when we next write the file.
+ continue;
+ }
+
int ownerUserId = Integer.parseInt(elems[0]);
boolean isUsedByOtherApps = readBoolean(elems[1]);
DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId,
@@ -709,13 +718,13 @@
// the compiled code will be private.
private boolean mUsedByOtherAppsBeforeUpgrade;
- public PackageUseInfo() {
+ /*package*/ PackageUseInfo() {
mCodePathsUsedByOtherApps = new HashMap<>();
mDexUseInfoMap = new HashMap<>();
}
// Creates a deep copy of the `other`.
- public PackageUseInfo(PackageUseInfo other) {
+ private PackageUseInfo(PackageUseInfo other) {
mCodePathsUsedByOtherApps = new HashMap<>();
for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) {
mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue()));
@@ -796,8 +805,9 @@
// Packages who load this dex file.
private final Set<String> mLoadingPackages;
- public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext,
- String loaderIsa) {
+ @VisibleForTesting
+ /* package */ DexUseInfo(boolean isUsedByOtherApps, int ownerUserId,
+ String classLoaderContext, String loaderIsa) {
mIsUsedByOtherApps = isUsedByOtherApps;
mOwnerUserId = ownerUserId;
mClassLoaderContext = classLoaderContext;
@@ -809,7 +819,7 @@
}
// Creates a deep copy of the `other`.
- public DexUseInfo(DexUseInfo other) {
+ private DexUseInfo(DexUseInfo other) {
mIsUsedByOtherApps = other.mIsUsedByOtherApps;
mOwnerUserId = other.mOwnerUserId;
mClassLoaderContext = other.mClassLoaderContext;
@@ -827,11 +837,7 @@
if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
// Can happen if we read a previous version.
mClassLoaderContext = dexUseInfo.mClassLoaderContext;
- } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) {
- // We detected an unsupported context.
- mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT;
- } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) &&
- !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
+ } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
// We detected a context change.
mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
}
@@ -846,7 +852,7 @@
return mIsUsedByOtherApps;
}
- public int getOwnerUserId() {
+ /* package */ int getOwnerUserId() {
return mOwnerUserId;
}
@@ -860,17 +866,15 @@
public String getClassLoaderContext() { return mClassLoaderContext; }
- public boolean isUnsupportedClassLoaderContext() {
- return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
- }
-
- public boolean isUnknownClassLoaderContext() {
+ @VisibleForTesting
+ /* package */ boolean isUnknownClassLoaderContext() {
// The class loader context may be unknown if we loaded the data from a previous version
// which didn't save the context.
return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
}
- public boolean isVariableClassLoaderContext() {
+ @VisibleForTesting
+ /* package */ boolean isVariableClassLoaderContext() {
return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index aae7b95..32b2bf0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.DownloadManager;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
@@ -40,7 +41,6 @@
import android.content.pm.ResolveInfo;
import android.media.RingtoneManager;
import android.net.Uri;
-import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
@@ -880,9 +880,8 @@
}
private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
- ResolveInfo handler = mServiceInternal.resolveIntent(intent,
- intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS,
- userId, false, Binder.getCallingUid());
+ ResolveInfo handler = mContext.getPackageManager().resolveActivityAsUser(
+ intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
if (handler == null || handler.activityInfo == null) {
return null;
}
@@ -899,8 +898,8 @@
private String getDefaultSystemHandlerServicePackage(
Intent intent, int userId) {
- List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
- intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId);
+ List<ResolveInfo> handlers = mContext.getPackageManager().queryIntentServicesAsUser(
+ intent, DEFAULT_INTENT_QUERY_FLAGS, userId);
if (handlers == null) {
return null;
}
@@ -924,10 +923,8 @@
for (String syncAdapterPackageName : syncAdapterPackageNames) {
homeIntent.setPackage(syncAdapterPackageName);
- ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
- homeIntent.resolveType(mContext.getContentResolver()),
- DEFAULT_INTENT_QUERY_FLAGS,
- userId, false, Binder.getCallingUid());
+ ResolveInfo homeActivity = mContext.getPackageManager().resolveActivityAsUser(
+ homeIntent, DEFAULT_INTENT_QUERY_FLAGS, userId);
if (homeActivity != null) {
continue;
}
@@ -941,7 +938,7 @@
}
private String getDefaultProviderAuthorityPackage(String authority, int userId) {
- ProviderInfo provider = mServiceInternal.resolveContentProvider(
+ ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
authority, DEFAULT_INTENT_QUERY_FLAGS, userId);
if (provider != null) {
return provider.packageName;
@@ -980,8 +977,9 @@
continue;
}
- final int flags = mServiceInternal.getPermissionFlagsTEMP(
- permission, packageName, userId);
+ UserHandle user = UserHandle.of(userId);
+ final int flags = mContext.getPackageManager()
+ .getPermissionFlags(permission, packageName, user);
// We didn't get this through the default grant policy. Move along.
if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -997,7 +995,7 @@
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
continue;
}
- mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false);
+ mContext.getPackageManager().revokeRuntimePermission(packageName, permission, user);
if (DEBUG) {
Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
@@ -1007,8 +1005,43 @@
// Remove the GRANTED_BY_DEFAULT flag without touching the others.
// Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
// sticky once set.
- mServiceInternal.updatePermissionFlagsTEMP(permission, packageName,
- PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId);
+ mContext.getPackageManager().updatePermissionFlags(permission, packageName,
+ PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, user);
+ }
+ }
+
+ /**
+ * Check if a permission is already fixed or is set by the user.
+ *
+ * <p>A permission should not be set by the default policy if the user or other policies already
+ * set the permission.
+ *
+ * @param flags The flags of the permission
+ *
+ * @return {@code true} iff the permission can be set without violating a policy of the users
+ * intention
+ */
+ private boolean isFixedOrUserSet(int flags) {
+ return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+ | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
+ }
+
+ /**
+ * Return the background permission for a permission.
+ *
+ * @param permission The name of the foreground permission
+ *
+ * @return The name of the background permission or {@code null} if the permission has no
+ * background permission
+ */
+ private @Nullable String getBackgroundPermission(@NonNull String permission) {
+ try {
+ return mContext.getPackageManager().getPermissionInfo(permission,
+ 0).backgroundPermission;
+ } catch (NameNotFoundException e) {
+ return null;
}
}
@@ -1024,9 +1057,15 @@
return;
}
+ PackageManager pm = mContext.getPackageManager();
final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
ApplicationInfo applicationInfo = pkg.applicationInfo;
+ int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ if (systemFixed) {
+ newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
// Automatically attempt to grant split permissions to older APKs
final List<PermissionManager.SplitPermissionInfo> splitPermissions =
mContext.getSystemService(PermissionManager.class).getSplitPermissions();
@@ -1066,9 +1105,28 @@
}
}
- final int grantablePermissionCount = requestedPermissions.length;
- for (int i = 0; i < grantablePermissionCount; i++) {
+ final int numRequestedPermissions = requestedPermissions.length;
+
+ // Sort requested permissions so that all permissions that are a foreground permission (i.e.
+ // permisions that have background permission) are before their background permissions.
+ final String[] sortedRequestedPermissions = new String[numRequestedPermissions];
+ int numForeground = 0;
+ int numOther = 0;
+ for (int i = 0; i < numRequestedPermissions; i++) {
String permission = requestedPermissions[i];
+ if (getBackgroundPermission(permission) != null) {
+ sortedRequestedPermissions[numForeground] = permission;
+ numForeground++;
+ } else {
+ sortedRequestedPermissions[numRequestedPermissions - 1 - numOther] =
+ permission;
+ numOther++;
+ }
+ }
+
+ for (int requestedPermissionNum = 0; requestedPermissionNum < numRequestedPermissions;
+ requestedPermissionNum++) {
+ String permission = requestedPermissions[requestedPermissionNum];
// If there is a disabled system app it may request a permission the updated
// version ot the data partition doesn't, In this case skip the permission.
@@ -1077,16 +1135,18 @@
}
if (permissions.contains(permission)) {
- final int flags = mServiceInternal.getPermissionFlagsTEMP(
- permission, pkg.packageName, userId);
+ UserHandle user = UserHandle.of(userId);
+ final int flags = mContext.getPackageManager().getPermissionFlags(
+ permission, pkg.packageName, user);
- // If any flags are set to the permission, then it is either set in
- // its current state by the system or device/profile owner or the user.
- // In all these cases we do not want to clobber the current state.
+ // Certain flags imply that the permission's current state by the system or
+ // device/profile owner or the user. In these cases we do not want to clobber the
+ // current state.
+ //
// Unless the caller wants to override user choices. The override is
// to make sure we can grant the needed permission to the default
// sms and phone apps after the user chooses this in the UI.
- if (flags == 0 || ignoreSystemPackage) {
+ if (!isFixedOrUserSet(flags) || ignoreSystemPackage) {
// Never clobber policy fixed permissions.
// We must allow the grant of a system-fixed permission because
// system-fixed is sticky, but the permission itself may be revoked.
@@ -1094,20 +1154,58 @@
continue;
}
- mServiceInternal.grantRuntimePermission(
- pkg.packageName, permission, userId, false);
+ int uid = UserHandle.getUid(userId,
+ UserHandle.getAppId(pkg.applicationInfo.uid));
+ String op = AppOpsManager.permissionToOp(permission);
+
+ mContext.getPackageManager()
+ .grantRuntimePermission(pkg.packageName, permission, user);
+
+ mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+ newFlags, newFlags, user);
+
+ List<String> fgPerms = mPermissionManager.getBackgroundPermissions()
+ .get(permission);
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ String fgPerm = fgPerms.get(fgPermNum);
+
+ if (pm.checkPermission(fgPerm, pkg.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ // Upgrade the app-op state of the fg permission to allow bg access
+ mContext.getSystemService(AppOpsManager.class).setMode(
+ AppOpsManager.permissionToOp(fgPerm), uid,
+ pkg.packageName, AppOpsManager.MODE_ALLOWED);
+
+ break;
+ }
+ }
+ }
+
+ String bgPerm = getBackgroundPermission(permission);
+ if (bgPerm == null) {
+ if (op != null) {
+ mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+ pkg.packageName, AppOpsManager.MODE_ALLOWED);
+ }
+ } else {
+ int mode;
+ if (pm.checkPermission(bgPerm, pkg.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ mode = AppOpsManager.MODE_ALLOWED;
+ } else {
+ mode = AppOpsManager.MODE_FOREGROUND;
+ }
+
+ mContext.getSystemService(AppOpsManager.class).setMode(op, uid,
+ pkg.packageName, mode);
+ }
+
if (DEBUG) {
Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
+ permission + " to default handler " + pkg);
}
-
- int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- if (systemFixed) {
- newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- }
-
- mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
- newFlags, newFlags, userId);
}
// If a component gets a permission for being the default handler A
@@ -1119,8 +1217,8 @@
Log.i(TAG, "Granted not fixed " + permission + " to default handler "
+ pkg);
}
- mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
- PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
+ mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+ PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, user);
}
}
}
@@ -1137,10 +1235,12 @@
private PackageInfo getPackageInfo(String pkg,
@PackageManager.PackageInfoFlags int extraFlags) {
- return mServiceInternal.getPackageInfo(pkg,
- DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags,
- //TODO is this the right filterCallingUid?
- UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM);
+ try {
+ return mContext.getPackageManager().getPackageInfo(pkg,
+ DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
}
private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index ffc4731..88b97ea 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,8 +1,9 @@
per-file DefaultPermissionGrantPolicy.java = bpoiesz@google.com
-per-file DefaultPermissionGrantPolicy.java = fkupolov@google.com
per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
per-file DefaultPermissionGrantPolicy.java = toddke@google.com
per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
per-file DefaultPermissionGrantPolicy.java = patb@google.com
+per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
+per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 80a5fbb..ec15c16 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -107,11 +107,7 @@
*/
public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract void removeAllPermissions(
- @NonNull PackageParser.Package pkg,
- @NonNull List<String> allPackageNames,
- @Nullable PermissionCallback permissionCallback,
- boolean chatty);
+ public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
int callingUid, @Nullable PermissionCallback callback);
public abstract void removeDynamicPermission(@NonNull String permName, int callingUid,
@@ -185,4 +181,4 @@
/** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4b6760c..5fa667a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -16,10 +16,28 @@
package com.android.server.pm.permission;
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.permissionToOp;
+import static android.app.AppOpsManager.permissionToOpCode;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.UserHandle.getAppId;
+import static android.os.UserHandle.getUid;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -30,8 +48,10 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
@@ -39,7 +59,6 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.metrics.LogMaker;
-import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -51,6 +70,7 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -154,6 +174,13 @@
@GuardedBy("mLock")
private boolean mSystemReady;
+ /**
+ * For each foreground/background permission the mapping:
+ * Background permission -> foreground permissions
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<String, List<String>> mBackgroundPermissions;
+
PermissionManagerService(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
@@ -478,9 +505,8 @@
" to " + newPermissionGroupName);
try {
- revokeRuntimePermission(permissionName, packageName,
- mSettings.getPermission(permissionName), false,
- Process.SYSTEM_UID, userId, permissionCallback, false);
+ revokeRuntimePermission(permissionName, packageName, false,
+ Process.SYSTEM_UID, userId, permissionCallback);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Could not revoke " + permissionName + " from "
+ packageName, e);
@@ -573,59 +599,9 @@
}
- private void revokeAllPermissions(
- @NonNull List<BasePermission> bps,
- @NonNull List<String> allPackageNames,
- @Nullable PermissionCallback permissionCallback) {
- AsyncTask.execute(() -> {
- final int numRemovedPermissions = bps.size();
- for (int permissionNum = 0; permissionNum < numRemovedPermissions; permissionNum++) {
- final int[] userIds = mUserManagerInt.getUserIds();
- final int numUserIds = userIds.length;
-
- final int numPackages = allPackageNames.size();
- for (int packageNum = 0; packageNum < numPackages; packageNum++) {
- final String packageName = allPackageNames.get(packageNum);
- final ApplicationInfo applicationInfo = mPackageManagerInt.getApplicationInfo(
- packageName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
- if (applicationInfo != null
- && applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- continue;
- }
- for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
- final int userId = userIds[userIdNum];
- final String permissionName = bps.get(permissionNum).getName();
- if (checkPermission(permissionName, packageName, UserHandle.USER_SYSTEM,
- userId) == PackageManager.PERMISSION_GRANTED) {
- try {
- revokeRuntimePermission(
- permissionName,
- packageName,
- bps.get(permissionNum),
- false,
- Process.SYSTEM_UID,
- userId,
- permissionCallback,
- true);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Could not revoke " + permissionName + " from "
- + packageName, e);
- }
- }
- }
- }
- }
- });
- }
-
- private void removeAllPermissions(
- @NonNull PackageParser.Package pkg,
- @NonNull List<String> allPackageNames,
- @Nullable PermissionCallback permissionCallback,
- boolean chatty) {
+ private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
synchronized (mLock) {
int N = pkg.permissions.size();
- List<BasePermission> bps = new ArrayList<BasePermission>(N);
StringBuilder r = null;
for (int i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
@@ -634,9 +610,6 @@
bp = mSettings.mPermissionTrees.get(p.info.name);
}
if (bp != null && bp.isPermission(p)) {
- if ((p.info.getProtection() & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
- bps.add(bp);
- }
bp.setPermission(null);
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -655,7 +628,6 @@
}
}
}
- revokeAllPermissions(bps, allPackageNames, permissionCallback);
if (r != null) {
if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
}
@@ -737,8 +709,24 @@
}
}
- private void grantPermissions(PackageParser.Package pkg, boolean replace,
- String packageOfInterest, PermissionCallback callback) {
+ /**
+ * Restore the permission state for a package.
+ *
+ * <ul>
+ * <li>During boot the state gets restored from the disk</li>
+ * <li>During app update the state gets restored from the last version of the app</li>
+ * </ul>
+ *
+ * <p>This restores the permission state for all users.
+ *
+ * @param pkg the package the permissions belong to
+ * @param replace if the package is getting replaced (this might change the requested
+ * permissions of this package)
+ * @param packageOfInterest If this is the name of {@code pkg} add extra logging
+ * @param callback Result call back
+ */
+ private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+ @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
// IMPORTANT: There are two types of permissions: install and runtime.
// Install time permissions are granted when the app is installed to
// all device users and users added in the future. Runtime permissions
@@ -866,7 +854,8 @@
}
if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
+ Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ + pkg.packageName);
}
if (grant != GRANT_DENIED) {
@@ -1055,6 +1044,11 @@
// changed.
ps.setInstallPermissionsFixed(true);
}
+
+ updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
+ updatedUserIds);
+ updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
+ permissionsState, pkg, updatedUserIds);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -1065,6 +1059,317 @@
}
}
+ /**
+ * Set app op for a app-op related to a permission.
+ *
+ * @param permission The permission the app-op belongs to
+ * @param pkg The package the permission belongs to
+ * @param userId The user to be changed
+ * @param mode The new mode to set
+ */
+ private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg,
+ @UserIdInt int userId, int mode) {
+ AppOpsManagerInternal appOpsInternal = LocalServices.getService(
+ AppOpsManagerInternal.class);
+
+ appOpsInternal.setMode(permissionToOpCode(permission),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkg.packageName, mode,
+ (pkg.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0);
+ }
+
+ /**
+ * Revoke permissions that are not implicit anymore and that have
+ * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
+ *
+ * @param ps The state of the permissions of the package
+ * @param pkg The package that is currently looked at
+ * @param updatedUserIds a list of user ids that needs to be amended if the permission state
+ * for a user is changed.
+ *
+ * @return The updated value of the {@code updatedUserIds} parameter
+ */
+ private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull int[] updatedUserIds) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ String pkgName = pkg.packageName;
+
+ int[] users = UserManagerService.getInstance().getUserIds();
+ int numUsers = users.length;
+ for (int i = 0; i < numUsers; i++) {
+ int userId = users[i];
+
+ for (String permission : ps.getPermissions(userId)) {
+ if (!pkg.implicitPermissions.contains(permission)) {
+ if (!ps.hasInstallPermission(permission)) {
+ int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
+
+ if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ BasePermission bp = mSettings.getPermissionLocked(permission);
+
+ ps.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
+ | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET,
+ 0);
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds,
+ userId);
+
+ if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
+ == 0) {
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ if (permissionToOpCode(permission) != OP_NONE) {
+ setAppOpMode(permission, pkg, userId, MODE_IGNORED);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking app-op "
+ + permissionToOp(permission) + " for " + pkgName
+ + " as it is now requested");
+ }
+ }
+ } else {
+ int revokeResult = ps.revokeRuntimePermission(bp, userId);
+ if (revokeResult
+ != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking runtime permission " + permission
+ + " for " + pkgName
+ + " as it is now requested");
+ }
+ }
+ }
+
+ List<String> fgPerms = mBackgroundPermissions.get(permission);
+ if (fgPerms != null) {
+ int numFgPerms = fgPerms.size();
+ for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
+ String fgPerm = fgPerms.get(fgPermNum);
+
+ int mode = appOpsManager.unsafeCheckOpRaw(
+ permissionToOp(fgPerm),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)),
+ pkgName);
+
+ if (mode == MODE_ALLOWED) {
+ setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return updatedUserIds;
+ }
+
+ /**
+ * {@code newPerm} is newly added; Inherit the state from {@code sourcePerms}.
+ *
+ * <p>A single new permission can be split off from several source permissions. In this case
+ * the most leniant state is inherited.
+ *
+ * <p>Warning: This does not handle foreground / background permissions
+ *
+ * @param sourcePerms The permissions to inherit from
+ * @param newPerm The permission to inherit to
+ * @param ps The permission state of the package
+ * @param pkg The package requesting the permissions
+ * @param userId The user the permission belongs to
+ */
+ private void inheritPermissionStateToNewImplicitPermissionLocked(
+ @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @UserIdInt int userId) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ String pkgName = pkg.packageName;
+
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ if (permissionToOp(newPerm) != null) {
+ int mostLenientSourceMode = MODE_ERRORED;
+
+ // Find most lenient source permission state.
+ int numSourcePerms = sourcePerms.size();
+ for (int i = 0; i < numSourcePerms; i++) {
+ String sourcePerm = sourcePerms.valueAt(i);
+
+ if (ps.hasRuntimePermission(sourcePerm, userId)) {
+ String sourceOp = permissionToOp(sourcePerm);
+
+ if (sourceOp != null) {
+ int mode = appOpsManager.unsafeCheckOpRaw(sourceOp,
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
+
+ if (mode == MODE_FOREGROUND) {
+ throw new IllegalArgumentException("split permission" + sourcePerm
+ + " has app-op state " + AppOpsManager.MODE_NAMES[mode]);
+ }
+
+ // Leniency order: allowed > ignored > default
+ if (mode == MODE_ALLOWED) {
+ mostLenientSourceMode = MODE_ALLOWED;
+ break;
+ } else if (mode == MODE_IGNORED) {
+ mostLenientSourceMode = MODE_IGNORED;
+ } else if (mode == MODE_DEFAULT
+ && mostLenientSourceMode != MODE_IGNORED) {
+ mostLenientSourceMode = MODE_DEFAULT;
+ }
+ }
+ }
+ }
+
+ if (mostLenientSourceMode != MODE_ERRORED) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode
+ + " from " + sourcePerms + " for " + pkgName);
+ }
+
+ setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode);
+ }
+ }
+ } else {
+ boolean isGranted = false;
+
+ int numSourcePerm = sourcePerms.size();
+ for (int i = 0; i < numSourcePerm; i++) {
+ String sourcePerm = sourcePerms.valueAt(i);
+ if (ps.hasRuntimePermission(sourcePerm, userId)
+ && ps.getRuntimePermissionState(sourcePerm, userId).isGranted()) {
+ isGranted = true;
+ break;
+ }
+ }
+
+ if (isGranted) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms
+ + " for " + pkgName);
+ }
+
+ ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
+ }
+ }
+ }
+
+ /**
+ * Set the state of a implicit permission that is seen for the first time.
+ *
+ * @param origPs The permission state of the package before the split
+ * @param ps The new permission state
+ * @param pkg The package the permission belongs to
+ * @param updatedUserIds List of users for which the permission state has already been changed
+ *
+ * @return List of users for which the permission state has been changed
+ */
+ private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
+ @NonNull PermissionsState origPs,
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull int[] updatedUserIds) {
+ AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ String pkgName = pkg.packageName;
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
+
+ int numRequestedPerms = pkg.requestedPermissions.size();
+ for (int i = 0; i < numRequestedPerms; i++) {
+ BasePermission bp = mSettings.getPermissionLocked(pkg.requestedPermissions.get(i));
+ if (bp != null) {
+ String perm = bp.getName();
+
+ if (!origPs.hasRequestedPermission(perm) && pkg.implicitPermissions.contains(
+ perm)) {
+ newImplicitPermissions.add(perm);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, perm + " is newly added for " + pkgName);
+ }
+ }
+ }
+ }
+
+ ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
+
+ int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ PermissionManager.SplitPermissionInfo spi =
+ PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+
+ List<String> newPerms = spi.getNewPermissions();
+ int numNewPerms = newPerms.size();
+ for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
+ String newPerm = newPerms.get(newPermNum);
+
+ ArraySet<String> splitPerms = newToSplitPerms.get(newPerm);
+ if (splitPerms == null) {
+ splitPerms = new ArraySet<>();
+ newToSplitPerms.put(newPerm, splitPerms);
+ }
+
+ splitPerms.add(spi.getSplitPermission());
+ }
+ }
+
+ int numNewImplicitPerms = newImplicitPermissions.size();
+ for (int newImplicitPermNum = 0; newImplicitPermNum < numNewImplicitPerms;
+ newImplicitPermNum++) {
+ String newPerm = newImplicitPermissions.valueAt(newImplicitPermNum);
+ ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm);
+
+ if (sourcePerms != null) {
+ if (!ps.hasInstallPermission(newPerm)) {
+ BasePermission bp = mSettings.getPermissionLocked(newPerm);
+
+ int[] users = UserManagerService.getInstance().getUserIds();
+ int numUsers = users.length;
+ for (int userNum = 0; userNum < numUsers; userNum++) {
+ int userId = users[userNum];
+
+ ps.updatePermissionFlags(bp, userId,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
+ FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+
+ // SPECIAL BEHAVIOR for background location. Foreground only by default.
+ if (newPerm.equals(ACCESS_BACKGROUND_LOCATION)) {
+ int numSourcePerms = sourcePerms.size();
+ for (int sourcePermNum = 0; sourcePermNum < numSourcePerms;
+ sourcePermNum++) {
+ String sourcePerm = sourcePerms.valueAt(sourcePermNum);
+
+ if (appOpsManager.unsafeCheckOpNoThrow(permissionToOp(sourcePerm),
+ getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName)
+ == MODE_ALLOWED) {
+ setAppOpMode(sourcePerm, pkg, userId, MODE_FOREGROUND);
+ }
+ }
+ } else {
+ if (!origPs.hasRequestedPermission(sourcePerms)) {
+ // Both permissions are new, do nothing
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+ + " for " + pkgName
+ + " as split permission is also new");
+ }
+
+ break;
+ } else {
+ inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
+ newPerm, ps, pkg, userId);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return updatedUserIds;
+ }
+
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;
@@ -1571,10 +1876,9 @@
}
}
-
- private void revokeRuntimePermission(String permName, String packageName, BasePermission bp,
- boolean overridePolicy, int callingUid, int userId, PermissionCallback callback,
- boolean permissionRemoved) {
+
+ private void revokeRuntimePermission(String permName, String packageName,
+ boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) {
if (!mUserManagerInt.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
@@ -1599,7 +1903,7 @@
if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
-
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + permName);
}
@@ -1812,7 +2116,29 @@
// and make sure there are no dangling permissions.
flags = updatePermissions(changingPkgName, changingPkg, flags);
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
+ synchronized (mLock) {
+ if (mBackgroundPermissions == null) {
+ // Cache background -> foreground permission mapping.
+ // Only system declares background permissions, hence mapping does never change.
+ mBackgroundPermissions = new ArrayMap<>();
+ for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
+ if (bp.perm.info != null && bp.perm.info.backgroundPermission != null) {
+ String fgPerm = bp.name;
+ String bgPerm = bp.perm.info.backgroundPermission;
+
+ List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
+ if (fgPerms == null) {
+ fgPerms = new ArrayList<>();
+ mBackgroundPermissions.put(bgPerm, fgPerms);
+ }
+
+ fgPerms.add(fgPerm);
+ }
+ }
+ }
+ }
+
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
@@ -1822,7 +2148,7 @@
final String volumeUuid = getVolumeUuidForPackage(pkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissions(pkg, replace, changingPkgName, callback);
+ restorePermissionState(pkg, replace, changingPkgName, callback);
}
}
}
@@ -1832,7 +2158,7 @@
final String volumeUuid = getVolumeUuidForPackage(changingPkg);
final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
&& Objects.equals(replaceVolumeUuid, volumeUuid);
- grantPermissions(changingPkg, replace, changingPkgName, callback);
+ restorePermissionState(changingPkg, replace, changingPkgName, callback);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -2129,6 +2455,17 @@
mMetricsLogger.write(log);
}
+ /**
+ * Get the mapping of background permissions to their foreground permissions.
+ *
+ * <p>Only initialized in the system server.
+ *
+ * @return the map <bg permission -> list<fg perm>>
+ */
+ public @Nullable ArrayMap<String, List<String>> getBackgroundPermissions() {
+ return mBackgroundPermissions;
+ }
+
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
@Override
public void systemReady() {
@@ -2156,10 +2493,8 @@
PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
}
@Override
- public void removeAllPermissions(Package pkg, List<String> allPackageNames,
- PermissionCallback permissionCallback, boolean chatty) {
- PermissionManagerService.this.removeAllPermissions(
- pkg, allPackageNames, permissionCallback, chatty);
+ public void removeAllPermissions(Package pkg, boolean chatty) {
+ PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
@Override
public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
@@ -2195,8 +2530,7 @@
boolean overridePolicy, int callingUid, int userId,
PermissionCallback callback) {
PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
- mSettings.getPermission(permName), overridePolicy, callingUid, userId,
- callback, false);
+ overridePolicy, callingUid, userId, callback);
}
@Override
public void updatePermissions(String packageName, Package pkg, boolean replaceGrant,
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 1e0b52a..ae1090c 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,13 +1,11 @@
package com.android.server.policy.keyguard;
-import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.wm.KeyguardServiceDelegateProto.INTERACTIVE_STATE;
import static com.android.server.wm.KeyguardServiceDelegateProto.OCCLUDED;
import static com.android.server.wm.KeyguardServiceDelegateProto.SCREEN_STATE;
import static com.android.server.wm.KeyguardServiceDelegateProto.SECURE;
import static com.android.server.wm.KeyguardServiceDelegateProto.SHOWING;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
@@ -212,10 +210,10 @@
mHandler.post(() -> {
try {
// There are no longer any keyguard windows on secondary displays, so pass
- // INVALID_DISPLAY. All that means is that showWhenLocked activities on
- // secondary displays now get to show.
+ // {@code null}. All that means is that showWhenLocked activities on
+ // external displays now get to show.
ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */,
- false /* aodShowing */, INVALID_DISPLAY);
+ false /* aodShowing */, null /* secondaryDisplaysShowing */);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 4f8e6b6..6d7b04c 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -57,16 +57,32 @@
public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
- // Secure setting for GPS behavior when battery saver mode is on.
- public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
-
private static final String KEY_GPS_MODE = "gps_mode";
private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
- private static final String KEY_FIREWALL_DISABLED = "firewall_disabled";
+
+ /**
+ * Disable turning on the network firewall when Battery Saver is turned on.
+ * If set to false, the firewall WILL be turned on when Battery Saver is turned on.
+ * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on.
+ */
+ private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled";
+
+ /**
+ * Disable turning on the special low power screen brightness dimming when Battery Saver is
+ * turned on.
+ * If set to false, the screen brightness dimming WILL be turned on by Battery Saver.
+ * If set to true, the screen brightness WILL NOT be turned on by Battery Saver.
+ */
private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
- private static final String KEY_DATASAVER_DISABLED = "datasaver_disabled";
+
+ /**
+ * Disable turning on Data Saver when Battery Saver is turned on.
+ * If set to false, Data Saver WILL be turned on when Battery Saver is turned on.
+ * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on.
+ */
+ private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled";
private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
@@ -82,6 +98,28 @@
private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
+ private static final Policy sDefaultPolicy = new Policy(
+ 0.5f, /* adjustBrightnessFactor */
+ true, /* deferFullBackup */
+ true, /* deferKeyValueBackup */
+ false, /* disableAnimation */
+ true, /* disableAod */
+ true, /* disableLaunchBoost */
+ true, /* disableOptionalSensors */
+ true, /* disableSoundTrigger */
+ true, /* disableVibration */
+ false, /* enableAdjustBrightness */
+ false, /* enableDataSaver */
+ true, /* enableFirewall */
+ false, /* enableQuickDoze */
+ new ArrayMap<>(), /* filesForInteractive */
+ new ArrayMap<>(), /* filesForNoninteractive */
+ true, /* forceAllAppsStandby */
+ true, /* forceBackgroundCheck */
+ PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* gpsMode */
+ false /* sendTronLog */
+ );
+
private final Object mLock;
private final Handler mHandler;
@@ -101,145 +139,20 @@
private String mEventLogKeys;
/**
- * {@code true} if vibration is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_VIBRATION_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mVibrationDisabledConfig;
-
- /**
- * Whether vibration should *really* be disabled -- i.e. {@link #mVibrationDisabledConfig}
+ * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
* is true *and* {@link #mAccessibilityEnabled} is false.
*/
@GuardedBy("mLock")
- private boolean mVibrationDisabledEffective;
+ private boolean mDisableVibrationEffective;
/**
- * {@code true} if animation is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ANIMATION_DISABLED
+ * Whether accessibility is currently enabled or not.
*/
@GuardedBy("mLock")
- private boolean mAnimationDisabled;
+ private boolean mAccessibilityEnabled;
- /**
- * {@code true} if sound trigger is disabled in battery saver mode
- * in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_SOUNDTRIGGER_DISABLED
- */
@GuardedBy("mLock")
- private boolean mSoundTriggerDisabled;
-
- /**
- * {@code true} if full backup is deferred in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_FULLBACKUP_DEFERRED
- */
- @GuardedBy("mLock")
- private boolean mFullBackupDeferred;
-
- /**
- * {@code true} if key value backup is deferred in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_KEYVALUE_DEFERRED
- */
- @GuardedBy("mLock")
- private boolean mKeyValueBackupDeferred;
-
- /**
- * {@code true} if network policy firewall is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_FIREWALL_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mFireWallDisabled;
-
- /**
- * {@code true} if adjust brightness is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mAdjustBrightnessDisabled;
-
- /**
- * {@code true} if data saver is disabled in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_DATASAVER_DISABLED
- */
- @GuardedBy("mLock")
- private boolean mDataSaverDisabled;
-
- /**
- * {@code true} if launch boost should be disabled on battery saver.
- */
- @GuardedBy("mLock")
- private boolean mLaunchBoostDisabled;
-
- /**
- * This is the flag to decide the gps mode in battery saver mode.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_GPS_MODE
- */
- @GuardedBy("mLock")
- private int mGpsMode;
-
- /**
- * This is the flag to decide the how much to adjust the screen brightness. This is
- * the float value from 0 to 1 where 1 means don't change brightness.
- *
- * @see Settings.Global#BATTERY_SAVER_CONSTANTS
- * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
- */
- @GuardedBy("mLock")
- private float mAdjustBrightnessFactor;
-
- /**
- * Whether to put all apps in the stand-by mode.
- */
- @GuardedBy("mLock")
- private boolean mForceAllAppsStandby;
-
- /**
- * Whether to put all apps in the stand-by mode.
- */
- @GuardedBy("mLock")
- private boolean mForceBackgroundCheck;
-
- /**
- * Whether to show non-essential sensors (e.g. edge sensors) or not.
- */
- @GuardedBy("mLock")
- private boolean mOptionalSensorsDisabled;
-
- /**
- * Whether AOD is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mAodDisabled;
-
- /**
- * Whether Quick Doze is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mQuickDozeEnabled;
-
- /**
- * Whether BatterySavingStats should send tron events.
- */
- @GuardedBy("mLock")
- private boolean mSendTronLog;
+ private Policy mCurrPolicy = sDefaultPolicy;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -248,30 +161,6 @@
@GuardedBy("mLock")
private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
- /**
- * List of [Filename -> content] that should be written when battery saver is activated
- * and the device is interactive.
- *
- * We use this to change the max CPU frequencies.
- */
- @GuardedBy("mLock")
- private ArrayMap<String, String> mFilesForInteractive;
-
- /**
- * List of [Filename -> content] that should be written when battery saver is activated
- * and the device is non-interactive.
- *
- * We use this to change the max CPU frequencies.
- */
- @GuardedBy("mLock")
- private ArrayMap<String, String> mFilesForNoninteractive;
-
- /**
- * Whether accessibility is enabled or not.
- */
- @GuardedBy("mLock")
- private boolean mAccessibilityEnabled;
-
public interface BatterySaverPolicyListener {
void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
}
@@ -379,36 +268,7 @@
final KeyValueListParser parser = new KeyValueListParser(',');
- // Non-device-specific parameters.
- try {
- parser.setString(setting);
- } catch (IllegalArgumentException e) {
- Slog.wtf(TAG, "Bad battery saver constants: " + setting);
- }
-
- mVibrationDisabledConfig = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
- mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, false);
- mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
- mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
- mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
- mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false);
- mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true);
- mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
- mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
- mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
- mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
- mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
- mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
- mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
- mQuickDozeEnabled = parser.getBoolean(KEY_QUICK_DOZE_ENABLED, false);
- mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
-
- // Get default value from Settings.Secure
- final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
- mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
-
- // Non-device-specific parameters.
+ // Device-specific parameters.
try {
parser.setString(deviceSpecificSetting);
} catch (IllegalArgumentException e) {
@@ -416,41 +276,280 @@
+ deviceSpecificSetting);
}
- mFilesForInteractive = (new CpuFrequencies()).parseString(
- parser.getString(KEY_CPU_FREQ_INTERACTIVE, "")).toSysFileMap();
+ final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
+ final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
- mFilesForNoninteractive = (new CpuFrequencies()).parseString(
- parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
+ // Non-device-specific parameters.
+ try {
+ parser.setString(setting);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad battery saver constants: " + setting);
+ }
+
+ float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
+ sDefaultPolicy.adjustBrightnessFactor);
+ boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
+ sDefaultPolicy.deferFullBackup);
+ boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
+ sDefaultPolicy.deferKeyValueBackup);
+ boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
+ sDefaultPolicy.disableAnimation);
+ boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, sDefaultPolicy.disableAod);
+ boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
+ sDefaultPolicy.disableLaunchBoost);
+ boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
+ sDefaultPolicy.disableOptionalSensors);
+ boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
+ sDefaultPolicy.disableSoundTrigger);
+ boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
+ sDefaultPolicy.disableVibration);
+ boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
+ !sDefaultPolicy.enableAdjustBrightness);
+ boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
+ !sDefaultPolicy.enableDataSaver);
+ boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
+ !sDefaultPolicy.enableFirewall);
+ boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
+ sDefaultPolicy.enableQuickDoze);
+ boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
+ sDefaultPolicy.forceAllAppsStandby);
+ boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
+ sDefaultPolicy.forceBackgroundCheck);
+ int gpsMode = parser.getInt(KEY_GPS_MODE, sDefaultPolicy.gpsMode);
+ boolean sendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, sDefaultPolicy.sendTronLog);
+
+ mCurrPolicy = new Policy(
+ adjustBrightnessFactor,
+ deferFullBackup,
+ deferKeyValueBackup,
+ disableAnimation,
+ disableAod,
+ disableLaunchBoost,
+ disableOptionalSensors,
+ disableSoundTrigger,
+ /* disableVibration */
+ disableVibrationConfig,
+ enableAdjustBrightness,
+ enableDataSaver,
+ enableFirewall,
+ enableQuickDoze,
+ /* filesForInteractive */
+ (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
+ /* filesForNoninteractive */
+ (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
+ forceAllAppsStandby,
+ forceBackgroundCheck,
+ gpsMode,
+ sendTronLog
+ );
// Update the effective policy.
- mVibrationDisabledEffective = mVibrationDisabledConfig
+ mDisableVibrationEffective = mCurrPolicy.disableVibration
&& !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
final StringBuilder sb = new StringBuilder();
- if (mForceAllAppsStandby) sb.append("A");
- if (mForceBackgroundCheck) sb.append("B");
+ if (mCurrPolicy.forceAllAppsStandby) sb.append("A");
+ if (mCurrPolicy.forceBackgroundCheck) sb.append("B");
- if (mVibrationDisabledEffective) sb.append("v");
- if (mAnimationDisabled) sb.append("a");
- if (mSoundTriggerDisabled) sb.append("s");
- if (mFullBackupDeferred) sb.append("F");
- if (mKeyValueBackupDeferred) sb.append("K");
- if (!mFireWallDisabled) sb.append("f");
- if (!mDataSaverDisabled) sb.append("d");
- if (!mAdjustBrightnessDisabled) sb.append("b");
+ if (mDisableVibrationEffective) sb.append("v");
+ if (mCurrPolicy.disableAnimation) sb.append("a");
+ if (mCurrPolicy.disableSoundTrigger) sb.append("s");
+ if (mCurrPolicy.deferFullBackup) sb.append("F");
+ if (mCurrPolicy.deferKeyValueBackup) sb.append("K");
+ if (mCurrPolicy.enableFirewall) sb.append("f");
+ if (mCurrPolicy.enableDataSaver) sb.append("d");
+ if (mCurrPolicy.enableAdjustBrightness) sb.append("b");
- if (mLaunchBoostDisabled) sb.append("l");
- if (mOptionalSensorsDisabled) sb.append("S");
- if (mAodDisabled) sb.append("o");
- if (mQuickDozeEnabled) sb.append("q");
- if (mSendTronLog) sb.append("t");
+ if (mCurrPolicy.disableLaunchBoost) sb.append("l");
+ if (mCurrPolicy.disableOptionalSensors) sb.append("S");
+ if (mCurrPolicy.disableAod) sb.append("o");
+ if (mCurrPolicy.enableQuickDoze) sb.append("q");
+ if (mCurrPolicy.sendTronLog) sb.append("t");
- sb.append(mGpsMode);
+ sb.append(mCurrPolicy.gpsMode);
mEventLogKeys = sb.toString();
- mBatterySavingStats.setSendTronLog(mSendTronLog);
+ mBatterySavingStats.setSendTronLog(mCurrPolicy.sendTronLog);
+ }
+
+ private static class Policy {
+ /**
+ * This is the flag to decide the how much to adjust the screen brightness. This is
+ * the float value from 0 to 1 where 1 means don't change brightness.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
+ */
+ public final float adjustBrightnessFactor;
+
+ /**
+ * {@code true} if full backup is deferred in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_FULLBACKUP_DEFERRED
+ */
+ public final boolean deferFullBackup;
+
+ /**
+ * {@code true} if key value backup is deferred in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_KEYVALUE_DEFERRED
+ */
+ public final boolean deferKeyValueBackup;
+
+ /**
+ * {@code true} if animation is disabled in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ANIMATION_DISABLED
+ */
+ public final boolean disableAnimation;
+
+ /**
+ * {@code true} if AOD is disabled in battery saver mode.
+ */
+ public final boolean disableAod;
+
+ /**
+ * {@code true} if launch boost should be disabled on battery saver.
+ */
+ public final boolean disableLaunchBoost;
+
+ /**
+ * Whether to show non-essential sensors (e.g. edge sensors) or not.
+ */
+ public final boolean disableOptionalSensors;
+
+ /**
+ * {@code true} if sound trigger is disabled in battery saver mode
+ * in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_SOUNDTRIGGER_DISABLED
+ */
+ public final boolean disableSoundTrigger;
+
+ /**
+ * {@code true} if vibration is disabled in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_VIBRATION_DISABLED
+ */
+ public final boolean disableVibration;
+
+ /**
+ * {@code true} if low power mode brightness adjustment should be turned on in battery saver
+ * mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+ */
+ public final boolean enableAdjustBrightness;
+
+ /**
+ * {@code true} if data saver should be turned on in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ACTIVATE_DATASAVER_DISABLED
+ */
+ public final boolean enableDataSaver;
+
+ /**
+ * {@code true} if network policy firewall should be turned on in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_ACTIVATE_FIREWALL_DISABLED
+ */
+ public final boolean enableFirewall;
+
+ /**
+ * Whether Quick Doze is enabled or not.
+ */
+ public final boolean enableQuickDoze;
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the device is interactive.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ public final ArrayMap<String, String> filesForInteractive;
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the device is non-interactive.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ public final ArrayMap<String, String> filesForNoninteractive;
+
+ /**
+ * Whether to put all apps in the stand-by mode.
+ */
+ public final boolean forceAllAppsStandby;
+
+ /**
+ * Whether to put all apps in the stand-by mode.
+ */
+ public final boolean forceBackgroundCheck;
+
+ /**
+ * This is the flag to decide the gps mode in battery saver mode.
+ *
+ * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+ * @see #KEY_GPS_MODE
+ */
+ public final int gpsMode;
+
+ /**
+ * Whether BatterySavingStats should send tron events.
+ */
+ public final boolean sendTronLog;
+
+ Policy(
+ float adjustBrightnessFactor,
+ boolean deferFullBackup,
+ boolean deferKeyValueBackup,
+ boolean disableAnimation,
+ boolean disableAod,
+ boolean disableLaunchBoost,
+ boolean disableOptionalSensors,
+ boolean disableSoundTrigger,
+ boolean disableVibration,
+ boolean enableAdjustBrightness,
+ boolean enableDataSaver,
+ boolean enableFirewall,
+ boolean enableQuickDoze,
+ ArrayMap<String, String> filesForInteractive,
+ ArrayMap<String, String> filesForNoninteractive,
+ boolean forceAllAppsStandby,
+ boolean forceBackgroundCheck,
+ int gpsMode,
+ boolean sendTronLog) {
+
+ this.adjustBrightnessFactor = adjustBrightnessFactor;
+ this.deferFullBackup = deferFullBackup;
+ this.deferKeyValueBackup = deferKeyValueBackup;
+ this.disableAnimation = disableAnimation;
+ this.disableAod = disableAod;
+ this.disableLaunchBoost = disableLaunchBoost;
+ this.disableOptionalSensors = disableOptionalSensors;
+ this.disableSoundTrigger = disableSoundTrigger;
+ this.disableVibration = disableVibration;
+ this.enableAdjustBrightness = enableAdjustBrightness;
+ this.enableDataSaver = enableDataSaver;
+ this.enableFirewall = enableFirewall;
+ this.enableQuickDoze = enableQuickDoze;
+ this.filesForInteractive = filesForInteractive;
+ this.filesForNoninteractive = filesForNoninteractive;
+ this.forceAllAppsStandby = forceAllAppsStandby;
+ this.forceBackgroundCheck = forceBackgroundCheck;
+ this.gpsMode = gpsMode;
+ this.sendTronLog = sendTronLog;
+ }
}
/**
@@ -473,47 +572,47 @@
switch (type) {
case ServiceType.GPS:
return builder.setBatterySaverEnabled(realMode)
- .setGpsMode(mGpsMode)
+ .setGpsMode(mCurrPolicy.gpsMode)
.build();
case ServiceType.ANIMATION:
- return builder.setBatterySaverEnabled(mAnimationDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableAnimation)
.build();
case ServiceType.FULL_BACKUP:
- return builder.setBatterySaverEnabled(mFullBackupDeferred)
+ return builder.setBatterySaverEnabled(mCurrPolicy.deferFullBackup)
.build();
case ServiceType.KEYVALUE_BACKUP:
- return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
+ return builder.setBatterySaverEnabled(mCurrPolicy.deferKeyValueBackup)
.build();
case ServiceType.NETWORK_FIREWALL:
- return builder.setBatterySaverEnabled(!mFireWallDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableFirewall)
.build();
case ServiceType.SCREEN_BRIGHTNESS:
- return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
- .setBrightnessFactor(mAdjustBrightnessFactor)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableAdjustBrightness)
+ .setBrightnessFactor(mCurrPolicy.adjustBrightnessFactor)
.build();
case ServiceType.DATA_SAVER:
- return builder.setBatterySaverEnabled(!mDataSaverDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableDataSaver)
.build();
case ServiceType.SOUND:
- return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableSoundTrigger)
.build();
case ServiceType.VIBRATION:
- return builder.setBatterySaverEnabled(mVibrationDisabledEffective)
+ return builder.setBatterySaverEnabled(mDisableVibrationEffective)
.build();
case ServiceType.FORCE_ALL_APPS_STANDBY:
- return builder.setBatterySaverEnabled(mForceAllAppsStandby)
+ return builder.setBatterySaverEnabled(mCurrPolicy.forceAllAppsStandby)
.build();
case ServiceType.FORCE_BACKGROUND_CHECK:
- return builder.setBatterySaverEnabled(mForceBackgroundCheck)
+ return builder.setBatterySaverEnabled(mCurrPolicy.forceBackgroundCheck)
.build();
case ServiceType.OPTIONAL_SENSORS:
- return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableOptionalSensors)
.build();
case ServiceType.AOD:
- return builder.setBatterySaverEnabled(mAodDisabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.disableAod)
.build();
case ServiceType.QUICK_DOZE:
- return builder.setBatterySaverEnabled(mQuickDozeEnabled)
+ return builder.setBatterySaverEnabled(mCurrPolicy.enableQuickDoze)
.build();
default:
return builder.setBatterySaverEnabled(realMode)
@@ -524,19 +623,20 @@
public int getGpsMode() {
synchronized (mLock) {
- return mGpsMode;
+ return mCurrPolicy.gpsMode;
}
}
public ArrayMap<String, String> getFileValues(boolean interactive) {
synchronized (mLock) {
- return interactive ? mFilesForInteractive : mFilesForNoninteractive;
+ return interactive ? mCurrPolicy.filesForInteractive
+ : mCurrPolicy.filesForNoninteractive;
}
}
public boolean isLaunchBoostDisabled() {
synchronized (mLock) {
- return mLaunchBoostDisabled;
+ return mCurrPolicy.disableLaunchBoost;
}
}
@@ -560,31 +660,35 @@
pw.println();
pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled);
- pw.println(" " + KEY_VIBRATION_DISABLED + ":config=" + mVibrationDisabledConfig);
- pw.println(" " + KEY_VIBRATION_DISABLED + ":effective=" + mVibrationDisabledEffective);
- pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
- pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
- pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
- pw.println(" " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
- pw.println(" " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
- pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
- pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
- pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
- pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
- pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
- pw.println(" " + KEY_AOD_DISABLED + "=" + mAodDisabled);
- pw.println(" " + KEY_QUICK_DOZE_ENABLED + "=" + mQuickDozeEnabled);
- pw.println(" " + KEY_SEND_TRON_LOG + "=" + mSendTronLog);
+ pw.println(" " + KEY_VIBRATION_DISABLED + ":config=" + mCurrPolicy.disableVibration);
+ pw.println(" " + KEY_VIBRATION_DISABLED + ":effective=" + mDisableVibrationEffective);
+ pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mCurrPolicy.disableAnimation);
+ pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mCurrPolicy.deferFullBackup);
+ pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mCurrPolicy.deferKeyValueBackup);
+ pw.println(" " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mCurrPolicy.enableFirewall);
+ pw.println(" " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mCurrPolicy.enableDataSaver);
+ pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + mCurrPolicy.disableLaunchBoost);
+ pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "="
+ + !mCurrPolicy.enableAdjustBrightness);
+ pw.println(
+ " " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mCurrPolicy.adjustBrightnessFactor);
+ pw.println(" " + KEY_GPS_MODE + "=" + mCurrPolicy.gpsMode);
+ pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mCurrPolicy.forceAllAppsStandby);
+ pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mCurrPolicy.forceBackgroundCheck);
+ pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "="
+ + mCurrPolicy.disableOptionalSensors);
+ pw.println(" " + KEY_AOD_DISABLED + "=" + mCurrPolicy.disableAod);
+ pw.println(" " + KEY_SOUNDTRIGGER_DISABLED + "=" + mCurrPolicy.disableSoundTrigger);
+ pw.println(" " + KEY_QUICK_DOZE_ENABLED + "=" + mCurrPolicy.enableQuickDoze);
+ pw.println(" " + KEY_SEND_TRON_LOG + "=" + mCurrPolicy.sendTronLog);
pw.println();
pw.print(" Interactive File values:\n");
- dumpMap(pw, " ", mFilesForInteractive);
+ dumpMap(pw, " ", mCurrPolicy.filesForInteractive);
pw.println();
pw.print(" Noninteractive File values:\n");
- dumpMap(pw, " ", mFilesForNoninteractive);
+ dumpMap(pw, " ", mCurrPolicy.filesForNoninteractive);
}
}
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index d118c4e..20e4985 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -2,3 +2,4 @@
per-file BatterySaverPolicy.java=omakoto@google.com
per-file ShutdownThread.java=fkupolov@google.com
+per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
new file mode 100644
index 0000000..812fd82
--- /dev/null
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2018 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.power;
+
+import android.content.Context;
+import android.hardware.thermal.V1_0.ThermalStatus;
+import android.hardware.thermal.V1_0.ThermalStatusCode;
+import android.hardware.thermal.V1_1.IThermalCallback;
+import android.hardware.thermal.V2_0.IThermalChangedCallback;
+import android.hardware.thermal.V2_0.ThrottlingSeverity;
+import android.os.Binder;
+import android.os.HwBinder;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * This is a system service that listens to HAL thermal events and dispatch those to listeners.
+ * <p>The service will also trigger actions based on severity of the throttling status.</p>
+ *
+ * @hide
+ */
+public class ThermalManagerService extends SystemService {
+ private static final String TAG = ThermalManagerService.class.getSimpleName();
+
+ /** Registered observers of the thermal changed events. Cookie is used to store type */
+ @GuardedBy("mLock")
+ private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners =
+ new RemoteCallbackList<>();
+
+ /** Lock to protect HAL handles and listen list. */
+ private final Object mLock = new Object();
+
+ /** Newly registered callback. */
+ @GuardedBy("mLock")
+ private IThermalEventListener mNewListenerCallback = null;
+
+ /** Newly registered callback type, null means not filter type. */
+ @GuardedBy("mLock")
+ private Integer mNewListenerType = null;
+
+ /** Local PMS handle. */
+ private final PowerManager mPowerManager;
+
+ /** Proxy object for the Thermal HAL 2.0 service. */
+ @GuardedBy("mLock")
+ private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
+
+ /** Proxy object for the Thermal HAL 1.1 service. */
+ @GuardedBy("mLock")
+ private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
+
+ /** Cookie for matching the right end point. */
+ private static final int THERMAL_HAL_DEATH_COOKIE = 5612;
+
+ /** HWbinder callback for Thermal HAL 2.0. */
+ private final IThermalChangedCallback.Stub mThermalCallback20 =
+ new IThermalChangedCallback.Stub() {
+ @Override
+ public void notifyThrottling(
+ android.hardware.thermal.V2_0.Temperature temperature) {
+ android.os.Temperature thermalSvcTemp = new android.os.Temperature(
+ temperature.value, temperature.type, temperature.name,
+ temperature.throttlingStatus);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ notifyThrottlingImpl(thermalSvcTemp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ /** HWbinder callback for Thermal HAL 1.1. */
+ private final IThermalCallback.Stub mThermalCallback11 =
+ new IThermalCallback.Stub() {
+ @Override
+ public void notifyThrottling(boolean isThrottling,
+ android.hardware.thermal.V1_0.Temperature temperature) {
+ android.os.Temperature thermalSvcTemp = new android.os.Temperature(
+ temperature.currentValue, temperature.type, temperature.name,
+ isThrottling ? ThrottlingSeverity.SEVERE : ThrottlingSeverity.NONE);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ notifyThrottlingImpl(thermalSvcTemp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ public ThermalManagerService(Context context) {
+ super(context);
+ mPowerManager = context.getSystemService(PowerManager.class);
+ }
+
+ private void setNewListener(IThermalEventListener listener, Integer type) {
+ synchronized (mLock) {
+ mNewListenerCallback = listener;
+ mNewListenerType = type;
+ }
+ }
+
+ private void clearNewListener() {
+ synchronized (mLock) {
+ mNewListenerCallback = null;
+ mNewListenerType = null;
+ }
+ }
+
+ private final IThermalService.Stub mService = new IThermalService.Stub() {
+ @Override
+ public void registerThermalEventListener(IThermalEventListener listener) {
+ synchronized (mLock) {
+ mThermalEventListeners.register(listener, null);
+ // Notify its callback after new client registered.
+ setNewListener(listener, null);
+ long token = Binder.clearCallingIdentity();
+ try {
+ notifyCurrentTemperaturesLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ clearNewListener();
+ }
+ }
+ }
+
+ @Override
+ public void registerThermalEventListenerWithType(IThermalEventListener listener, int type) {
+ synchronized (mLock) {
+ mThermalEventListeners.register(listener, new Integer(type));
+ setNewListener(listener, new Integer(type));
+ // Notify its callback after new client registered.
+ long token = Binder.clearCallingIdentity();
+ try {
+ notifyCurrentTemperaturesLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ clearNewListener();
+ }
+ }
+ }
+
+ @Override
+ public void unregisterThermalEventListener(IThermalEventListener listener) {
+ synchronized (mLock) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mThermalEventListeners.unregister(listener);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public List<android.os.Temperature> getCurrentTemperatures() {
+ List<android.os.Temperature> ret;
+ long token = Binder.clearCallingIdentity();
+ try {
+ ret = getCurrentTemperaturesInternal(false, 0 /* not used */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return ret;
+ }
+
+ @Override
+ public List<android.os.Temperature> getCurrentTemperaturesWithType(int type) {
+ List<android.os.Temperature> ret;
+ long token = Binder.clearCallingIdentity();
+ try {
+ ret = getCurrentTemperaturesInternal(true, type);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return ret;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+ pw.println("ThermalEventListeners dump:");
+ synchronized (mLock) {
+ mThermalEventListeners.dump(pw, "\t");
+ pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes" : "no"));
+ pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes" : "no"));
+ }
+ }
+ };
+
+ private List<android.os.Temperature> getCurrentTemperaturesInternal(boolean shouldFilter,
+ int type) {
+ List<android.os.Temperature> ret = new ArrayList<>();
+ synchronized (mLock) {
+ if (mThermalHal20 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal20.getCurrentTemperatures(shouldFilter, type,
+ (ThermalStatus status,
+ ArrayList<android.hardware.thermal.V2_0.Temperature>
+ temperatures) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V2_0.Temperature
+ temperature : temperatures) {
+ ret.add(new android.os.Temperature(
+ temperature.value, temperature.type, temperature.name,
+ temperature.throttlingStatus));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get temperatures because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+ connectToHalLocked();
+ // Post to listeners after reconnect to HAL.
+ notifyCurrentTemperaturesLocked();
+ }
+ }
+ return ret;
+ }
+
+ private void notifyListener(android.os.Temperature temperature, IThermalEventListener listener,
+ Integer type) {
+ // Skip if listener registered with a different type
+ if (type != null && type != temperature.getType()) {
+ return;
+ }
+ final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
+ try {
+ listener.notifyThrottling(temperature);
+ } catch (RemoteException | RuntimeException e) {
+ Slog.e(TAG, "Thermal callback failed to call", e);
+ }
+ });
+ if (!thermalCallbackQueued) {
+ Slog.e(TAG, "Thermal callback failed to queue");
+ }
+ }
+
+ private void notifyThrottlingImpl(android.os.Temperature temperature) {
+ synchronized (mLock) {
+ // Thermal Shutdown for Skin temperature
+ if (temperature.getStatus() == android.os.Temperature.THROTTLING_SHUTDOWN
+ && temperature.getType() == android.os.Temperature.TYPE_SKIN) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ if (mNewListenerCallback != null) {
+ // Only notify current newly added callback.
+ notifyListener(temperature, mNewListenerCallback, mNewListenerType);
+ } else {
+ final int length = mThermalEventListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ final IThermalEventListener listener =
+ mThermalEventListeners.getBroadcastItem(i);
+ final Integer type = (Integer) mThermalEventListeners.getBroadcastCookie(i);
+ notifyListener(temperature, listener, type);
+ }
+ } finally {
+ mThermalEventListeners.finishBroadcast();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.THERMAL_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ onActivityManagerReady();
+ }
+ }
+
+ private void notifyCurrentTemperaturesCallbackLocked(ThermalStatus status,
+ ArrayList<android.hardware.thermal.V2_0.Temperature> temperatures) {
+ if (ThermalStatusCode.SUCCESS != status.code) {
+ Slog.e(TAG, "Couldn't get temperatures because of HAL error: "
+ + status.debugMessage);
+ return;
+ }
+ for (android.hardware.thermal.V2_0.Temperature temperature : temperatures) {
+ android.os.Temperature thermal_svc_temp =
+ new android.os.Temperature(
+ temperature.value, temperature.type,
+ temperature.name,
+ temperature.throttlingStatus);
+ notifyThrottlingImpl(thermal_svc_temp);
+ }
+ }
+
+ private void notifyCurrentTemperaturesLocked() {
+ if (mThermalHal20 == null) {
+ return;
+ }
+ try {
+ mThermalHal20.getCurrentTemperatures(false, 0,
+ this::notifyCurrentTemperaturesCallbackLocked);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't get temperatures, reconnecting...", e);
+ connectToHalLocked();
+ }
+ }
+
+ private void onActivityManagerReady() {
+ synchronized (mLock) {
+ connectToHalLocked();
+ // Post to listeners after connect to HAL.
+ notifyCurrentTemperaturesLocked();
+ }
+ }
+
+ final class DeathRecipient implements HwBinder.DeathRecipient {
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == THERMAL_HAL_DEATH_COOKIE) {
+ Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
+ synchronized (mLock) {
+ connectToHalLocked();
+ // Post to listeners after reconnect to HAL.
+ notifyCurrentTemperaturesLocked();
+ }
+ }
+ }
+ }
+
+ private void connectToHalLocked() {
+ try {
+ mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+ mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
+ mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
+ 0 /* not used */);
+ } catch (NoSuchElementException | RemoteException e) {
+ Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+ mThermalHal20 = null;
+ try {
+ mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+ mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
+ mThermalHal11.registerThermalCallback(mThermalCallback11);
+ } catch (NoSuchElementException | RemoteException e2) {
+ Slog.e(TAG,
+ "Thermal HAL 1.1 service not connected, no thermal call back "
+ + "will be called.");
+ mThermalHal11 = null;
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 4d3fc1a..2be55c0 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -253,8 +253,8 @@
if (b != null) {
sThermalService = IThermalService.Stub.asInterface(b);
try {
- sThermalService.registerThermalEventListener(
- new ThermalEventListener());
+ sThermalService.registerThermalEventListenerWithType(
+ new ThermalEventListener(), Temperature.TYPE_SKIN);
Slog.i(TAG, "register thermal listener successfully");
} catch (RemoteException e) {
// Should never happen.
@@ -1853,7 +1853,8 @@
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
- public void notifyThrottling(boolean isThrottling, Temperature temp) {
+ public void notifyThrottling(Temperature temp) {
+ boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE;
StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
isThrottling ? 1 : 0, temp.getValue());
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 5fb1def..478a11a 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
@@ -51,6 +52,7 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
+import android.content.res.Configuration;
import android.graphics.Point;
import android.os.UserHandle;
import android.util.IntArray;
@@ -156,7 +158,7 @@
}
void updateBounds() {
- mDisplay.getSize(mTmpDisplaySize);
+ mDisplay.getRealSize(mTmpDisplaySize);
setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
}
@@ -938,6 +940,25 @@
return mStacks.indexOf(stack);
}
+ @Override
+ public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ final int currRotation = getOverrideConfiguration().windowConfiguration.getRotation();
+ if (currRotation != ROTATION_UNDEFINED
+ && currRotation != overrideConfiguration.windowConfiguration.getRotation()
+ && getWindowContainerController() != null) {
+ getWindowContainerController().applyRotation(currRotation,
+ overrideConfiguration.windowConfiguration.getRotation());
+ }
+ super.onOverrideConfigurationChanged(overrideConfiguration);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ // update resources before cascade so that docked/pinned stacks use the correct info
+ getWindowContainerController().preOnConfigurationChanged();
+ super.onConfigurationChanged(newParentConfig);
+ }
+
void onLockTaskPackagesUpdated() {
for (int i = mStacks.size() - 1; i >= 0; --i) {
mStacks.get(i).onLockTaskPackagesUpdated();
@@ -1010,29 +1031,50 @@
void remove() {
final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+ ActivityStack lastReparentedStack = null;
+ mPreferredTopFocusableStack = null;
// Stacks could be reparented from the removed display to other display. While
// reparenting the last stack of the removed display, the remove display is ready to be
// released (no more ActivityStack). But, we cannot release it at that moment or the
// related WindowContainer and WindowContainerController will also be removed. So, we
// set display as removed after reparenting stack finished.
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
- // Always finish non-standard type stacks.
- if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
- stack.finishAllActivitiesLocked(true /* immediately */);
- } else {
- // If default display is in split-window mode, set windowing mode of the stack to
- // split-screen secondary. Otherwise, set the windowing mode to undefined by
- // default to let stack inherited the windowing mode from the new display.
- int windowingMode = mSupervisor.getDefaultDisplay().hasSplitScreenPrimaryStack()
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_UNDEFINED;
- mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, true);
- stack.setWindowingMode(windowingMode);
+ final ActivityDisplay toDisplay = mSupervisor.getDefaultDisplay();
+ mSupervisor.beginDeferResume();
+ try {
+ int numStacks = mStacks.size();
+ // Keep the order from bottom to top.
+ for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+ final ActivityStack stack = mStacks.get(stackNdx);
+ // Always finish non-standard type stacks.
+ if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ stack.finishAllActivitiesLocked(true /* immediately */);
+ } else {
+ // If default display is in split-window mode, set windowing mode of the stack
+ // to split-screen secondary. Otherwise, set the windowing mode to undefined by
+ // default to let stack inherited the windowing mode from the new display.
+ final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_UNDEFINED;
+ stack.reparent(toDisplay, true /* onTop */, true /* displayRemoved */);
+ stack.setWindowingMode(windowingMode);
+ lastReparentedStack = stack;
+ }
+ // Stacks may be removed from this display. Ensure each stack will be processed and
+ // the loop will end.
+ stackNdx -= numStacks - mStacks.size();
+ numStacks = mStacks.size();
}
+ } finally {
+ mSupervisor.endDeferResume();
}
mRemoved = true;
+ // Only update focus/visibility for the last one because there may be many stacks are
+ // reparented and the intermediate states are unnecessary.
+ if (lastReparentedStack != null) {
+ lastReparentedStack.postReparent();
+ }
releaseSelfIfNeeded();
if (!mAllSleepTokens.isEmpty()) {
@@ -1070,7 +1112,8 @@
|| mDisplayId == mSupervisor.mService.mVr2dDisplayId;
}
- private boolean shouldDestroyContentOnRemove() {
+ @VisibleForTesting
+ boolean shouldDestroyContentOnRemove() {
return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
new file mode 100644
index 0000000..e3133ef
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 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.wm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Observe activity manager launch sequences.
+ *
+ * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface
+ * are ordered by a happens-before relation for each defined state transition (see below).
+ *
+ * When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
+ * is communicated by the {@link #onIntentStarted} callback. This is a transient state.
+ *
+ * The intent can fail to launch the activity, in which case the sequence's state transitions to
+ * {@code INTENT_FAILED} via {@link #onIntentFailed}. This is a terminal state.
+ *
+ * If an activity is successfully started, the launch sequence's state will transition into
+ * {@code STARTED} via {@link #onActivityLaunched}. This is a transient state.
+ *
+ * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled}
+ * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states.
+ *
+ * Note that the {@link ActivityRecord} provided as a parameter to some state transitions isn't
+ * necessarily the same within a single launch sequence: it is only the top-most activity at the
+ * time (if any). Trampoline activities coalesce several activity starts into a single launch
+ * sequence.
+ *
+ * Upon reaching a terminal state, it is considered that there are no active launch sequences
+ * until a subsequent transition into {@code INTENT_STARTED} initiates a new launch sequence.
+ *
+ * <pre>
+ * ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ╔══════════════════════════╗
+ * ╴╴▶ ⋮ INTENT_STARTED ⋮ ──▶ ⋮ ACTIVITY_LAUNCHED ⋮ ──▶ ║ ACTIVITY_LAUNCH_FINISHED ║
+ * └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ ╚══════════════════════════╝
+ * : :
+ * : :
+ * ▼ ▼
+ * ╔════════════════╗ ╔═══════════════════════════╗
+ * ║ INTENT_FAILED ║ ║ ACTIVITY_LAUNCH_CANCELLED ║
+ * ╚════════════════╝ ╚═══════════════════════════╝
+ * </pre>
+ */
+public interface ActivityMetricsLaunchObserver {
+ /**
+ * The 'temperature' at which a launch sequence had started.
+ *
+ * The lower the temperature the more work has to be done during start-up.
+ * A 'cold' temperature means that a new process has been started and likely
+ * nothing is cached.
+ *
+ * A hot temperature means the existing activity is brought to the foreground.
+ * It may need to regenerate some objects as a result of {@code onTrimMemory}.
+ *
+ * A warm temperature is in the middle; an existing process is used, but the activity
+ * has to be created from scratch with {@code #onCreate}.
+ *
+ * @see https://developer.android.com/topic/performance/vitals/launch-time
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TEMPERATURE_COLD,
+ TEMPERATURE_WARM,
+ TEMPERATURE_HOT
+ })
+ @interface Temperature {}
+
+ /** Cold launch sequence: a new process has started. */
+ public static final int TEMPERATURE_COLD = 1;
+ /** Warm launch sequence: process reused, but activity has to be created. */
+ public static final int TEMPERATURE_WARM = 2;
+ /** Hot launch sequence: process reused, activity brought-to-top. */
+ public static final int TEMPERATURE_HOT = 3;
+
+ /**
+ * Notifies the observer that a new launch sequence has begun as a result of a new intent.
+ *
+ * Once a launch sequence begins, the resolved activity will either subsequently start with
+ * {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
+ * a security error) with {@link #onIntentFailed}.
+ *
+ * Multiple calls to this method cannot occur without first terminating the current
+ * launch sequence.
+ */
+ public void onIntentStarted(@NonNull Intent intent);
+
+ /**
+ * Notifies the observer that the current launch sequence has failed to launch an activity.
+ *
+ * This function call terminates the current launch sequence. The next method call, if any,
+ * must be {@link #onIntentStarted}.
+ *
+ * Examples of this happening:
+ * - Failure to resolve to an activity
+ * - Calling package did not have the security permissions to call the requested activity
+ * - Resolved activity was already running and only needed to be brought to the top
+ *
+ * Multiple calls to this method cannot occur without first terminating the current
+ * launch sequence.
+ */
+ public void onIntentFailed();
+
+ /**
+ * Notifies the observer that the current launch sequence had begun starting an activity.
+ *
+ * This is an intermediate state: once an activity begins starting, the entire launch sequence
+ * will later terminate by either finishing or cancelling.
+ *
+ * The initial activity is the first activity to be started as part of a launch sequence:
+ * it is represented by {@param activity} However, it isn't
+ * necessarily the activity which will be considered as displayed when the activity
+ * finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
+ *
+ * Multiple calls to this method cannot occur without first terminating the current
+ * launch sequence.
+ */
+ public void onActivityLaunched(@NonNull ActivityRecord activity,
+ @Temperature int temperature);
+
+ /**
+ * Notifies the observer that the current launch sequence has been aborted.
+ *
+ * This function call terminates the current launch sequence. The next method call, if any,
+ * must be {@link #onIntentStarted}.
+ *
+ * This can happen for many reasons, for example the user switches away to another app
+ * prior to the launch sequence completing, or the application being killed.
+ *
+ * Multiple calls to this method cannot occur without first terminating the current
+ * launch sequence.
+ *
+ * @param abortingActivity the last activity that had the top-most window during abort
+ * (this can be {@code null} in rare situations its unknown).
+ *
+ * @apiNote The aborting activity isn't necessarily the same as the starting activity;
+ * in the case of a trampoline, multiple activities could've been started
+ * and only the latest activity is reported here.
+ */
+ public void onActivityLaunchCancelled(@Nullable ActivityRecord abortingActivity);
+
+ /**
+ * Notifies the observer that the current launch sequence has been successfully finished.
+ *
+ * This function call terminates the current launch sequence. The next method call, if any,
+ * must be {@link #onIntentStarted}.
+ *
+ * A launch sequence is considered to be successfully finished when a frame is fully
+ * drawn for the first time: the top-most activity at the time is what's reported here.
+ *
+ * @param finalActivity the top-most activity whose windows were first to fully draw
+ *
+ * Multiple calls to this method cannot occur without first terminating the current
+ * launch sequence.
+ *
+ * @apiNote The finishing activity isn't necessarily the same as the starting activity;
+ * in the case of a trampoline, multiple activities could've been started
+ * and only the latest activity that was top-most during first-frame drawn
+ * is reported here.
+ */
+ public void onActivityLaunchFinished(@NonNull ActivityRecord finalActivity);
+}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 8bde7dd..9b01dfd 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -80,6 +80,7 @@
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
+import android.app.WindowConfiguration.WindowingMode;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -141,15 +142,21 @@
private final Context mContext;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
+ // set to INVALID_START_TIME in reset.
+ // set to valid value in notifyActivityLaunching
private long mCurrentTransitionStartTime = INVALID_START_TIME;
private long mLastTransitionStartTime = INVALID_START_TIME;
private int mCurrentTransitionDeviceUptime;
private int mCurrentTransitionDelayMs;
+
+ /** If the any app transitions have been logged as starting, after the latest reset. */
private boolean mLoggedTransitionStarting;
+ /** Map : @WindowingMode int => WindowingModeTransitionInfo */
private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo =
new SparseArray<>();
+ /** Map : @WindowingMode int => WindowingModeTransitionInfo */
private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo =
new SparseArray<>();
private final H mHandler;
@@ -157,6 +164,12 @@
private ArtManagerInternal mArtManagerInternal;
private final StringBuilder mStringBuilder = new StringBuilder();
+ /**
+ * Due to the global single concurrent launch sequence, all calls to this observer must be made
+ * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
+ */
+ private final ActivityMetricsLaunchObserver mLaunchObserver = null;
+
private final class H extends Handler {
public H(Looper looper) {
@@ -175,6 +188,7 @@
}
private final class WindowingModeTransitionInfo {
+ /** The latest activity to have been launched. */
private ActivityRecord launchedActivity;
private int startResult;
private boolean currentTransitionProcessRunning;
@@ -273,7 +287,7 @@
return;
}
- int windowingMode = stack.getWindowingMode();
+ @WindowingMode int windowingMode = stack.getWindowingMode();
if (windowingMode == WINDOWING_MODE_PINNED) {
stack = mSupervisor.findStackBehind(stack);
windowingMode = stack.getWindowingMode();
@@ -301,11 +315,19 @@
* Notifies the tracker at the earliest possible point when we are starting to launch an
* activity.
*/
- void notifyActivityLaunching() {
+ void notifyActivityLaunching(Intent intent) {
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, String.format("notifyActivityLaunching: active:%b, intent:%s",
+ isAnyTransitionActive(),
+ intent));
+ }
+
if (!isAnyTransitionActive()) {
- if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
+
mCurrentTransitionStartTime = SystemClock.uptimeMillis();
mLastTransitionStartTime = mCurrentTransitionStartTime;
+
+ launchObserverNotifyIntentStarted(intent);
}
}
@@ -350,7 +372,9 @@
+ " processRunning=" + processRunning
+ " processSwitch=" + processSwitch);
- final int windowingMode = launchedActivity != null
+ // If we are already in an existing transition, only update the activity name, but not the
+ // other attributes.
+ final @WindowingMode int windowingMode = launchedActivity != null
? launchedActivity.getWindowingMode()
: WINDOWING_MODE_UNDEFINED;
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
@@ -361,13 +385,15 @@
if (launchedActivity != null && launchedActivity.nowVisible) {
// Launched activity is already visible. We cannot measure windows drawn delay.
- reset(true /* abort */, info);
+ reset(true /* abort */, info, "launched activity already visible");
return;
}
if (launchedActivity != null && info != null) {
// If we are already in an existing transition, only update the activity name, but not
// the other attributes.
+
+ // Coalesce multiple (trampoline) activities from a single sequence together.
info.launchedActivity = launchedActivity;
return;
}
@@ -377,7 +403,7 @@
if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
// Failed to launch or it was not a process switch, so we don't care about the timing.
- reset(true /* abort */, info);
+ reset(true /* abort */, info, "failed to launch or not a process switch");
return;
} else if (otherWindowModesLaunching) {
// Don't log this windowing mode but continue with the other windowing modes.
@@ -386,6 +412,8 @@
if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
+ // A new launch sequence [with the windowingMode] has begun.
+ // Start tracking it.
final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
newInfo.launchedActivity = launchedActivity;
newInfo.currentTransitionProcessRunning = processRunning;
@@ -394,6 +422,7 @@
mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);
mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
startTraces(newInfo);
+ launchObserverNotifyActivityLaunched(newInfo);
}
/**
@@ -407,7 +436,8 @@
/**
* Notifies the tracker that all windows of the app have been drawn.
*/
- WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(int windowingMode, long timestamp) {
+ WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode,
+ long timestamp) {
if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
@@ -419,7 +449,7 @@
final WindowingModeTransitionInfoSnapshot infoSnapshot =
new WindowingModeTransitionInfoSnapshot(info);
if (allWindowsDrawn() && mLoggedTransitionStarting) {
- reset(false /* abort */, info);
+ reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn");
}
return infoSnapshot;
}
@@ -427,7 +457,7 @@
/**
* Notifies the tracker that the starting window was drawn.
*/
- void notifyStartingWindowDrawn(int windowingMode, long timestamp) {
+ void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestamp) {
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (info == null || info.loggedStartingWindowDrawn) {
return;
@@ -444,22 +474,28 @@
*/
void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) {
if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
+ // Ignore calls to this made after a reset and prior to notifyActivityLaunching.
+
+ // Ignore any subsequent notifyTransitionStarting until the next reset.
return;
}
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
mCurrentTransitionDelayMs = calculateDelay(timestamp);
mLoggedTransitionStarting = true;
+
+ WindowingModeTransitionInfo foundInfo = null;
for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
- final int windowingMode = windowingModeToReason.keyAt(index);
+ final @WindowingMode int windowingMode = windowingModeToReason.keyAt(index);
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
windowingMode);
if (info == null) {
continue;
}
info.reason = windowingModeToReason.valueAt(index);
+ foundInfo = info;
}
if (allWindowsDrawn()) {
- reset(false /* abort */, null /* WindowingModeTransitionInfo */);
+ reset(false /* abort */, foundInfo, "notifyTransitionStarting - all windows drawn");
}
}
@@ -498,7 +534,7 @@
logAppTransitionCancel(info);
mWindowingModeTransitionInfo.remove(r.getWindowingMode());
if (mWindowingModeTransitionInfo.size() == 0) {
- reset(true /* abort */, info);
+ reset(true /* abort */, info, "notifyVisibilityChanged to invisible");
}
}
}
@@ -534,12 +570,25 @@
&& mWindowingModeTransitionInfo.size() > 0;
}
- private void reset(boolean abort, WindowingModeTransitionInfo info) {
- if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
+ private void reset(boolean abort, WindowingModeTransitionInfo info, String cause) {
+ if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause);
if (!abort && isAnyTransitionActive()) {
logAppTransitionMultiEvents();
}
stopLaunchTrace(info);
+
+ // Ignore reset-after reset.
+ if (isAnyTransitionActive()) {
+ // LaunchObserver callbacks.
+ if (abort) {
+ launchObserverNotifyActivityLaunchCancelled(info);
+ } else {
+ launchObserverNotifyActivityLaunchFinished(info);
+ }
+ } else {
+ launchObserverNotifyIntentFailed();
+ }
+
mCurrentTransitionStartTime = INVALID_START_TIME;
mCurrentTransitionDelayMs = INVALID_DELAY;
mLoggedTransitionStarting = false;
@@ -572,6 +621,13 @@
info.launchedActivity.packageName,
convertAppStartTransitionType(type),
info.launchedActivity.info.name);
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
+ info.launchedActivity.appInfo.uid,
+ info.launchedActivity.packageName,
+ convertAppStartTransitionType(type),
+ info.launchedActivity.info.name));
+ }
}
private void logAppTransitionMultiEvents() {
@@ -656,6 +712,17 @@
launchToken,
packageOptimizationInfo.getCompilationReason(),
packageOptimizationInfo.getCompilationFilter());
+
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
+ info.applicationInfo.uid,
+ info.packageName,
+ convertAppStartTransitionType(info.type),
+ info.launchedActivityName,
+ info.launchedActivityLaunchedFromPackage));
+ }
+
+
logAppStartMemoryStateCapture(info);
}
@@ -923,4 +990,76 @@
info.launchTraceActive = false;
}
}
+
+ /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
+ private void launchObserverNotifyIntentStarted(Intent intent) {
+ if (mLaunchObserver != null) {
+ // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+ mLaunchObserver.onIntentStarted(intent);
+ }
+ }
+
+ /**
+ * Notify the {@link ActivityMetricsLaunchObserver} that the previous launch sequence has
+ * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
+ * intent being delivered to the top running activity.
+ */
+ private void launchObserverNotifyIntentFailed() {
+ if (mLaunchObserver != null) {
+ mLaunchObserver.onIntentFailed();
+ }
+ }
+
+ /**
+ * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
+ * has started.
+ */
+ private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
+ @ActivityMetricsLaunchObserver.Temperature int temperature =
+ convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));
+
+ if (mLaunchObserver != null) {
+ // Beginning a launch is timing sensitive and so should be observed as soon as possible.
+ mLaunchObserver.onActivityLaunched(info.launchedActivity,
+ temperature);
+ }
+ }
+
+ /**
+ * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
+ * cancelled.
+ */
+ private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
+ final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null;
+
+ if (mLaunchObserver != null) {
+ mLaunchObserver.onActivityLaunchCancelled(launchedActivity);
+ }
+ }
+
+ /**
+ * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
+ * has fully finished (successfully).
+ */
+ private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) {
+ final ActivityRecord launchedActivity = info.launchedActivity;
+
+ if (mLaunchObserver != null) {
+ mLaunchObserver.onActivityLaunchFinished(launchedActivity);
+ }
+ }
+
+ private static @ActivityMetricsLaunchObserver.Temperature int
+ convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
+ switch (transitionType) {
+ case TYPE_TRANSITION_WARM_LAUNCH:
+ return ActivityMetricsLaunchObserver.TEMPERATURE_WARM;
+ case TYPE_TRANSITION_HOT_LAUNCH:
+ return ActivityMetricsLaunchObserver.TEMPERATURE_HOT;
+ case TYPE_TRANSITION_COLD_LAUNCH:
+ return ActivityMetricsLaunchObserver.TEMPERATURE_COLD;
+ default:
+ return -1;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index a8b4a9d..1944184 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -46,6 +46,13 @@
import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.am.ActivityStackProto.BOUNDS;
+import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
+import static com.android.server.am.ActivityStackProto.FULLSCREEN;
+import static com.android.server.am.ActivityStackProto.ID;
+import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityStackProto.TASKS;
import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
@@ -56,13 +63,6 @@
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.ActivityStackProto.BOUNDS;
-import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
-import static com.android.server.am.ActivityStackProto.FULLSCREEN;
-import static com.android.server.am.ActivityStackProto.ID;
-import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityStackProto.TASKS;
import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -513,14 +513,23 @@
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWindowingMode = getWindowingMode();
final boolean prevIsAlwaysOnTop = isAlwaysOnTop();
- super.onConfigurationChanged(newParentConfig);
final ActivityDisplay display = getDisplay();
+
+ getBounds(mTmpRect2);
+ final boolean hasNewBounds = display != null && getWindowContainerController() != null
+ && getWindowContainerController().updateBoundsForConfigChange(
+ newParentConfig, getConfiguration(), mTmpRect2);
+
+ super.onConfigurationChanged(newParentConfig);
if (display == null) {
return;
}
if (prevWindowingMode != getWindowingMode()) {
display.onStackWindowingModeChanged(this);
}
+ if (hasNewBounds) {
+ resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
+ }
if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
// Since always on top is only on when the stack is freeform or pinned, the state
// can be toggled when the windowing mode changes. We must make sure the stack is
@@ -729,7 +738,7 @@
}
/** Adds the stack to specified display and calls WindowManager to do the same. */
- void reparent(ActivityDisplay activityDisplay, boolean onTop) {
+ void reparent(ActivityDisplay activityDisplay, boolean onTop, boolean displayRemoved) {
// TODO: We should probably resolve the windowing mode for the stack on the new display here
// so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
removeFromDisplay();
@@ -738,6 +747,13 @@
mTmpRect2.setEmpty();
mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
+ if (!displayRemoved) {
+ postReparent();
+ }
+ }
+
+ /** Resume next focusable stack after reparenting to another display. */
+ void postReparent() {
adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
// Update visibility of activities before notifying WM. This way it won't try to resize
@@ -752,6 +768,12 @@
* @param bounds Updated bounds.
*/
private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) {
+ if (mDisplayId != activityDisplay.mDisplayId) {
+ // rotations are relative to the display, so pretend like our current rotation is
+ // the same as the new display so we don't try to rotate bounds.
+ getConfiguration().windowConfiguration.setRotation(
+ activityDisplay.getWindowConfiguration().getRotation());
+ }
mDisplayId = activityDisplay.mDisplayId;
setBounds(bounds);
onParentChanged();
@@ -810,10 +832,6 @@
outBounds.setEmpty();
}
- void getBoundsForNewConfiguration(Rect outBounds) {
- mWindowContainerController.getBoundsForNewConfiguration(outBounds);
- }
-
void positionChildWindowContainerAtTop(TaskRecord child) {
mWindowContainerController.positionChildAtTop(child.getWindowContainerController(),
true /* includingParents */);
@@ -1151,7 +1169,8 @@
}
final boolean isAttached() {
- return getParent() != null;
+ final ActivityDisplay display = getDisplay();
+ return display != null && !display.isRemoved();
}
/**
@@ -2679,136 +2698,129 @@
|| (lastFocusedStack.mLastPausedActivity != null
&& !lastFocusedStack.mLastPausedActivity.fullscreen));
- // The contained logic must be synchronized, since we are both changing the visibility
- // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
- // ultimately cause the client code to schedule a layout. Since layouts retrieve the
- // current {@link Configuration}, we must ensure that the below code updates it before
- // the layout can occur.
- synchronized(mWindowManager.getWindowManagerLock()) {
- // This activity is now becoming visible.
- if (!next.visible || next.stopped || lastActivityTranslucent) {
+ // This activity is now becoming visible.
+ if (!next.visible || next.stopped || lastActivityTranslucent) {
+ next.setVisibility(true);
+ }
+
+ // schedule launch ticks to collect information about slow apps.
+ next.startLaunchTickingLocked();
+
+ ActivityRecord lastResumedActivity =
+ lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity;
+ final ActivityState lastState = next.getState();
+
+ mService.updateCpuStats();
+
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ + " (in existing)");
+
+ next.setState(RESUMED, "resumeTopActivityInnerLocked");
+
+ next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* updateLru */, true /* activityChange */, true /* updateOomAdj */);
+ updateLRUListLocked(next);
+
+ // Have the window manager re-evaluate the orientation of
+ // the screen based on the new activity order.
+ boolean notUpdated = true;
+
+ if (isFocusedStackOnDisplay()) {
+ // We have special rotation behavior when here is some active activity that
+ // requests specific orientation or Keyguard is locked. Make sure all activity
+ // visibilities are set correctly as well as the transition is updated if needed
+ // to get the correct rotation behavior. Otherwise the following call to update
+ // the orientation may cause incorrect configurations delivered to client as a
+ // result of invisible window resize.
+ // TODO: Remove this once visibilities are set correctly immediately when
+ // starting an activity.
+ notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
+ true /* markFrozenIfConfigChanged */, false /* deferResume */);
+ }
+
+ if (notUpdated) {
+ // The configuration update wasn't able to keep the existing
+ // instance of the activity, and instead started a new one.
+ // We should be all done, but let's just make sure our activity
+ // is still at the top and schedule another run if something
+ // weird happened.
+ ActivityRecord nextNext = topRunningActivityLocked();
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
+ "Activity config changed during resume: " + next
+ + ", new next: " + nextNext);
+ if (nextNext != next) {
+ // Do over!
+ mStackSupervisor.scheduleResumeTopActivities();
+ }
+ if (!next.visible || next.stopped) {
next.setVisibility(true);
}
+ next.completeResumeLocked();
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ return true;
+ }
- // schedule launch ticks to collect information about slow apps.
- next.startLaunchTickingLocked();
-
- ActivityRecord lastResumedActivity =
- lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity;
- final ActivityState lastState = next.getState();
-
- mService.updateCpuStats();
-
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
- + " (in existing)");
-
- next.setState(RESUMED, "resumeTopActivityInnerLocked");
-
- next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* updateLru */, true /* activityChange */, true /* updateOomAdj */);
- updateLRUListLocked(next);
-
- // Have the window manager re-evaluate the orientation of
- // the screen based on the new activity order.
- boolean notUpdated = true;
-
- if (isFocusedStackOnDisplay()) {
- // We have special rotation behavior when here is some active activity that
- // requests specific orientation or Keyguard is locked. Make sure all activity
- // visibilities are set correctly as well as the transition is updated if needed
- // to get the correct rotation behavior. Otherwise the following call to update
- // the orientation may cause incorrect configurations delivered to client as a
- // result of invisible window resize.
- // TODO: Remove this once visibilities are set correctly immediately when
- // starting an activity.
- notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
- true /* markFrozenIfConfigChanged */, false /* deferResume */);
+ try {
+ final ClientTransaction transaction =
+ ClientTransaction.obtain(next.app.getThread(), next.appToken);
+ // Deliver all pending results.
+ ArrayList<ResultInfo> a = next.results;
+ if (a != null) {
+ final int N = a.size();
+ if (!next.finishing && N > 0) {
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+ "Delivering results to " + next + ": " + a);
+ transaction.addCallback(ActivityResultItem.obtain(a));
+ }
}
- if (notUpdated) {
- // The configuration update wasn't able to keep the existing
- // instance of the activity, and instead started a new one.
- // We should be all done, but let's just make sure our activity
- // is still at the top and schedule another run if something
- // weird happened.
- ActivityRecord nextNext = topRunningActivityLocked();
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
- "Activity config changed during resume: " + next
- + ", new next: " + nextNext);
- if (nextNext != next) {
- // Do over!
- mStackSupervisor.scheduleResumeTopActivities();
- }
- if (!next.visible || next.stopped) {
- next.setVisibility(true);
- }
- next.completeResumeLocked();
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- return true;
+ if (next.newIntents != null) {
+ transaction.addCallback(NewIntentItem.obtain(next.newIntents,
+ false /* andPause */));
}
- try {
- final ClientTransaction transaction =
- ClientTransaction.obtain(next.app.getThread(), next.appToken);
- // Deliver all pending results.
- ArrayList<ResultInfo> a = next.results;
- if (a != null) {
- final int N = a.size();
- if (!next.finishing && N > 0) {
- if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
- "Delivering results to " + next + ": " + a);
- transaction.addCallback(ActivityResultItem.obtain(a));
- }
- }
+ // Well the app will no longer be stopped.
+ // Clear app token stopped state in window manager if needed.
+ next.notifyAppResumed(next.stopped);
- if (next.newIntents != null) {
- transaction.addCallback(NewIntentItem.obtain(next.newIntents,
- false /* andPause */));
- }
+ EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
+ System.identityHashCode(next), next.getTask().taskId,
+ next.shortComponentName);
- // Well the app will no longer be stopped.
- // Clear app token stopped state in window manager if needed.
- next.notifyAppResumed(next.stopped);
+ next.sleeping = false;
+ mService.getAppWarningsLocked().onResumeActivity(next);
+ next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState);
+ next.clearOptionsLocked();
+ transaction.setLifecycleStateRequest(
+ ResumeActivityItem.obtain(next.app.getReportedProcState(),
+ getDisplay().getWindowContainerController()
+ .isNextTransitionForward()));
+ mService.getLifecycleManager().scheduleTransaction(transaction);
- EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
- System.identityHashCode(next), next.getTask().taskId,
- next.shortComponentName);
+ if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
+ + next);
+ } catch (Exception e) {
+ // Whoops, need to restart this activity!
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
+ + lastState + ": " + next);
+ next.setState(lastState, "resumeTopActivityInnerLocked");
- next.sleeping = false;
- mService.getAppWarningsLocked().onResumeActivity(next);
- next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState);
- next.clearOptionsLocked();
- transaction.setLifecycleStateRequest(
- ResumeActivityItem.obtain(next.app.getReportedProcState(),
- getDisplay().getWindowContainerController()
- .isNextTransitionForward()));
- mService.getLifecycleManager().scheduleTransaction(transaction);
-
- if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
- + next);
- } catch (Exception e) {
- // Whoops, need to restart this activity!
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
- + lastState + ": " + next);
- next.setState(lastState, "resumeTopActivityInnerLocked");
-
- // lastResumedActivity being non-null implies there is a lastStack present.
- if (lastResumedActivity != null) {
- lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
- }
-
- Slog.i(TAG, "Restarting because process died: " + next);
- if (!next.hasBeenLaunched) {
- next.hasBeenLaunched = true;
- } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null
- && lastFocusedStack.isTopStackOnDisplay()) {
- next.showStartingWindow(null /* prev */, false /* newTask */,
- false /* taskSwitch */);
- }
- mStackSupervisor.startSpecificActivityLocked(next, true, false);
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- return true;
+ // lastResumedActivity being non-null implies there is a lastStack present.
+ if (lastResumedActivity != null) {
+ lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
}
+
+ Slog.i(TAG, "Restarting because process died: " + next);
+ if (!next.hasBeenLaunched) {
+ next.hasBeenLaunched = true;
+ } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null
+ && lastFocusedStack.isTopStackOnDisplay()) {
+ next.showStartingWindow(null /* prev */, false /* newTask */,
+ false /* taskSwitch */);
+ }
+ mStackSupervisor.startSpecificActivityLocked(next, true, false);
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ return true;
}
// From this point on, if something goes wrong there is no way
@@ -4841,35 +4853,33 @@
mTmpBounds.clear();
mTmpInsetBounds.clear();
- synchronized (mWindowManager.getWindowManagerLock()) {
- for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
- final TaskRecord task = mTaskHistory.get(i);
- if (task.isResizeable()) {
- if (inFreeformWindowingMode()) {
- // TODO(b/71028874): Can be removed since each freeform task is its own
- // stack.
- // For freeform stack we don't adjust the size of the tasks to match that
- // of the stack, but we do try to make sure the tasks are still contained
- // with the bounds of the stack.
- if (task.getOverrideBounds() != null) {
- mTmpRect2.set(task.getOverrideBounds());
- fitWithinBounds(mTmpRect2, bounds);
- task.updateOverrideConfiguration(mTmpRect2);
- }
- } else {
- task.updateOverrideConfiguration(taskBounds, insetBounds);
+ for (int i = mTaskHistory.size() - 1; i >= 0; i--) {
+ final TaskRecord task = mTaskHistory.get(i);
+ if (task.isResizeable()) {
+ if (inFreeformWindowingMode()) {
+ // TODO(b/71028874): Can be removed since each freeform task is its own
+ // stack.
+ // For freeform stack we don't adjust the size of the tasks to match that
+ // of the stack, but we do try to make sure the tasks are still contained
+ // with the bounds of the stack.
+ if (task.getOverrideBounds() != null) {
+ mTmpRect2.set(task.getOverrideBounds());
+ fitWithinBounds(mTmpRect2, bounds);
+ task.updateOverrideConfiguration(mTmpRect2);
}
- }
-
- mTmpBounds.put(task.taskId, task.getOverrideBounds());
- if (tempTaskInsetBounds != null) {
- mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+ } else {
+ task.updateOverrideConfiguration(taskBounds, insetBounds);
}
}
- mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds);
- setBounds(bounds);
+ mTmpBounds.put(task.taskId, task.getOverrideBounds());
+ if (tempTaskInsetBounds != null) {
+ mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+ }
}
+
+ mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds);
+ setBounds(bounds);
}
void onPipAnimationEndResize() {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 77b331e..f32761e 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -59,6 +59,13 @@
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
+import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
+import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
+import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
+import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
+import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
@@ -67,13 +74,6 @@
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
-import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
-import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
-import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
-import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -789,7 +789,15 @@
return startHomeOnDisplay(mCurrentUser, myReason, displayId);
}
- boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId) {
+ /**
+ * Check if home activity start should be allowed on a display.
+ * @param homeInfo {@code ActivityInfo} of the home activity that is going to be launched.
+ * @param displayId The id of the target display.
+ * @param allowInstrumenting Whether launching home should be allowed if being instrumented.
+ * @return {@code true} if allow to launch, {@code false} otherwise.
+ */
+ boolean canStartHomeOnDisplay(ActivityInfo homeInfo, int displayId,
+ boolean allowInstrumenting) {
if (mService.mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mService.mTopAction == null) {
// We are running in factory test mode, but unable to find the factory test app, so
@@ -799,7 +807,7 @@
final WindowProcessController app =
mService.getProcessController(homeInfo.processName, homeInfo.applicationInfo.uid);
- if (app != null && app.isInstrumenting()) {
+ if (!allowInstrumenting && app != null && app.isInstrumenting()) {
// Don't do this if the home app is currently being instrumented.
return false;
}
@@ -1049,20 +1057,26 @@
boolean allResumedActivitiesIdle() {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ // TODO(b/117135575): Check resumed activities on all visible stacks.
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- // We cannot only check the top stack on each display since there might have
- // always-on-top stacks (e.g. pinned stack).
- final ActivityStack stack = display.getChildAt(stackNdx);
- if (stack.numActivities() == 0) {
- continue;
+ if (display.isSleeping()) {
+ // No resumed activities while display is sleeping.
+ continue;
+ }
+
+ // If the focused stack is not null or not empty, there should have some activities
+ // resuming or resumed. Make sure these activities are idle.
+ final ActivityStack stack = display.getFocusedStack();
+ if (stack == null || stack.numActivities() == 0) {
+ continue;
+ }
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity == null || !resumedActivity.idle) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
+ + stack.mStackId + " " + resumedActivity + " not idle");
}
- final ActivityRecord resumedActivity = stack.getResumedActivity();
- if (resumedActivity != null && !resumedActivity.idle) {
- if (DEBUG_STATES) Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack="
- + stack.mStackId + " " + resumedActivity + " not idle");
- return false;
- }
+ return false;
}
}
// Send launch end powerhint when idle
@@ -1976,8 +1990,9 @@
//Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
- // Make sure we can finish booting when all resumed activities are idle.
- if ((!mService.isBooted() && allResumedActivitiesIdle()) || fromTimeout) {
+ // Check if able to finish booting when device is booting and all resumed activities
+ // are idle.
+ if ((mService.isBooting() && allResumedActivitiesIdle()) || fromTimeout) {
booting = checkFinishBootingLocked();
}
@@ -2050,7 +2065,7 @@
}
}
- mService.mAmInternal.trimApplications();
+ mService.mH.post(() -> mService.mAmInternal.trimApplications());
//dump();
//mWindowManager.dump();
@@ -3172,7 +3187,7 @@
+ " to its current displayId=" + displayId);
}
- stack.reparent(activityDisplay, onTop);
+ stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
// TODO(multi-display): resize stacks properly if moved from split-screen.
}
@@ -4136,7 +4151,12 @@
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
getActivityDisplayOrCreateLocked(displayId);
- startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+ // Do not start home before booting, or it may accidentally finish booting before it
+ // starts. Instead, we expect home activities to be launched when the system is ready
+ // (ActivityManagerService#systemReady).
+ if (mService.isBooted() || mService.isBooting()) {
+ startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+ }
}
}
@@ -4234,7 +4254,7 @@
return false;
}
- if (!canStartHomeOnDisplay(aInfo, displayId)) {
+ if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
return false;
}
@@ -4562,14 +4582,14 @@
/**
* Begin deferring resume to avoid duplicate resumes in one pass.
*/
- private void beginDeferResume() {
+ void beginDeferResume() {
mDeferResumeCount++;
}
/**
* End deferring resume and determine if resume can be called.
*/
- private void endDeferResume() {
+ void endDeferResume() {
mDeferResumeCount--;
}
@@ -4745,7 +4765,7 @@
final ActivityRecord targetActivity = task.getTopActivity();
sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity);
- mActivityMetricsLogger.notifyActivityLaunching();
+ mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(task.taskId, 0, options,
true /* fromRecents */);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e43a79a..83db8de 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -53,6 +53,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -72,7 +73,6 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
@@ -114,9 +114,9 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.InstantAppResolver;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.wm.LaunchParamsController.LaunchParams;
-import com.android.server.pm.InstantAppResolver;
import java.io.PrintWriter;
import java.text.DateFormat;
@@ -996,7 +996,7 @@
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
boolean componentSpecified = intent.getComponent() != null;
final int realCallingPid = Binder.getCallingPid();
@@ -1284,8 +1284,8 @@
// Do not start home activity if it cannot be launched on preferred display. We are not
// doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
// fallback to launch on other displays.
- if (r.isActivityTypeHome()
- && !mSupervisor.canStartHomeOnDisplay(r.info, mPreferredDisplayId)) {
+ if (r.isActivityTypeHome() && !mSupervisor.canStartHomeOnDisplay(r.info,
+ mPreferredDisplayId, true /* allowInstrumenting */)) {
Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId);
return START_CANCELED;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index dcc7bc5..d665592 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -22,6 +22,7 @@
import android.app.AppProtoEnums;
import android.app.IActivityManager;
import android.app.IApplicationThread;
+import android.app.ProfilerInfo;
import android.content.ComponentName;
import android.content.IIntentSender;
import android.content.Intent;
@@ -468,4 +469,8 @@
public abstract void clearLockedTasks(String reason);
public abstract void updateUserConfiguration();
public abstract boolean canShowErrorDialogs();
+
+ public abstract void setProfileApp(String profileApp);
+ public abstract void setProfileProc(WindowProcessController wpc);
+ public abstract void setProfilerInfo(ProfilerInfo profilerInfo);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3ede8bc8..89193f7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -114,17 +114,17 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
-import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
+import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import android.Manifest;
import android.annotation.NonNull;
@@ -190,7 +190,6 @@
import android.os.IBinder;
import android.os.IUserManager;
import android.os.LocaleList;
-import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
@@ -247,9 +246,11 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
+import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
+import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
@@ -347,7 +348,7 @@
IntentFirewall mIntentFirewall;
/* Global service lock used by the package the owns this service. */
- Object mGlobalLock;
+ final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
ActivityStackSupervisor mStackSupervisor;
WindowManagerService mWindowManager;
private UserManagerService mUserManager;
@@ -466,6 +467,11 @@
String mTopAction = Intent.ACTION_MAIN;
String mTopData;
+ /** Profiling app information. */
+ String mProfileApp = null;
+ WindowProcessController mProfileProc = null;
+ ProfilerInfo mProfilerInfo = null;
+
/**
* Dump of the activity state at the time of the last ANR. Cleared after
* {@link WindowManagerService#LAST_ANR_LIFETIME_DURATION_MSECS}
@@ -716,11 +722,13 @@
}
}
- // TODO: Will be converted to WM lock once transition is complete.
- public void setActivityManagerService(Object globalLock, Looper looper,
- IntentFirewall intentFirewall, PendingIntentController intentController) {
- mGlobalLock = globalLock;
- mH = new H(looper);
+ public WindowManagerGlobalLock getGlobalLock() {
+ return mGlobalLock;
+ }
+
+ public void setActivityManagerService(IntentFirewall intentFirewall,
+ PendingIntentController intentController) {
+ mH = new H();
mUiHandler = new UiHandler();
mIntentFirewall = intentFirewall;
final File systemDir = SystemServiceManager.ensureSystemDir();
@@ -2885,7 +2893,7 @@
@Override
public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
- int secondaryDisplayShowing) {
+ int[] secondaryDisplaysShowing) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
@@ -2903,7 +2911,7 @@
}
try {
mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
- secondaryDisplayShowing);
+ secondaryDisplaysShowing);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4873,21 +4881,6 @@
mH.sendMessage(msg);
}
}
-
- // Update the configuration with WM first and check if any of the stacks need to be resized
- // due to the configuration change. If so, resize the stacks now and do any relaunches if
- // necessary. This way we don't need to relaunch again afterwards in
- // ensureActivityConfiguration().
- if (mWindowManager != null) {
- final int[] resizedStacks =
- mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
- if (resizedStacks != null) {
- for (int stackId : resizedStacks) {
- resizeStackWithBoundsFromWindowManager(stackId, deferResume);
- }
- }
- }
-
return changes;
}
@@ -5277,28 +5270,6 @@
return "focused app: " + packageName;
}
- /** Helper method that requests bounds from WM and applies them to stack. */
- private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
- final Rect newStackBounds = new Rect();
- final ActivityStack stack = mStackSupervisor.getStack(stackId);
-
- // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
- if (stack == null) {
- final StringWriter writer = new StringWriter();
- final PrintWriter printWriter = new PrintWriter(writer);
- mStackSupervisor.dumpDisplays(printWriter);
- printWriter.flush();
-
- Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
- }
-
- stack.getBoundsForNewConfiguration(newStackBounds);
- mStackSupervisor.resizeStackLocked(
- stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
- }
-
/** Applies latest configuration and/or visibility updates if needed. */
private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
boolean kept = true;
@@ -5487,8 +5458,8 @@
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_SUPERVISOR_STACK_MSG = 200;
- public H(Looper looper) {
- super(looper, null, true);
+ public H() {
+ super(DisplayThread.get().getLooper());
}
@Override
@@ -5506,7 +5477,7 @@
static final int DISMISS_DIALOG_UI_MSG = 1;
public UiHandler() {
- super(com.android.server.UiThread.get().getLooper(), null, true);
+ super(UiThread.get().getLooper(), null, true);
}
@Override
@@ -6762,5 +6733,26 @@
&& mAmInternal.getCurrentUser().isDemo());
}
}
+
+ @Override
+ public void setProfileApp(String profileApp) {
+ synchronized (mGlobalLock) {
+ mProfileApp = profileApp;
+ }
+ }
+
+ @Override
+ public void setProfileProc(WindowProcessController wpc) {
+ synchronized (mGlobalLock) {
+ mProfileProc = wpc;
+ }
+ }
+
+ @Override
+ public void setProfilerInfo(ProfilerInfo profilerInfo) {
+ synchronized (mGlobalLock) {
+ mProfilerInfo = profilerInfo;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 584c1e4..830c2e6 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_NONE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
@@ -27,9 +28,9 @@
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_UNSET;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -862,6 +863,8 @@
displayContent.mAppTransition.overridePendingAppTransitionRemote(
pendingOptions.getRemoteAnimationAdapter());
break;
+ case ANIM_NONE:
+ break;
default:
Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
break;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 348b2af..fece980 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -157,8 +157,8 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.view.WindowManager;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
@@ -1153,14 +1153,19 @@
}
/**
- * Update rotation of the display with an option to force the update.
+ * Update rotation of the DisplayContent with an option to force the update. This updates
+ * the container's perception of rotation and, depending on the top activities, will freeze
+ * the screen or start seamless rotation. The display itself gets rotated in
+ * {@link #applyRotationLocked} during {@link WindowManagerService#sendNewConfiguration}.
+ *
* @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
* orientation because we're waiting for some rotation to finish or display
* to unfreeze, which results in configuration of the previously visible
* activity being applied to a newly visible one. Forcing the rotation
* update allows to workaround this issue.
* @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
- * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
+ * {@link WindowManagerService#sendNewConfiguration(int)} TO COMPLETE THE ROTATION AND
+ * UNFREEZE THE SCREEN.
*/
boolean updateRotationUnchecked(boolean forceUpdate) {
ScreenRotationAnimation screenRotationAnimation;
@@ -1258,7 +1263,7 @@
mService.mWaitingForConfig = true;
}
- setRotation(rotation);
+ mRotation = rotation;
mAltOrientation = altOrientation;
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
@@ -1272,18 +1277,29 @@
if (!rotateSeamlessly) {
mService.startFreezingDisplayLocked(anim[0], anim[1], this);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
- screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
- mDisplayId);
} else {
// The screen rotation animation uses a screenshot to freeze the screen
// while windows resize underneath.
// When we are rotating seamlessly, we allow the elements to transition
// to their rotated state independently and without a freeze required.
- screenRotationAnimation = null;
-
mService.startSeamlessRotation();
}
+ return true;
+ }
+
+ /**
+ * Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
+ * (if it returned {@code true}) to actually finish the rotation.
+ *
+ * @param oldRotation the rotation we are coming from.
+ * @param rotation the rotation to apply.
+ */
+ void applyRotationLocked(final int oldRotation, final int rotation) {
+ mDisplayRotation.setRotation(rotation);
+ final boolean rotateSeamlessly = mService.isRotatingSeamlessly();
+ ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
+ ? null : mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
// We need to update our screen size information to match the new rotation. If the rotation
// has actually changed then this method will return true and, according to the comment at
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
@@ -1344,8 +1360,6 @@
&& isDefaultDisplay) {
mService.mAccessibilityController.onRotationChangedLocked(this);
}
-
- return true;
}
void configureDisplayPolicy() {
@@ -1455,7 +1469,6 @@
mCompatDisplayMetrics);
}
- updateBounds();
return mDisplayInfo;
}
@@ -1489,11 +1502,14 @@
*/
void computeScreenConfiguration(Configuration config) {
final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode);
+ calculateBounds(displayInfo, mTmpBounds);
+ config.windowConfiguration.setBounds(mTmpBounds);
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
config.windowConfiguration.setWindowingMode(getWindowingMode());
+ config.windowConfiguration.setRotation(displayInfo.rotation);
final float density = mDisplayMetrics.density;
config.screenWidthDp =
@@ -1525,7 +1541,7 @@
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
- dh, mDisplayId);
+ dh, displayInfo.displayCutout, mDisplayId);
config.densityDpi = displayInfo.logicalDensityDpi;
config.colorMode =
@@ -1602,7 +1618,7 @@
}
private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
- int displayId) {
+ DisplayCutout displayCutout, int displayId) {
mTmpDisplayMetrics.setTo(mDisplayMetrics);
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
final int unrotDw, unrotDh;
@@ -1614,22 +1630,22 @@
unrotDh = dh;
}
int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
- displayId);
+ displayCutout, displayId);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
- displayId);
+ displayCutout, displayId);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
- displayId);
+ displayCutout, displayId);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
- displayId);
+ displayCutout, displayId);
return sw;
}
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
- DisplayMetrics dm, int dw, int dh, int displayId) {
+ DisplayMetrics dm, int dw, int dh, DisplayCutout displayCutout, int displayId) {
dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
- displayId, mDisplayInfo.displayCutout);
+ displayId, displayCutout);
dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
- uiMode, displayId, mDisplayInfo.displayCutout);
+ uiMode, displayId, displayCutout);
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
if (curSize == 0 || size < curSize) {
@@ -1667,24 +1683,24 @@
unrotDw);
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
- displayId);
+ displayInfo.displayCutout, displayId);
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
- displayId);
+ displayInfo.displayCutout, displayId);
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
- displayId);
+ displayInfo.displayCutout, displayId);
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
- displayId);
+ displayInfo.displayCutout, displayId);
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
outConfig.screenLayout = sl;
}
private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
- int uiMode, int displayId) {
+ int uiMode, DisplayCutout displayCutout, int displayId) {
// Get the app screen size at this rotation.
int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId,
- mDisplayInfo.displayCutout);
+ displayCutout);
int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId,
- mDisplayInfo.displayCutout);
+ displayCutout);
// Compute the screen layout size class for this rotation.
int longSize = w;
@@ -1858,11 +1874,26 @@
public void onConfigurationChanged(Configuration newParentConfig) {
super.onConfigurationChanged(newParentConfig);
+ // If there was no pinned stack, we still need to notify the controller of the display info
+ // update as a result of the config change.
+ if (mPinnedStackControllerLocked != null && !hasPinnedStack()) {
+ mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo());
+ }
+
// The display size information is heavily dependent on the resources in the current
// configuration, so we need to reconfigure it every time the configuration changes.
// See {@link #configureDisplayPolicy}...sigh...
mService.reconfigureDisplayLocked(this);
+ }
+
+ /**
+ * Updates the resources used by docked/pinned controllers. This needs to be called at the
+ * beginning of a configuration update cascade since the metrics from these resources are used
+ * for bounds calculations. Since ActivityDisplay initiates the configuration update, this
+ * should be called from there instead of DisplayContent's onConfigurationChanged.
+ */
+ void preOnConfigurationChanged() {
final DockedStackDividerController dividerController = getDockedDividerController();
if (dividerController != null) {
@@ -1876,26 +1907,6 @@
}
}
- /**
- * Callback used to trigger bounds update after configuration change and get ids of stacks whose
- * bounds were updated.
- */
- void updateStackBoundsAfterConfigChange(@NonNull List<TaskStack> changedStackList) {
- for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
- final TaskStack stack = mTaskStackContainers.getChildAt(i);
- if (stack.updateBoundsAfterConfigChange()) {
- changedStackList.add(stack);
- }
- }
-
- // If there was no pinned stack, we still need to notify the controller of the display info
- // update as a result of the config change. We do this here to consolidate the flow between
- // changes when there is and is not a stack.
- if (!hasPinnedStack()) {
- mPinnedStackControllerLocked.onDisplayInfoChanged();
- }
- }
-
@Override
boolean fillsParent() {
return true;
@@ -2494,11 +2505,15 @@
void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
getBounds(mTmpRect, newRotation);
+ rotateBounds(mTmpRect, oldRotation, newRotation, bounds);
+ }
+ void rotateBounds(Rect parentBounds, int oldRotation, int newRotation, Rect bounds) {
// Compute a transform matrix to undo the coordinate space transformation,
// and present the window at the same physical position it previously occupied.
final int deltaRotation = deltaRotation(newRotation, oldRotation);
- createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
+ createRotationMatrix(
+ deltaRotation, parentBounds.width(), parentBounds.height(), mTmpMatrix);
mTmpRectF.set(bounds);
mTmpMatrix.mapRect(mTmpRectF);
@@ -3426,27 +3441,27 @@
}
private void updateBounds() {
- calculateBounds(mTmpBounds);
+ calculateBounds(mDisplayInfo, mTmpBounds);
setBounds(mTmpBounds);
}
// Determines the current display bounds based on the current state
- private void calculateBounds(Rect out) {
+ private void calculateBounds(DisplayInfo displayInfo, Rect out) {
// Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
- final int orientation = mDisplayInfo.rotation;
- boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
+ final int rotation = displayInfo.rotation;
+ boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
- int width = mDisplayInfo.logicalWidth;
+ int width = displayInfo.logicalWidth;
int left = (physWidth - width) / 2;
- int height = mDisplayInfo.logicalHeight;
+ int height = displayInfo.logicalHeight;
int top = (physHeight - height) / 2;
out.set(left, top, left + width, top + height);
}
@Override
public void getBounds(Rect out) {
- calculateBounds(out);
+ calculateBounds(mDisplayInfo, out);
}
private void getBounds(Rect out, int orientation) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index f772216..632494b 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -88,9 +88,34 @@
@Override
public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
- // TODO: The container receives override configuration changes through other means. enabling
- // callbacks through the controller causes layout issues. Investigate consolidating
- // override configuration propagation to just here.
+ synchronized (mGlobalLock) {
+ if (mContainer != null) {
+ mContainer.mService.setNewDisplayOverrideConfiguration(overrideConfiguration,
+ mContainer);
+ }
+ }
+ }
+
+ /**
+ * Updates the docked/pinned controller resources to the current system context.
+ */
+ public void preOnConfigurationChanged() {
+ synchronized (mGlobalLock) {
+ if (mContainer != null) {
+ mContainer.preOnConfigurationChanged();
+ }
+ }
+ }
+
+ /**
+ * @see DisplayContent#applyRotationLocked(int, int)
+ */
+ public void applyRotation(int oldRotation, int newRotation) {
+ synchronized (mGlobalLock) {
+ if (mContainer != null) {
+ mContainer.applyRotationLocked(oldRotation, newRotation);
+ }
+ }
}
public int getDisplayId() {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 985ce06..6daf2f5 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -171,7 +171,7 @@
final int orientation = mTmpRect2.width() <= mTmpRect2.height()
? ORIENTATION_PORTRAIT
: ORIENTATION_LANDSCAPE;
- final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
+ final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation);
final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
getContentWidth());
@@ -202,7 +202,7 @@
* @param orientation the origination of device
* @return current docked side
*/
- int getDockSide(Rect bounds, Rect displayRect, int orientation) {
+ int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
// Portrait mode, docked either at the top or the bottom.
final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
@@ -211,7 +211,8 @@
} else if (diff < 0) {
return DOCKED_BOTTOM;
}
- return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
+ return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation)
+ ? DOCKED_TOP : DOCKED_BOTTOM;
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Landscape mode, docked either on the left or on the right.
final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
@@ -220,7 +221,8 @@
} else if (diff < 0) {
return DOCKED_RIGHT;
}
- return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
+ return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation)
+ ? DOCKED_LEFT : DOCKED_RIGHT;
}
return DOCKED_INVALID;
}
@@ -463,10 +465,9 @@
* @param dockSide the side to see if it is valid
* @return true if the side provided is valid
*/
- boolean canPrimaryStackDockTo(int dockSide) {
- final DisplayInfo di = mDisplayContent.getDisplayInfo();
- return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
- di.logicalHeight, di.rotation);
+ boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
+ return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide,
+ parentRect.width(), parentRect.height(), rotation);
}
void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 3560635..c91af73 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -18,7 +18,6 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -30,13 +29,13 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.os.IBinder;
import android.os.RemoteException;
@@ -50,6 +49,7 @@
import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -67,10 +67,9 @@
private boolean mAodShowing;
private boolean mKeyguardGoingAway;
private boolean mDismissalRequested;
+ private int[] mSecondaryDisplayIdsShowing;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
- // TODO(b/111955725): Support multiple external displays
- private int mSecondaryDisplayShowing = INVALID_DISPLAY;
private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>();
private final ActivityTaskManagerService mService;
@@ -90,7 +89,9 @@
*/
boolean isKeyguardOrAodShowing(int displayId) {
return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
- && !isDisplayOccluded(displayId);
+ && (displayId == DEFAULT_DISPLAY
+ ? !isDisplayOccluded(DEFAULT_DISPLAY)
+ : isShowingOnSecondaryDisplay(displayId));
}
/**
@@ -98,7 +99,10 @@
* display, false otherwise
*/
boolean isKeyguardShowing(int displayId) {
- return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
+ return mKeyguardShowing && !mKeyguardGoingAway
+ && (displayId == DEFAULT_DISPLAY
+ ? !isDisplayOccluded(DEFAULT_DISPLAY)
+ : isShowingOnSecondaryDisplay(displayId));
}
/**
@@ -120,16 +124,17 @@
* Update the Keyguard showing state.
*/
void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
- int secondaryDisplayShowing) {
+ int[] secondaryDisplaysShowing) {
boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
// If keyguard is going away, but SystemUI aborted the transition, need to reset state.
showingChanged |= mKeyguardGoingAway && keyguardShowing;
- if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) {
+ if (!showingChanged && Arrays.equals(secondaryDisplaysShowing,
+ mSecondaryDisplayIdsShowing)) {
return;
}
mKeyguardShowing = keyguardShowing;
mAodShowing = aodShowing;
- mSecondaryDisplayShowing = secondaryDisplayShowing;
+ mSecondaryDisplayIdsShowing = secondaryDisplaysShowing;
mWindowManager.setAodShowing(aodShowing);
if (showingChanged) {
dismissDockedStackIfNeeded();
@@ -145,6 +150,14 @@
updateKeyguardSleepToken();
}
+ private boolean isShowingOnSecondaryDisplay(int displayId) {
+ if (mSecondaryDisplayIdsShowing == null) return false;
+ for (int showingId : mSecondaryDisplayIdsShowing) {
+ if (displayId == showingId) return true;
+ }
+ return false;
+ }
+
/**
* Called when Keyguard is going away.
*
@@ -386,16 +399,18 @@
}
private KeyguardDisplayState getDisplay(int displayId) {
- if (mDisplayStates.get(displayId) == null) {
- mDisplayStates.append(displayId,
- new KeyguardDisplayState(mService, displayId));
+ KeyguardDisplayState state = mDisplayStates.get(displayId);
+ if (state == null) {
+ state = new KeyguardDisplayState(mService, displayId);
+ mDisplayStates.append(displayId, state);
}
- return mDisplayStates.get(displayId);
+ return state;
}
void onDisplayRemoved(int displayId) {
- if (mDisplayStates.get(displayId) != null) {
- mDisplayStates.get(displayId).onRemoved();
+ final KeyguardDisplayState state = mDisplayStates.get(displayId);
+ if (state != null) {
+ state.onRemoved();
mDisplayStates.remove(displayId);
}
}
@@ -456,7 +471,8 @@
mOccluded |= controller.mWindowManager.isShowingDream();
}
- // TODO(b/113840485): Handle app transition for individual display.
+ // TODO(b/113840485): Handle app transition for individual display, and apply occluded
+ // state change to secondary displays.
// For now, only default display can change occluded.
if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
controller.handleOccludedChanged();
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 405aaab..d21f67d9 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -314,8 +314,8 @@
* onTaskStackBoundsChanged() to be called. But we still should update our known display info
* with the new state so that we can update SystemUI.
*/
- synchronized void onDisplayInfoChanged() {
- mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
+ synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) {
+ mDisplayInfo.copyFrom(displayInfo);
notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 7a1ebf2..067b01a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -42,7 +42,6 @@
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
-import com.android.server.wm.AssistDataReceiverProxy;
import com.android.server.am.AssistDataRequester;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
@@ -122,9 +121,9 @@
targetActivity);
}
- mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
- mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true);
+ mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));
mWindowManager.deferSurfaceLayout();
try {
@@ -234,7 +233,8 @@
mStackSupervisor.sendPowerHintForLaunchEndIfNeeded();
}
- mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false);
+ mService.mH.post(
+ () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false));
mWindowManager.inSurfaceTransaction(() -> {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 67fe5c4..8c0c073 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -54,6 +54,7 @@
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
import android.content.res.Configuration;
import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
@@ -75,12 +76,10 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.internal.util.ArrayUtils;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.function.Consumer;
/** Root {@link WindowContainer} for the device. */
@@ -115,9 +114,6 @@
boolean mOrientationChangeComplete = true;
boolean mWallpaperActionPending = false;
- private final ArrayList<TaskStack> mTmpStackList = new ArrayList();
- private final ArrayList<Integer> mTmpStackIds = new ArrayList<>();
-
final WallpaperController mWallpaperController;
private final Handler mHandler;
@@ -313,57 +309,33 @@
}
/**
- * Set new display override config and return array of ids of stacks that were changed during
- * update. If called for the default display, global configuration will also be updated. Stacks
- * that are marked for deferred removal are excluded from the returned array.
+ * Set new display override config. If called for the default display, global configuration
+ * will also be updated.
*/
- int[] setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration, int displayId) {
- final DisplayContent displayContent = getDisplayContent(displayId);
- if (displayContent == null) {
- throw new IllegalArgumentException("Display not found for id: " + displayId);
- }
+ void setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration,
+ @NonNull DisplayContent displayContent) {
final Configuration currentConfig = displayContent.getOverrideConfiguration();
final boolean configChanged = currentConfig.diff(newConfiguration) != 0;
if (!configChanged) {
- return null;
+ return;
}
displayContent.onOverrideConfigurationChanged(newConfiguration);
- mTmpStackList.clear();
- if (displayId == DEFAULT_DISPLAY) {
+ if (displayContent.getDisplayId() == DEFAULT_DISPLAY) {
// Override configuration of the default display duplicates global config. In this case
// we also want to update the global config.
- setGlobalConfigurationIfNeeded(newConfiguration, mTmpStackList);
- } else {
- updateStackBoundsAfterConfigChange(displayId, mTmpStackList);
+ setGlobalConfigurationIfNeeded(newConfiguration);
}
-
- mTmpStackIds.clear();
- final int stackCount = mTmpStackList.size();
-
- for (int i = 0; i < stackCount; ++i) {
- final TaskStack stack = mTmpStackList.get(i);
-
- // We only include stacks that are not marked for removal as they do not exist outside
- // of WindowManager at this point.
- if (!stack.mDeferRemoval) {
- mTmpStackIds.add(stack.mStackId);
- }
- }
-
- return mTmpStackIds.isEmpty() ? null : ArrayUtils.convertToIntArray(mTmpStackIds);
}
- private void setGlobalConfigurationIfNeeded(Configuration newConfiguration,
- List<TaskStack> changedStacks) {
+ private void setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
if (!configChanged) {
return;
}
onConfigurationChanged(newConfiguration);
- updateStackBoundsAfterConfigChange(changedStacks);
}
@Override
@@ -374,24 +346,6 @@
forAllDisplays(mDisplayContentConfigChangesConsumer);
}
- /**
- * Callback used to trigger bounds update after configuration change and get ids of stacks whose
- * bounds were updated.
- */
- private void updateStackBoundsAfterConfigChange(List<TaskStack> changedStacks) {
- final int numDisplays = mChildren.size();
- for (int i = 0; i < numDisplays; ++i) {
- final DisplayContent dc = mChildren.get(i);
- dc.updateStackBoundsAfterConfigChange(changedStacks);
- }
- }
-
- /** Same as {@link #updateStackBoundsAfterConfigChange()} but only for a specific display. */
- private void updateStackBoundsAfterConfigChange(int displayId, List<TaskStack> changedStacks) {
- final DisplayContent dc = getDisplayContent(displayId);
- dc.updateStackBoundsAfterConfigChange(changedStacks);
- }
-
private void prepareFreezingTaskBounds() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).prepareFreezingTaskBounds();
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c920b9e..d8e1ebf 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -245,12 +245,6 @@
}
}
- public void getBoundsForNewConfiguration(Rect outBounds) {
- synchronized (mGlobalLock) {
- mContainer.getBoundsForNewConfiguration(outBounds);
- }
- }
-
/**
* Adjusts the screen size in dp's for the {@param config} for the given params. The provided
* params represent the desired state of a configuration change. Since this utility is used
@@ -378,6 +372,14 @@
mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
}
+ /** @see TaskStack.updateBoundsForConfigChange(Configuration, Configuration, Rect) */
+ public boolean updateBoundsForConfigChange(
+ Configuration parentConfig, Configuration prevConfig, Rect outBounds) {
+ synchronized (mGlobalLock) {
+ return mContainer.updateBoundsForConfigChange(parentConfig, prevConfig, outBounds);
+ }
+ }
+
@Override
public String toString() {
return "{StackWindowController stackId=" + mStackId + "}";
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3f394a2..30eca89 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -290,12 +290,7 @@
if (displayContent != null) {
rotation = displayContent.getDisplayInfo().rotation;
} else if (bounds == null) {
- // Can't set to fullscreen if we don't have a display to get bounds from...
- return BOUNDS_CHANGE_NONE;
- }
-
- if (equivalentOverrideBounds(bounds)) {
- return BOUNDS_CHANGE_NONE;
+ return super.setBounds(bounds);
}
final int boundsChange = super.setBounds(bounds);
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index d697f28..d4acb18 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -1960,7 +1960,7 @@
info.stackId = getStackId();
info.taskId = taskId;
info.isRunning = getTopActivity() != null;
- info.baseIntent = getBaseIntent();
+ info.baseIntent = new Intent(getBaseIntent());
info.baseActivity = reuseActivitiesReport.base != null
? reuseActivitiesReport.base.intent.getComponent()
: null;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0d98b20..4dc2b8e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -23,6 +23,9 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -61,6 +64,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -143,10 +147,6 @@
private Rect mBoundsAnimationTarget = new Rect();
private Rect mBoundsAnimationSourceHintBounds = new Rect();
- // Temporary storage for the new bounds that should be used after the configuration change.
- // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
- private final Rect mBoundsAfterRotation = new Rect();
-
Rect mPreAnimationBounds = new Rect();
private Dimmer mDimmer = new Dimmer(this);
@@ -292,8 +292,9 @@
private int setBounds(Rect existing, Rect bounds) {
int rotation = Surface.ROTATION_0;
int density = DENSITY_DPI_UNDEFINED;
- if (mDisplayContent != null) {
- mDisplayContent.getBounds(mTmpRect);
+ WindowContainer parent = getParent();
+ if (parent != null) {
+ parent.getBounds(mTmpRect);
rotation = mDisplayContent.getDisplayInfo().rotation;
density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
}
@@ -443,20 +444,33 @@
// If the rotation or density didn't match, we'll update it in onConfigurationChanged.
}
- /** @return true if bounds were updated to some non-empty value. */
- boolean updateBoundsAfterConfigChange() {
- if (mDisplayContent == null) {
- // If the stack is already detached we're not updating anything,
- // as it's going away soon anyway.
- return false;
- }
-
- if (inPinnedWindowingMode()) {
- getAnimationOrCurrentBounds(mTmpRect2);
+ /**
+ * Updates the passed-in {@code inOutBounds} based on how it would change when this container's
+ * override configuration is applied to the specified {@code parentConfig} and
+ * {@code prevConfig}. This gets run *after* the override configuration is updated, so it's
+ * safe to rely on wm hierarchy state in here (though eventually this dependence should be
+ * removed).
+ *
+ * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
+ * update various controller state (pinned/docked).
+ *
+ * @param parentConfig a parent configuration to compute relative to.
+ * @param prevConfig the full configuration used to produce the incoming {@code inOutBounds}.
+ * @param inOutBounds the bounds to update (both input and output).
+ * @return true if bounds were updated to some non-empty value. */
+ boolean updateBoundsForConfigChange(
+ Configuration parentConfig, Configuration prevConfig, Rect inOutBounds) {
+ if (getOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
+ if ((mBoundsAnimatingRequested || mBoundsAnimating)
+ && !mBoundsAnimationTarget.isEmpty()) {
+ getFinalAnimationBounds(mTmpRect2);
+ } else {
+ mTmpRect2.set(prevConfig.windowConfiguration.getBounds());
+ }
boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
mTmpRect2, mTmpRect3);
if (updated) {
- mBoundsAfterRotation.set(mTmpRect3);
+ inOutBounds.set(mTmpRect3);
// Once we've set the bounds based on the rotation of the old bounds in the new
// orientation, clear the animation target bounds since they are obsolete, and
@@ -464,72 +478,75 @@
mBoundsAnimationTarget.setEmpty();
mBoundsAnimationSourceHintBounds.setEmpty();
mCancelCurrentBoundsAnimation = true;
- return true;
}
+ return updated;
}
- final int newRotation = getDisplayInfo().rotation;
- final int newDensity = getDisplayInfo().logicalDensityDpi;
+ final int newRotation = parentConfig.windowConfiguration.getRotation();
+ final int newDensity = parentConfig.densityDpi;
- if (mRotation == newRotation && mDensity == newDensity) {
- // Nothing to do here as we already update the state in updateDisplayInfo.
+ if (prevConfig.windowConfiguration.getRotation() == newRotation
+ && prevConfig.densityDpi == newDensity) {
return false;
}
if (matchParentBounds()) {
- // Update stack bounds again since rotation changed since updateDisplayInfo().
- setBounds(null);
- // Return false since we don't need the client to resize.
return false;
}
- mTmpRect2.set(getRawBounds());
- mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
- if (inSplitScreenPrimaryWindowingMode()) {
- repositionPrimarySplitScreenStackAfterRotation(mTmpRect2);
- snapDockedStackAfterRotation(mTmpRect2);
- final int newDockSide = getDockSide(mTmpRect2);
+ mDisplayContent.rotateBounds(parentConfig.windowConfiguration.getBounds(),
+ prevConfig.windowConfiguration.getRotation(), newRotation, inOutBounds);
+ if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+ boolean primary = getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+ repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds);
+ final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout;
+ snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds);
+ if (primary) {
+ final int newDockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
- // Update the dock create mode and clear the dock create bounds, these
- // might change after a rotation and the original values will be invalid.
- mService.setDockedStackCreateStateLocked(
- (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
- null);
- mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+ // Update the dock create mode and clear the dock create bounds, these
+ // might change after a rotation and the original values will be invalid.
+ mService.setDockedStackCreateStateLocked(
+ (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
+ ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+ : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
+ null);
+ mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+ }
}
- mBoundsAfterRotation.set(mTmpRect2);
return true;
}
- void getBoundsForNewConfiguration(Rect outBounds) {
- outBounds.set(mBoundsAfterRotation);
- mBoundsAfterRotation.setEmpty();
- }
-
/**
* Some primary split screen sides are not allowed by the policy. This method queries the policy
* and moves the primary stack around if needed.
*
- * @param inOutBounds the bounds of the primary stack to adjust
+ * @param parentConfig the configuration of the stack's parent.
+ * @param primary true if adjusting the primary docked stack, false for secondary.
+ * @param inOutBounds the bounds of the stack to adjust.
*/
- private void repositionPrimarySplitScreenStackAfterRotation(Rect inOutBounds) {
- int dockSide = getDockSide(inOutBounds);
- if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) {
+ void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary,
+ Rect inOutBounds) {
+ final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
+ final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide);
+ final int primaryDockSide = primary ? dockSide : otherDockSide;
+ if (mDisplayContent.getDockedDividerController()
+ .canPrimaryStackDockTo(primaryDockSide,
+ parentConfig.windowConfiguration.getBounds(),
+ parentConfig.windowConfiguration.getRotation())) {
return;
}
- mDisplayContent.getBounds(mTmpRect);
- dockSide = DockedDividerUtils.invertDockSide(dockSide);
- switch (dockSide) {
+ final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+ switch (otherDockSide) {
case DOCKED_LEFT:
int movement = inOutBounds.left;
inOutBounds.left -= movement;
inOutBounds.right -= movement;
break;
case DOCKED_RIGHT:
- movement = mTmpRect.right - inOutBounds.right;
+ movement = parentBounds.right - inOutBounds.right;
inOutBounds.left += movement;
inOutBounds.right += movement;
break;
@@ -539,7 +556,7 @@
inOutBounds.bottom -= movement;
break;
case DOCKED_BOTTOM:
- movement = mTmpRect.bottom - inOutBounds.bottom;
+ movement = parentBounds.bottom - inOutBounds.bottom;
inOutBounds.top += movement;
inOutBounds.bottom += movement;
break;
@@ -549,22 +566,22 @@
/**
* Snaps the bounds after rotation to the closest snap target for the docked stack.
*/
- private void snapDockedStackAfterRotation(Rect outBounds) {
+ void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout,
+ Rect outBounds) {
// Calculate the current position.
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
- final int dockSide = getDockSide(outBounds);
+ final int dockSide = getDockSide(parentConfig, outBounds);
final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
dockSide, dividerSize);
- final int displayWidth = displayInfo.logicalWidth;
- final int displayHeight = displayInfo.logicalHeight;
+ final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
+ final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
// Snap the position to a target.
- final int rotation = displayInfo.rotation;
- final int orientation = mDisplayContent.getConfiguration().orientation;
+ final int rotation = parentConfig.windowConfiguration.getRotation();
+ final int orientation = parentConfig.orientation;
mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight,
- displayInfo.displayCutout, outBounds);
+ displayCutout, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
@@ -573,7 +590,7 @@
// Recalculate the bounds based on the position of the target.
DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
- outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
+ outBounds, displayWidth, displayHeight,
dividerSize);
}
@@ -1473,27 +1490,27 @@
* information which side of the screen was the dock anchored.
*/
int getDockSide() {
- return getDockSide(getRawBounds());
+ return getDockSide(mDisplayContent.getConfiguration(), getRawBounds());
}
int getDockSideForDisplay(DisplayContent dc) {
- return getDockSide(dc, getRawBounds());
+ return getDockSide(dc, dc.getConfiguration(), getRawBounds());
}
- private int getDockSide(Rect bounds) {
+ int getDockSide(Configuration parentConfig, Rect bounds) {
if (mDisplayContent == null) {
return DOCKED_INVALID;
}
- return getDockSide(mDisplayContent, bounds);
+ return getDockSide(mDisplayContent, parentConfig, bounds);
}
- private int getDockSide(DisplayContent dc, Rect bounds) {
+ private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) {
if (!inSplitScreenWindowingMode()) {
return DOCKED_INVALID;
}
- dc.getBounds(mTmpRect);
- final int orientation = dc.getConfiguration().orientation;
- return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
+ return dc.getDockedDividerController().getDockSide(bounds,
+ parentConfig.windowConfiguration.getBounds(),
+ parentConfig.orientation, parentConfig.windowConfiguration.getRotation());
}
boolean hasTaskForUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a641f75..ec68f76 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -441,7 +441,7 @@
final WindowHashMap mWindowMap = new WindowHashMap();
/** Global service lock used by the package the owns this service. */
- WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
+ final WindowManagerGlobalLock mGlobalLock;
/**
* List of app window tokens that are waiting for replacing windows. If the
@@ -855,9 +855,11 @@
}
public static WindowManagerService main(final Context context, final InputManagerService im,
- final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy) {
+ final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
+ final WindowManagerGlobalLock globalLock) {
DisplayThread.getHandler().runWithScissors(() ->
- sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy),
+ sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
+ globalLock),
0);
return sInstance;
}
@@ -879,8 +881,10 @@
}
private WindowManagerService(Context context, InputManagerService inputManager,
- boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy) {
+ boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
+ WindowManagerGlobalLock globalLock) {
installLock(this, INDEX_WINDOW);
+ mGlobalLock = globalLock;
mContext = context;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
@@ -2403,20 +2407,13 @@
return config;
}
- @Override
- public int[] setNewDisplayOverrideConfiguration(Configuration overrideConfig, int displayId) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewDisplayOverrideConfiguration()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+ void setNewDisplayOverrideConfiguration(Configuration overrideConfig, DisplayContent dc) {
+ if (mWaitingForConfig) {
+ mWaitingForConfig = false;
+ mLastFinishedFreezeSource = "new-config";
}
- synchronized (mGlobalLock) {
- if (mWaitingForConfig) {
- mWaitingForConfig = false;
- mLastFinishedFreezeSource = "new-config";
- }
-
- return mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, displayId);
- }
+ mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, dc);
}
// TODO(multi-display): remove when no default display use case.
@@ -2629,21 +2626,16 @@
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
- * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout}
+ * layouting will be resumed once the last caller has called
+ * {@link #continueSurfaceLayout}.
*/
- public void deferSurfaceLayout() {
- synchronized (mGlobalLock) {
- mWindowPlacerLocked.deferLayout();
- }
+ void deferSurfaceLayout() {
+ mWindowPlacerLocked.deferLayout();
}
- /**
- * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()}
- */
- public void continueSurfaceLayout() {
- synchronized (mGlobalLock) {
- mWindowPlacerLocked.continueLayout();
- }
+ /** Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} */
+ void continueSurfaceLayout() {
+ mWindowPlacerLocked.continueLayout();
}
/**
@@ -6902,7 +6894,7 @@
if (DEBUG_DISPLAY) {
Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId);
}
- synchronized (WindowManagerService.this) {
+ synchronized (mGlobalLock) {
mVr2dDisplayId = vr2dDisplayId;
}
}
@@ -7027,10 +7019,6 @@
* WARNING: This interrupts surface updates, be careful! Don't
* execute within the transaction for longer than you would
* execute on an animation thread.
- * WARNING: This holds the WindowManager lock, so if exec will acquire
- * the ActivityManager lock, you should hold it BEFORE calling this
- * otherwise there is a risk of deadlock if another thread holding the AM
- * lock waits on the WM lock.
* WARNING: This method contains locks known to the State of California
* to cause Deadlocks and other conditions.
*
@@ -7051,19 +7039,12 @@
* deferSurfaceLayout may be a little too broad, in particular the total
* enclosure of startActivityUnchecked which could run for quite some time.
*/
- public void inSurfaceTransaction(Runnable exec) {
- // We hold the WindowManger lock to ensure relayoutWindow
- // does not return while a Surface transaction is opening.
- // The client depends on us to have resized the surface
- // by that point (b/36462635)
-
- synchronized (mGlobalLock) {
- SurfaceControl.openTransaction();
- try {
- exec.run();
- } finally {
- SurfaceControl.closeTransaction();
- }
+ void inSurfaceTransaction(Runnable exec) {
+ SurfaceControl.openTransaction();
+ try {
+ exec.run();
+ } finally {
+ SurfaceControl.closeTransaction();
}
}
@@ -7139,6 +7120,10 @@
mRotatingSeamlessly = true;
}
+ boolean isRotatingSeamlessly() {
+ return mRotatingSeamlessly;
+ }
+
void finishSeamlessRotation() {
mRotatingSeamlessly = false;
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bb17254..4c9788d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -56,6 +56,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -690,24 +691,52 @@
}
void addPackage(String pkg, long versionCode) {
- // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
- // using WM lock. Need to figure-out if it is okay to do this asynchronously.
if (mListener == null) return;
- mListener.addPackage(pkg, versionCode);
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Message m = PooledLambda.obtainMessage(
+ WindowProcessListener::addPackage, mListener, pkg, versionCode);
+ mAtm.mH.sendMessage(m);
}
ProfilerInfo onStartActivity(int topProcessState) {
- // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
- // using WM lock. Need to figure-out if it is okay to do this asynchronously.
- if (mListener == null) return null;
- return mListener.onStartActivity(topProcessState);
+ ProfilerInfo profilerInfo = null;
+ boolean setProfileProc = false;
+ if (mAtm.mProfileApp != null
+ && mAtm.mProfileApp.equals(mName)) {
+ if (mAtm.mProfileProc == null || mAtm.mProfileProc == this) {
+ setProfileProc = true;
+ final ProfilerInfo profilerInfoSvc = mAtm.mProfilerInfo;
+ if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
+ if (profilerInfoSvc.profileFd != null) {
+ try {
+ profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
+ } catch (IOException e) {
+ profilerInfoSvc.closeFd();
+ }
+ }
+
+ profilerInfo = new ProfilerInfo(profilerInfoSvc);
+ }
+ }
+ }
+
+
+ if (mListener != null) {
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Message m = PooledLambda.obtainMessage(WindowProcessListener::onStartActivity,
+ mListener, topProcessState, setProfileProc);
+ mAtm.mH.sendMessage(m);
+ }
+
+ return profilerInfo;
}
public void appDied() {
- // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
- // using WM lock. Need to figure-out if it is okay to do this asynchronously.
if (mListener == null) return;
- mListener.appDied();
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Message m = PooledLambda.obtainMessage(
+ WindowProcessListener::appDied, mListener);
+ mAtm.mH.sendMessage(m);
}
void registerDisplayConfigurationListenerLocked(ActivityDisplay activityDisplay) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 7f20f4b..bce5e2d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import android.app.ProfilerInfo;
import android.util.proto.ProtoOutputStream;
/**
@@ -58,7 +57,7 @@
void addPackage(String pkg, long versionCode);
/** Called when we are in the process on starting an activity. */
- ProfilerInfo onStartActivity(int topProcessState);
+ void onStartActivity(int topProcessState, boolean setProfileProc);
/** App died :(...oh well */
void appDied();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f432c8d..e364e9a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,6 +16,12 @@
package com.android.server;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import android.app.ActivityThread;
import android.app.INotificationManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -64,10 +70,11 @@
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
-import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.appbinding.AppBindingService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.face.FaceService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
import com.android.server.biometrics.iris.IrisService;
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
@@ -79,8 +86,6 @@
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
-import com.android.server.biometrics.face.FaceService;
-import com.android.server.biometrics.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.inputmethod.InputMethodManagerService;
@@ -88,8 +93,8 @@
import com.android.server.lights.LightsService;
import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
-import com.android.server.media.MediaUpdateService;
import com.android.server.media.MediaSessionService;
+import com.android.server.media.MediaUpdateService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -110,6 +115,7 @@
import com.android.server.policy.PhoneWindowManager;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
+import com.android.server.power.ThermalManagerService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
@@ -128,6 +134,8 @@
import com.android.server.usage.UsageStatsService;
import com.android.server.vr.VrManagerService;
import com.android.server.webkit.WebViewUpdateService;
+import com.android.server.wm.ActivityTaskManagerService;
+import com.android.server.wm.WindowManagerGlobalLock;
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
@@ -139,12 +147,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
-import static android.os.IServiceManager.DUMP_FLAG_PROTO;
-import static android.view.Display.DEFAULT_DISPLAY;
-
public final class SystemServer {
private static final String TAG = "SystemServer";
@@ -230,6 +232,8 @@
"com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
"com.android.server.autofill.AutofillManagerService";
+ private static final String INTELLIGENCE_MANAGER_SERVICE_CLASS =
+ "com.android.server.intelligence.IntelligenceManagerService";
private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
"com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String IOT_SERVICE_CLASS =
@@ -273,6 +277,7 @@
// TODO: remove all of these references by improving dependency resolution and boot phases
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
+ private WindowManagerGlobalLock mWindowManagerGlobalLock;
private WebViewUpdateService mWebViewUpdateService;
private DisplayManagerService mDisplayManagerService;
private PackageManagerService mPackageManagerService;
@@ -595,6 +600,7 @@
mSystemServiceManager, atm);
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
+ mWindowManagerGlobalLock = atm.getGlobalLock();
traceEnd();
// Power manager needs to be started early because other services need it.
@@ -605,6 +611,10 @@
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
traceEnd();
+ traceBeginAndSlog("StartThermalManager");
+ mSystemServiceManager.startService(ThermalManagerService.class);
+ traceEnd();
+
// Now that the power manager has been started, let the activity manager
// initialize power management features.
traceBeginAndSlog("InitPowerManagement");
@@ -795,6 +805,8 @@
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
+ boolean disableIntelligence = SystemProperties.getBoolean(
+ "config.disable_intelligence", false);
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
@@ -917,7 +929,7 @@
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
- new PhoneWindowManager());
+ new PhoneWindowManager(), mWindowManagerGlobalLock);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
@@ -1737,6 +1749,12 @@
traceEnd();
}
+ if (!disableIntelligence) {
+ traceBeginAndSlog("StartIntelligenceService");
+ mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
traceBeginAndSlog("AppServiceManager");
mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
traceEnd();
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 878179b..e2f8995 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -33,7 +33,8 @@
testables \
testng \
ub-uiautomator\
- platformprotosnano
+ platformprotosnano \
+ hamcrest-library
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index e53518c..69d8e25 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -28,8 +28,9 @@
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.os.storage.StorageManagerInternal;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 2b5b812..a847b6a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -38,12 +38,13 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.security.KeyChain;
-import android.support.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Pair;
import android.view.IWindowManager;
+import androidx.annotation.NonNull;
+
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.net.NetworkPolicyManagerInternal;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 213961c..be00bb6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -30,11 +30,12 @@
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManagerInternal;
-import android.support.annotation.NonNull;
import android.test.mock.MockContext;
import android.util.ArrayMap;
import android.util.ExceptionUtils;
+import androidx.annotation.NonNull;
+
import com.android.internal.util.FunctionalUtils;
import org.junit.Assert;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b0b7def..58c4bbf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,10 @@
*/
package com.android.server.pm;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -38,12 +41,12 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import libcore.io.IoUtils;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import libcore.io.IoUtils;
-
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
@@ -461,6 +464,7 @@
pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
pkg.requestedPermissions.add("foo7");
+ pkg.implicitPermissions.add("foo25");
pkg.protectedBroadcasts = new ArrayList<>();
pkg.protectedBroadcasts.add("foo8");
@@ -490,7 +494,7 @@
pkg.usesLibraryFiles = new String[] { "foo13"};
pkg.usesLibraryInfos = new ArrayList<>();
- pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null));
+ pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null));
pkg.mOriginalPackages = new ArrayList<>();
pkg.mOriginalPackages.add("foo14");
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
index 416a616..bd42b73 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -401,15 +401,7 @@
List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
- PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
- assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
- // We expect that all the contexts are unsupported.
- String[] expectedContexts =
- Collections.nCopies(secondaries.size(),
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
+ assertNoUseInfo(mBarUser0UnsupportedClassLoader);
}
@Test
@@ -438,27 +430,18 @@
}
@Test
- public void testNotifyUnsupportedClassLoaderDoesNotChange() {
- List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
+ public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
+ List<String> secondaries = mBarUser0.getSecondaryDexPaths();
+
+ notifyDexLoad(mBarUser0, secondaries, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+ assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
+
+ // Record bar secondaries again with an unsupported class loader. This should not change the
+ // context.
notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
-
- PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
- assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
- // We expect that all the contexts are unsupported.
- String[] expectedContexts =
- Collections.nCopies(secondaries.size(),
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
- // Record bar secondaries again with a different class loader. This will change the context.
- // However, because the context was already marked as unsupported we should not chage it.
- notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0);
- pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
+ pui = getPackageUseInfo(mBarUser0);
+ assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
}
@Test
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
index 3e93dcf..7755e94 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -399,20 +399,6 @@
}
@Test
- public void testRecordClassLoaderContextUnsupportedContext() {
- // Record a secondary dex file.
- assertTrue(record(mFooSecondary1User0));
- // Now update its context.
- TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext(
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
- assertTrue(record(unsupportedContext));
-
- assertPackageDexUsage(null, unsupportedContext);
- writeAndReadBack();
- assertPackageDexUsage(null, unsupportedContext);
- }
-
- @Test
public void testRecordClassLoaderContextTransitionFromUnknown() {
// Record a secondary dex file.
TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext(
@@ -440,29 +426,41 @@
PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId,
"valid_context", "arm");
assertFalse(validContext.isUnknownClassLoaderContext());
- assertFalse(validContext.isUnsupportedClassLoaderContext());
assertFalse(validContext.isVariableClassLoaderContext());
- PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId,
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm");
- assertFalse(unsupportedContext.isUnknownClassLoaderContext());
- assertTrue(unsupportedContext.isUnsupportedClassLoaderContext());
- assertFalse(unsupportedContext.isVariableClassLoaderContext());
-
PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId,
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm");
assertFalse(variableContext.isUnknownClassLoaderContext());
- assertFalse(variableContext.isUnsupportedClassLoaderContext());
assertTrue(variableContext.isVariableClassLoaderContext());
PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId,
PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm");
assertTrue(unknownContext.isUnknownClassLoaderContext());
- assertFalse(unknownContext.isUnsupportedClassLoaderContext());
assertFalse(unknownContext.isVariableClassLoaderContext());
}
@Test
+ public void testUnsupportedClassLoaderDiscardedOnRead() throws Exception {
+ String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n"
+ + mBarSecondary1User0.mPackageName + "\n"
+ + "#" + mBarSecondary1User0.mDexFile + "\n"
+ + "0,0," + mBarSecondary1User0.mLoaderIsa + "\n"
+ + "@\n"
+ + "=UnsupportedClassLoaderContext=\n"
+
+ + mFooSecondary1User0.mPackageName + "\n"
+ + "#" + mFooSecondary1User0.mDexFile + "\n"
+ + "0,0," + mFooSecondary1User0.mLoaderIsa + "\n"
+ + "@\n"
+ + mFooSecondary1User0.mClassLoaderContext + "\n";
+
+ mPackageDexUsage.read(new StringReader(content));
+
+ assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0);
+ assertPackageDexUsage(mBarBaseUser0);
+ }
+
+ @Test
public void testReadVersion1() {
String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
// Equivalent to
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index caaa0bb..41d5691 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -129,6 +129,7 @@
static class MyInjector extends AppStandbyController.Injector {
long mElapsedRealtime;
+ boolean mIsAppIdleEnabled = true;
boolean mIsCharging;
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
boolean mDisplayOn;
@@ -160,7 +161,7 @@
@Override
boolean isAppIdleEnabled() {
- return true;
+ return mIsAppIdleEnabled;
}
@Override
@@ -277,6 +278,13 @@
}
}
+ private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
+ mInjector.mIsAppIdleEnabled = enabled;
+ if (controller != null) {
+ controller.setAppIdleEnabled(enabled);
+ }
+ }
+
private AppStandbyController setupController() throws Exception {
mInjector.mElapsedRealtime = 0;
setupPm(mInjector.getContext().getPackageManager());
@@ -346,7 +354,7 @@
public void onParoleStateChanged(boolean isParoleOn) {
synchronized (this) {
// Only record information if it is being looked for
- if (mLatch.getCount() > 0) {
+ if (mLatch != null && mLatch.getCount() > 0) {
mOnParole = isParoleOn;
mLastParoleChangeTime = getCurrentTime();
mLatch.countDown();
@@ -407,6 +415,74 @@
marginOfError);
}
+ @Test
+ public void testEnabledState() throws Exception {
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+ long lastUpdateTime;
+
+ // Test that listeners are notified if enabled changes when the device is not in parole.
+ setChargingState(mController, false);
+
+ // Start off not enabled. Device is effectively on permanent parole.
+ setAppIdleEnabled(mController, false);
+
+ // Enable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ // Disable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+
+ // Test that listeners aren't notified if enabled status changes when the device is already
+ // in parole.
+
+ // A device is in parole whenever it's charging.
+ setChargingState(mController, true);
+
+ // Start off not enabled.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ // Test that toggling doesn't notify the listener.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+ }
+
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
mInjector.mElapsedRealtime = elapsedTime;
controller.checkIdleStates(USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index a8e1ed4..552390d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -190,7 +190,11 @@
private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
+ int oldRotation = mDisplayContent.getRotation();
mWm.updateRotation(false, false);
+ // Must manually apply here since ATM doesn't know about the display during this test
+ // (meaning it can't perform the normal sendNewConfiguration flow).
+ mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation());
// Prevent the next rotation from being deferred by animation.
mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index dd374e9..f4da4b3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -230,7 +230,6 @@
*/
@Test
public void testDisplayOverrideConfigUpdate() {
- final int displayId = mDisplayContent.getDisplayId();
final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
// Create new, slightly changed override configuration and apply it to the display.
@@ -238,7 +237,7 @@
newOverrideConfig.densityDpi += 120;
newOverrideConfig.fontScale += 0.3;
- mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent);
// Check that override config is applied.
assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
@@ -249,14 +248,15 @@
*/
@Test
public void testDefaultDisplayOverrideConfigUpdate() {
- final Configuration currentConfig = mDisplayContent.getConfiguration();
+ DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ final Configuration currentConfig = defaultDisplay.getConfiguration();
// Create new, slightly changed override configuration and apply it to the display.
final Configuration newOverrideConfig = new Configuration(currentConfig);
newOverrideConfig.densityDpi += 120;
newOverrideConfig.fontScale += 0.3;
- mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay);
// Check that global configuration is updated, as we've updated default display's config.
Configuration globalConfig = mWm.mRoot.getConfiguration();
@@ -264,7 +264,7 @@
assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
// Return back to original values.
- mWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
+ mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay);
globalConfig = mWm.mRoot.getConfiguration();
assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
diff --git a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
deleted file mode 100644
index 62a617d..0000000
--- a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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.wm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Tests for the {@link RootWindowContainer} class.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:RootWindowContainerTests
- */
-@SmallTest
-@Presubmit
-public class RootWindowContainerTests extends WindowTestsBase {
- @Test
- public void testSetDisplayOverrideConfigurationIfNeeded() {
- synchronized (mWm.mGlobalLock) {
- // Add first stack we expect to be updated with configuration change.
- final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
- stack.getOverrideConfiguration().windowConfiguration.setBounds(new Rect(0, 0, 5, 5));
-
- // Add second task that will be set for deferred removal that should not be returned
- // with the configuration change.
- final TaskStack deferredDeletedStack = createTaskStackOnDisplay(mDisplayContent);
- deferredDeletedStack.getOverrideConfiguration().windowConfiguration.setBounds(
- new Rect(0, 0, 5, 5));
- deferredDeletedStack.mDeferRemoval = true;
-
- final Configuration override = new Configuration(
- mDisplayContent.getOverrideConfiguration());
- override.windowConfiguration.setBounds(new Rect(0, 0, 10, 10));
-
- // Set display override.
- final int[] results = mWm.mRoot.setDisplayOverrideConfigurationIfNeeded(override,
- mDisplayContent.getDisplayId());
-
- // Ensure only first stack is returned.
- assertEquals(1, results.length);
- assertEquals(stack.mStackId, results[0]);
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index 4369c96..3643457 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -22,6 +22,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOW_CONFIG_ALWAYS_ON_TOP;
import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_ROTATION;
import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -33,6 +34,7 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
+import android.view.Surface;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -66,11 +68,13 @@
final WindowConfiguration winConfig2 = config2.windowConfiguration;
final Configuration config3 = new Configuration();
final WindowConfiguration winConfig3 = config3.windowConfiguration;
+ final Configuration config4 = new Configuration();
+ final WindowConfiguration winConfig4 = config4.windowConfiguration;
winConfig1.setAppBounds(0, 1, 1, 0);
winConfig2.setAppBounds(1, 2, 2, 1);
winConfig3.setAppBounds(winConfig1.getAppBounds());
-
+ winConfig4.setRotation(Surface.ROTATION_90);
assertEquals(CONFIG_WINDOW_CONFIGURATION, config1.diff(config2));
assertEquals(0, config1.diffPublicOnly(config2));
@@ -86,6 +90,9 @@
| WINDOW_CONFIG_ALWAYS_ON_TOP,
winConfig1.diff(winConfig2, false /* compareUndefined */));
+ assertEquals(WINDOW_CONFIG_ROTATION,
+ winConfig1.diff(winConfig4, false /* compareUndefined */));
+
assertEquals(0, config1.diff(config3));
assertEquals(0, config1.diffPublicOnly(config3));
assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */));
@@ -123,11 +130,18 @@
winConfig2.setAppBounds(0, 2, 3, 4);
assertNotEquals(config1.compareTo(config2), 0);
assertNotEquals(winConfig1.compareTo(winConfig2), 0);
+ winConfig2.setAppBounds(winConfig1.getAppBounds());
// No bounds
assertEquals(config1.compareTo(blankConfig), -1);
assertEquals(winConfig1.compareTo(blankWinConfig), -1);
+ // Different rotation
+ winConfig2.setRotation(Surface.ROTATION_180);
+ assertNotEquals(config1.compareTo(config2), 0);
+ assertNotEquals(winConfig1.compareTo(winConfig2), 0);
+ winConfig2.setRotation(winConfig1.getRotation());
+
assertEquals(blankConfig.compareTo(config1), 1);
assertEquals(blankWinConfig.compareTo(winConfig1), 1);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 4e75ec9..9a13efb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -124,9 +124,10 @@
doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
}
- mService = WindowManagerService.main(context, ims, false,
- false, mPolicy = new TestWindowManagerPolicy(
- WindowManagerServiceRule.this::getWindowManagerService));
+ mService = WindowManagerService.main(context, ims, false, false,
+ mPolicy = new TestWindowManagerPolicy(
+ WindowManagerServiceRule.this::getWindowManagerService),
+ new WindowManagerGlobalLock());
mService.mTransactionFactory = () -> {
final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
mSurfaceTransactions.add(new WeakReference<>(transaction));
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 9e12f02..b318b91 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -53,14 +53,6 @@
public class WindowTestUtils {
private static int sNextTaskId = 0;
- /** Retrieves an instance of a mock {@link WindowManagerService}. */
- static WindowManagerService getMockWindowManagerService() {
- final WindowManagerService service = mock(WindowManagerService.class);
- final WindowManagerGlobalLock lock = new WindowManagerGlobalLock();
- doReturn(lock).when(service).getWindowManagerLock();
- return service;
- }
-
/** An extension of {@link DisplayContent} to gain package scoped access. */
public static class TestDisplayContent extends DisplayContent {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index 6c125d1..32f389a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -71,7 +71,8 @@
private NotificationRecord getNotificationRecord(NotificationChannel c) {
StatusBarNotification sbn = mock(StatusBarNotification.class);
- when(sbn.getNotification()).thenReturn(mock(Notification.class));
+ Notification notification = mock(Notification.class);
+ when(sbn.getNotification()).thenReturn(notification);
return new NotificationRecord(mContext, sbn, c);
}
diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk
index dd656c30..9655b3d 100644
--- a/services/tests/wmtests/Android.mk
+++ b/services/tests/wmtests/Android.mk
@@ -23,6 +23,7 @@
truth-prebuilt \
testables \
ub-uiautomator \
+ hamcrest-library
LOCAL_JAVA_LIBRARIES := \
android.test.mock \
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 73a34b6..ff84803 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -41,7 +41,8 @@
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" />
- <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+ <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
+ android:showWhenLocked="true" />
</application>
<instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index d3f1a0a..7a9c8dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -27,7 +28,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import android.platform.test.annotations.Presubmit;
@@ -120,6 +126,39 @@
assertTrue(stack2.isFocusedStackOnDisplay());
}
+ /**
+ * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
+ */
+ @Test
+ public void testNotResumeHomeStackOnRemovingDisplay() {
+ // Create a display which supports system decoration and allows reparenting stacks to
+ // another display when the display is removed.
+ final ActivityDisplay display = spy(createNewActivityDisplay());
+ doReturn(false).when(display).shouldDestroyContentOnRemove();
+ doReturn(true).when(display).supportsSystemDecorations();
+ mSupervisor.addChild(display, ActivityDisplay.POSITION_TOP);
+
+ // Put home stack on the display.
+ final ActivityStack homeStack = display.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(homeStack).build();
+ new ActivityBuilder(mService).setTask(task).build();
+ display.removeChild(homeStack);
+ final ActivityStack spiedHomeStack = spy(homeStack);
+ display.addChild(spiedHomeStack, ActivityDisplay.POSITION_TOP);
+ reset(spiedHomeStack);
+
+ // Put a finishing standard activity which will be reparented.
+ final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
+ stack.topRunningActivityLocked().makeFinishingLocked();
+
+ display.remove();
+
+ // The removed display should have no focused stack and its home stack should never resume.
+ assertNull(display.getFocusedStack());
+ verify(spiedHomeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
+ }
+
private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
final ActivityStack fullscreenStack = display.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
new file mode 100644
index 0000000..215c51d
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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.wm;
+
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.Intent;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseIntArray;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ActivityMetricsLaunchObserver} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:ActivityMetricsLaunchObserverTests
+ */
+@SmallTest
+@Presubmit
+@FlakyTest(detail="promote once confirmed non-flaky")
+public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
+ private ActivityMetricsLogger mActivityMetricsLogger;
+ private ActivityMetricsLaunchObserver mLaunchObserver;
+
+ private TestActivityStack mStack;
+ private TaskRecord mTask;
+ private ActivityRecord mActivityRecord;
+ private ActivityRecord mActivityRecordTrampoline;
+
+ @Before
+ public void setUpAMLO() throws Exception {
+ setupActivityTaskManagerService();
+
+ mActivityMetricsLogger =
+ new ActivityMetricsLogger(mSupervisor, mService.mContext, mService.mH.getLooper());
+
+ mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
+
+ // TODO: Use ActivityMetricsLaunchObserverRegistry .
+ java.lang.reflect.Field f =
+ mActivityMetricsLogger.getClass().getDeclaredField("mLaunchObserver");
+ f.setAccessible(true);
+ f.set(mActivityMetricsLogger, mLaunchObserver);
+
+ // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
+ // This seems to be the easiest way to create an ActivityRecord.
+ mStack = mSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
+ mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build();
+ mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
+ }
+
+ @Test
+ public void testOnIntentStarted() throws Exception {
+ Intent intent = new Intent("action 1");
+
+ mActivityMetricsLogger.notifyActivityLaunching(intent);
+
+ verify(mLaunchObserver).onIntentStarted(eq(intent));
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnIntentFailed() throws Exception {
+ testOnIntentStarted();
+
+ ActivityRecord activityRecord = null;
+
+ // Bringing an intent that's already running 'to front' is not considered
+ // as an ACTIVITY_LAUNCHED state transition.
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+ activityRecord);
+
+ verify(mLaunchObserver).onIntentFailed();
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunched() throws Exception {
+ testOnIntentStarted();
+
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+ mActivityRecord);
+
+ verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt());
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunchFinished() throws Exception {
+ testOnActivityLaunched();
+
+ mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+ SystemClock.uptimeMillis());
+
+ mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
+ SystemClock.uptimeMillis());
+
+ verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecord));
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunchCancelled() throws Exception {
+ testOnActivityLaunched();
+
+ mActivityRecord.nowVisible = true;
+
+ // Cannot time already-visible activities.
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
+
+ verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecord));
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunchedTrampoline() throws Exception {
+ testOnIntentStarted();
+
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+ mActivityRecord);
+
+ verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt());
+
+ // A second, distinct, activity launch is coalesced into the the current app launch sequence
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
+ mActivityRecordTrampoline);
+
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunchFinishedTrampoline() throws Exception {
+ testOnActivityLaunchedTrampoline();
+
+ mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+ SystemClock.uptimeMillis());
+
+ mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
+ SystemClock.uptimeMillis());
+
+ verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecordTrampoline));
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+
+ @Test
+ public void testOnActivityLaunchCancelledTrampoline() throws Exception {
+ testOnActivityLaunchedTrampoline();
+
+ mActivityRecordTrampoline.nowVisible = true;
+
+ // Cannot time already-visible activities.
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+ mActivityRecordTrampoline);
+
+ verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecordTrampoline));
+ verifyNoMoreInteractions(mLaunchObserver);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index a794d6d..f692a57 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -25,12 +25,12 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -54,6 +54,8 @@
import android.app.ActivityOptions;
import android.app.WaitResult;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -436,7 +438,7 @@
* Tests that home activities can be started on the displays that supports system decorations.
*/
@Test
- public void testStartHomeOnAllDisplays() throws Exception {
+ public void testStartHomeOnAllDisplays() {
// Create secondary displays.
final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
mSupervisor.addChild(secondDisplay, POSITION_TOP);
@@ -450,7 +452,7 @@
.create(any(), anyInt(), any(), any(), any(), any());
doReturn(true).when(mService.mStackSupervisor)
.ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
- doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt());
+ doReturn(true).when(mSupervisor).canStartHomeOnDisplay(any(), anyInt(), anyBoolean());
mSupervisor.startHomeOnAllDisplays(0, "testStartHome");
@@ -458,4 +460,49 @@
assertNotNull(secondDisplay.getTopStack());
assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
}
+
+ /**
+ * Tests that home activities won't be started before booting when display added.
+ */
+ @Test
+ public void testNotStartHomeBeforeBoot() {
+ final int displayId = 1;
+ final boolean isBooting = mService.mAmInternal.isBooting();
+ final boolean isBooted = mService.mAmInternal.isBooted();
+ try {
+ mService.mAmInternal.setBooting(false);
+ mService.mAmInternal.setBooted(false);
+ mSupervisor.onDisplayAdded(displayId);
+ verify(mSupervisor, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
+ } finally {
+ mService.mAmInternal.setBooting(isBooting);
+ mService.mAmInternal.setBooted(isBooted);
+ }
+ }
+
+ /**
+ * Tests whether home can be started if being instrumented.
+ */
+ @Test
+ public void testCanStartHomeWhenInstrumented() {
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ final WindowProcessController app = mock(WindowProcessController.class);
+ doReturn(app).when(mService).getProcessController(any(), anyInt());
+
+ // Can not start home if we don't want to start home while home is being instrumented.
+ doReturn(true).when(app).isInstrumenting();
+ assertFalse(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ false /* allowInstrumenting*/));
+
+ // Can start home for other cases.
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ true /* allowInstrumenting*/));
+
+ doReturn(false).when(app).isInstrumenting();
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ false /* allowInstrumenting*/));
+ assertTrue(mSupervisor.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
+ true /* allowInstrumenting*/));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 974e285..62767e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -457,7 +457,7 @@
final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final TestActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
homeStack.setIsTranslucent(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 9d28c57..c35e4d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -153,8 +153,7 @@
void setupActivityManagerService(
TestActivityManagerService am, TestActivityTaskManagerService atm) {
- atm.setActivityManagerService(am, am.mHandlerThread.getLooper(), am.mIntentFirewall,
- am.mPendingIntentController);
+ atm.setActivityManagerService(am.mIntentFirewall, am.mPendingIntentController);
atm.mAmInternal = am.getLocalService();
am.mAtmInternal = atm.getLocalService();
// Makes sure the supervisor is using with the spy object.
@@ -629,7 +628,7 @@
}
private static WindowManagerService prepareMockWindowManager() {
- final WindowManagerService service = WindowTestUtils.getMockWindowManagerService();
+ final WindowManagerService service = mock(WindowManagerService.class);
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 4455630..72d7c90 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -19,9 +19,12 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import android.app.ActivityManager;
@@ -92,6 +95,18 @@
assertNotNull(TaskRecord.getTaskRecordFactory());
}
+ /** Ensure we have no chance to modify the original intent. */
+ @Test
+ public void testCopyBaseIntentForTaskInfo() {
+ final TaskRecord task = createTaskRecord(1);
+ task.lastTaskDescription = new ActivityManager.TaskDescription();
+ final ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
+ task.fillTaskInfo(info, new TaskRecord.TaskActivitiesReport());
+
+ // The intent of info should be a copy so assert that they are different instances.
+ assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
+ }
+
@Test
public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
TestTaskRecordFactory factory = new TestTaskRecordFactory();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 115bcb1..3b4ab38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -38,15 +38,6 @@
* to WindowManager related test functionality.
*/
public class WindowTestUtils {
- private static int sNextTaskId = 0;
-
- /** Retrieves an instance of a mock {@link WindowManagerService}. */
- static WindowManagerService getMockWindowManagerService() {
- final WindowManagerService service = mock(WindowManagerService.class);
- final WindowManagerGlobalLock lock = new WindowManagerGlobalLock();
- doReturn(lock).when(service).getWindowManagerLock();
- return service;
- }
/** An extension of {@link DisplayContent} to gain package scoped access. */
public static class TestDisplayContent extends DisplayContent {
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 6a74564..4f573a4 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,18 +30,19 @@
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
@@ -340,14 +341,21 @@
}
void setAppIdleEnabled(boolean enabled) {
- mAppIdleEnabled = enabled;
+ synchronized (mAppIdleLock) {
+ if (mAppIdleEnabled != enabled) {
+ final boolean oldParoleState = isParoledOrCharging();
+ mAppIdleEnabled = enabled;
+ if (isParoledOrCharging() != oldParoleState) {
+ postParoleStateChanged();
+ }
+ }
+ }
}
public void onBootPhase(int phase) {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
Slog.d(TAG, "Setting app idle enabled state");
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Observe changes to the threshold
SettingsObserver settingsObserver = new SettingsObserver(mHandler);
settingsObserver.registerObserver();
@@ -1842,8 +1850,6 @@
mContext.getContentResolver(),
Global.APP_IDLE_CONSTANTS));
}
- // Check if app_idle_enabled has changed
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Look at global settings for this.
// TODO: Maybe apply different thresholds for different users.
@@ -1915,6 +1921,10 @@
(KEY_STABLE_CHARGING_THRESHOLD,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
}
+
+ // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
+ // in case we need to change something based on the new values.
+ setAppIdleEnabled(mInjector.isAppIdleEnabled());
}
long[] parseLongArray(String values, long[] defaults) {
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
index 0121d30..84add88 100644
--- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -40,7 +40,6 @@
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
-import android.os.Binder;
import android.os.UserHandle;
import android.service.usb.UsbAccessoryAttachedActivities;
import android.service.usb.UsbDeviceAttachedActivities;
@@ -190,9 +189,8 @@
@Nullable UsbAccessory accessory,
boolean canBeDefault,
String packageName,
- PendingIntent pi) {
- final int uid = Binder.getCallingUid();
-
+ PendingIntent pi,
+ int uid) {
// compare uid with packageName to foil apps pretending to be someone else
try {
ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
@@ -235,7 +233,8 @@
}
}
- requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi);
+ requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi,
+ uid);
}
public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi,
@@ -253,8 +252,8 @@
return;
}
- requestPermissionDialog(null, accessory,
- canBeDefault(accessory, packageName), packageName, pi);
+ requestPermissionDialog(null, accessory, canBeDefault(accessory, packageName), packageName,
+ pi, uid);
}
public void grantDevicePermission(UsbDevice device, int uid) {
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 3681529..c39688c 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -16,10 +16,15 @@
cc_defaults {
name: "viewcompiler_defaults",
+ header_libs: [
+ "libbase_headers",
+ ],
shared_libs: [
+ "libbase",
"libdexfile",
"slicer",
],
+ cppflags: ["-std=c++17"],
}
cc_library_host_static {
@@ -30,9 +35,6 @@
"java_lang_builder.cc",
"util.cc",
],
- static_libs: [
- "libbase",
- ],
}
cc_binary_host {
@@ -42,7 +44,6 @@
"main.cc",
],
static_libs: [
- "libbase",
"libtinyxml2",
"libgflags",
"libviewcompiler",
@@ -59,4 +60,5 @@
static_libs: [
"libviewcompiler",
],
+ test_suites: ["general-tests"],
}
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
deleted file mode 100644
index cc4b17a..0000000
--- a/startop/view_compiler/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "view-compiler-tests"
- }
- ]
-}
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 7a9f41f..13e7f73 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -22,14 +22,16 @@
#include <fstream>
#include <memory>
+#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr)
+
namespace startop {
namespace dex {
using std::shared_ptr;
using std::string;
-using art::Instruction;
using ::dex::kAccPublic;
+using Op = Instruction::Op;
const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
@@ -43,6 +45,20 @@
} // namespace
+std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
+ switch (opcode) {
+ case Instruction::Op::kReturn:
+ out << "kReturn";
+ return out;
+ case Instruction::Op::kMove:
+ out << "kMove";
+ return out;
+ case Instruction::Op::kInvokeVirtual:
+ out << "kInvokeVirtual";
+ return out;
+ }
+}
+
void* TrackingAllocator::Allocate(size_t size) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
void* raw_buffer = buffer.get();
@@ -56,7 +72,7 @@
//
// package dextest;
// public class DexTest {
-// public static int foo() { return 5; }
+// public static int foo(String s) { return s.length(); }
// }
void WriteTestDexFile(const string& filename) {
DexBuilder dex_file;
@@ -64,11 +80,17 @@
ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
cbuilder.set_source_file("dextest.java");
- MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+ TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String");
- MethodBuilder::Register r = method.MakeRegister();
- method.BuildConst4(r, 5);
- method.BuildReturn(r);
+ MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
+
+ Value result = method.MakeRegister();
+
+ MethodDeclData string_length =
+ dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
+
+ method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+ method.BuildReturn(result);
method.Encode();
@@ -78,6 +100,10 @@
out_file.write(image.ptr<const char>(), image.size());
}
+TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
+ return TypeDescriptor{art::DotToDescriptor(name.c_str())};
+}
+
DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
}
@@ -119,10 +145,9 @@
class_def->type = type_def;
class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
class_def->access_flags = kAccPublic;
- return ClassBuilder{this, class_def};
+ return ClassBuilder{this, name, class_def};
}
-// TODO(eholk): we probably want GetOrAddString() also
ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
return types_by_descriptor_[descriptor];
@@ -158,16 +183,11 @@
return shorty;
}
-ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def)
- : parent_(parent), class_(class_def) {}
+ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
+ : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
- ir::String* dex_name{parent_->GetOrAddString(name)};
-
- auto* decl = parent_->Alloc<ir::MethodDecl>();
- decl->name = dex_name;
- decl->parent = class_->type;
- decl->prototype = prototype.Encode(parent_);
+ ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl;
return MethodBuilder{parent_, class_, decl};
}
@@ -187,8 +207,13 @@
method->access_flags = kAccPublic | ::dex::kAccStatic;
auto* code = dex_->Alloc<ir::Code>();
- code->registers = num_registers_;
- // TODO: support ins and outs
+ DCHECK_NOT_NULL(decl_->prototype);
+ size_t const num_args =
+ decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
+ code->registers = num_registers_ + num_args;
+ code->ins_count = num_args;
+ code->outs_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1;
+ EncodeInstructions();
code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
method->code = code;
@@ -197,17 +222,135 @@
return method;
}
-MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; }
+Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
-void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); }
+void MethodBuilder::AddInstruction(Instruction instruction) {
+ instructions_.push_back(instruction);
+}
-void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); }
+void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); }
-void MethodBuilder::BuildConst4(Register target, int value) {
+void MethodBuilder::BuildReturn(Value src) {
+ AddInstruction(Instruction::OpWithArgs(Op::kReturn, /*destination=*/{}, src));
+}
+
+void MethodBuilder::BuildConst4(Value target, int value) {
DCHECK_LT(value, 16);
- // TODO: support more registers
- DCHECK_LT(target, 16);
- buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8));
+ AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
+}
+
+void MethodBuilder::EncodeInstructions() {
+ buffer_.clear();
+ for (const auto& instruction : instructions_) {
+ EncodeInstruction(instruction);
+ }
+}
+
+void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
+ switch (instruction.opcode()) {
+ case Instruction::Op::kReturn:
+ return EncodeReturn(instruction);
+ case Instruction::Op::kMove:
+ return EncodeMove(instruction);
+ case Instruction::Op::kInvokeVirtual:
+ return EncodeInvokeVirtual(instruction);
+ }
+}
+
+void MethodBuilder::EncodeReturn(const Instruction& instruction) {
+ DCHECK_EQ(Instruction::Op::kReturn, instruction.opcode());
+ DCHECK(!instruction.dest().has_value());
+ if (instruction.args().size() == 0) {
+ buffer_.push_back(art::Instruction::RETURN_VOID);
+ } else {
+ DCHECK(instruction.args().size() == 1);
+ size_t source = RegisterValue(instruction.args()[0]);
+ buffer_.push_back(art::Instruction::RETURN | source << 8);
+ }
+}
+
+void MethodBuilder::EncodeMove(const Instruction& instruction) {
+ DCHECK_EQ(Instruction::Op::kMove, instruction.opcode());
+ DCHECK(instruction.dest().has_value());
+ DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter());
+ DCHECK_EQ(1, instruction.args().size());
+
+ const Value& source = instruction.args()[0];
+
+ if (source.is_immediate()) {
+ // TODO: support more registers
+ DCHECK_LT(RegisterValue(*instruction.dest()), 16);
+ DCHECK_LT(source.value(), 16);
+ buffer_.push_back(art::Instruction::CONST_4 | (source.value() << 12) |
+ (RegisterValue(*instruction.dest()) << 8));
+ } else {
+ UNIMPLEMENTED(FATAL);
+ }
+}
+
+void MethodBuilder::EncodeInvokeVirtual(const Instruction& instruction) {
+ DCHECK_EQ(Instruction::Op::kInvokeVirtual, instruction.opcode());
+
+ // TODO: support more than one argument (i.e. the this argument) and change this to DCHECK_GE
+ DCHECK_EQ(1, instruction.args().size());
+
+ const Value& this_arg = instruction.args()[0];
+
+ size_t real_reg = RegisterValue(this_arg) & 0xf;
+ buffer_.push_back(1 << 12 | art::Instruction::INVOKE_VIRTUAL);
+ buffer_.push_back(instruction.method_id());
+ buffer_.push_back(real_reg);
+
+ if (instruction.dest().has_value()) {
+ real_reg = RegisterValue(*instruction.dest());
+ buffer_.push_back(real_reg << 8 | art::Instruction::MOVE_RESULT);
+ }
+}
+
+size_t MethodBuilder::RegisterValue(Value value) const {
+ if (value.is_register()) {
+ return value.value();
+ } else if (value.is_parameter()) {
+ return value.value() + num_registers_;
+ }
+ DCHECK(false && "Must be either a parameter or a register");
+ return 0;
+}
+
+const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
+ Prototype prototype) {
+ MethodDeclData& entry = method_id_map_[{type, name, prototype}];
+
+ if (entry.decl == nullptr) {
+ // This method has not already been declared, so declare it.
+ ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>();
+ // The method id is the last added method.
+ size_t id = dex_file_->methods.size() - 1;
+
+ ir::String* dex_name{GetOrAddString(name)};
+ decl->name = dex_name;
+ decl->parent = GetOrAddType(type.descriptor());
+ decl->prototype = GetOrEncodeProto(prototype);
+
+ // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
+ auto new_index = dex_file_->methods_indexes.AllocateIndex();
+ auto& ir_node = dex_file_->methods_map[new_index];
+ SLICER_CHECK(ir_node == nullptr);
+ ir_node = decl;
+ decl->orig_index = new_index;
+
+ entry = {id, decl};
+ }
+
+ return entry;
+}
+
+ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
+ ir::Proto*& ir_proto = proto_map_[prototype];
+ if (ir_proto == nullptr) {
+ ir_proto = prototype.Encode(this);
+ }
+ return ir_proto;
}
} // namespace dex
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index d280abc..e46655e 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -17,7 +17,9 @@
#define DEX_BUILDER_H_
#include <map>
+#include <optional>
#include <string>
+#include <unordered_map>
#include <vector>
#include "slicer/dex_ir.h"
@@ -45,7 +47,7 @@
virtual void Free(void* ptr);
private:
- std::map<void*, std::unique_ptr<uint8_t[]>> allocations_;
+ std::unordered_map<void*, std::unique_ptr<uint8_t[]>> allocations_;
};
// Represents a DEX type descriptor.
@@ -57,11 +59,17 @@
static const TypeDescriptor Int();
static const TypeDescriptor Void();
+ // Creates a type descriptor from a fully-qualified class name. For example, it turns the class
+ // name java.lang.Object into the descriptor Ljava/lang/Object.
+ static TypeDescriptor FromClassname(const std::string& name);
+
// Return the full descriptor, such as I or Ljava/lang/Object
const std::string& descriptor() const { return descriptor_; }
// Return the shorty descriptor, such as I or L
std::string short_descriptor() const { return descriptor().substr(0, 1); }
+ bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; }
+
private:
TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
@@ -82,11 +90,98 @@
// Get the shorty descriptor, such as VII for (Int, Int) -> Void
std::string Shorty() const;
+ bool operator<(const Prototype& rhs) const {
+ return std::make_tuple(return_type_, param_types_) <
+ std::make_tuple(rhs.return_type_, rhs.param_types_);
+ }
+
private:
const TypeDescriptor return_type_;
const std::vector<TypeDescriptor> param_types_;
};
+// Represents a DEX register or constant. We separate regular registers and parameters
+// because we will not know the real parameter id until after all instructions
+// have been generated.
+class Value {
+ public:
+ static constexpr Value Local(size_t id) { return Value{id, Kind::kLocalRegister}; }
+ static constexpr Value Parameter(size_t id) { return Value{id, Kind::kParameter}; }
+ static constexpr Value Immediate(size_t value) { return Value{value, Kind::kImmediate}; }
+
+ bool is_register() const { return kind_ == Kind::kLocalRegister; }
+ bool is_parameter() const { return kind_ == Kind::kParameter; }
+ bool is_immediate() const { return kind_ == Kind::kImmediate; }
+
+ size_t value() const { return value_; }
+
+ private:
+ enum class Kind { kLocalRegister, kParameter, kImmediate };
+
+ const size_t value_;
+ const Kind kind_;
+
+ constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
+};
+
+// A virtual instruction. We convert these to real instructions in MethodBuilder::Encode.
+// Virtual instructions are needed to keep track of information that is not known until all of the
+// code is generated. This information includes things like how many local registers are created and
+// branch target locations.
+class Instruction {
+ public:
+ // The operation performed by this instruction. These are virtual instructions that do not
+ // correspond exactly to DEX instructions.
+ enum class Op { kReturn, kMove, kInvokeVirtual };
+
+ ////////////////////////
+ // Named Constructors //
+ ////////////////////////
+
+ // For instructions with no return value and no arguments.
+ static inline Instruction OpNoArgs(Op opcode) {
+ return Instruction{opcode, /*method_id*/ 0, /*dest*/ {}};
+ }
+ // For most instructions, which take some number of arguments and have an optional return value.
+ template <typename... T>
+ static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
+ return Instruction{opcode, /*method_id*/ 0, dest, args...};
+ }
+ // For method calls.
+ template <typename... T>
+ static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
+ Value this_arg, T... args) {
+ return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...};
+ }
+
+ ///////////////
+ // Accessors //
+ ///////////////
+
+ Op opcode() const { return opcode_; }
+ size_t method_id() const { return method_id_; }
+ const std::optional<const Value>& dest() const { return dest_; }
+ const std::vector<const Value>& args() const { return args_; }
+
+ private:
+ inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest)
+ : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{} {}
+
+ template <typename... T>
+ inline constexpr Instruction(Op opcode, size_t method_id, std::optional<const Value> dest,
+ T... args)
+ : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{args...} {}
+
+ const Op opcode_;
+ // The index of the method to invoke, for kInvokeVirtual and similar opcodes.
+ const size_t method_id_{0};
+ const std::optional<const Value> dest_;
+ const std::vector<const Value> args_;
+};
+
+// Needed for CHECK_EQ, DCHECK_EQ, etc.
+std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode);
+
// Tools to help build methods and their bodies.
class MethodBuilder {
public:
@@ -95,42 +190,53 @@
// Encode the method into DEX format.
ir::EncodedMethod* Encode();
- // Registers are just represented by their number.
- using Register = size_t;
-
// Create a new register to be used to storing values. Note that these are not SSA registers, like
// might be expected in similar code generators. This does no liveness tracking or anything, so
// it's up to the caller to reuse registers as appropriate.
- Register MakeRegister();
+ Value MakeRegister();
/////////////////////////////////
// Instruction builder methods //
/////////////////////////////////
+ void AddInstruction(Instruction instruction);
+
// return-void
void BuildReturn();
- void BuildReturn(Register src);
+ void BuildReturn(Value src);
// const/4
- void BuildConst4(Register target, int value);
+ void BuildConst4(Value target, int value);
// TODO: add builders for more instructions
private:
+ void EncodeInstructions();
+ void EncodeInstruction(const Instruction& instruction);
+ void EncodeReturn(const Instruction& instruction);
+ void EncodeMove(const Instruction& instruction);
+ void EncodeInvokeVirtual(const Instruction& instruction);
+
+ // Converts a register or parameter to its DEX register number.
+ size_t RegisterValue(Value value) const;
+
DexBuilder* dex_;
ir::Class* class_;
ir::MethodDecl* decl_;
- // A buffer to hold instructions we are generating.
+ // A list of the instructions we will eventually encode.
+ std::vector<Instruction> instructions_;
+
+ // A buffer to hold instructions that have been encoded.
std::vector<::dex::u2> buffer_;
// How many registers we've allocated
- size_t num_registers_;
+ size_t num_registers_{0};
};
// A helper to build class definitions.
class ClassBuilder {
public:
- ClassBuilder(DexBuilder* parent, ir::Class* class_def);
+ ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def);
void set_source_file(const std::string& source);
@@ -139,8 +245,15 @@
MethodBuilder CreateMethod(const std::string& name, Prototype prototype);
private:
- DexBuilder* parent_;
- ir::Class* class_;
+ DexBuilder* const parent_;
+ const TypeDescriptor type_descriptor_;
+ ir::Class* const class_;
+};
+
+// Keeps track of information needed to manipulate or call a method.
+struct MethodDeclData {
+ size_t id;
+ ir::MethodDecl* decl;
};
// Builds Dex files from scratch.
@@ -163,10 +276,19 @@
ClassBuilder MakeClass(const std::string& name);
// Add a type for the given descriptor, or return the existing one if it already exists.
- // See the TypeDescriptor class for help generating these.
+ // See the TypeDescriptor class for help generating these. GetOrAddType can be used to declare
+ // imported classes.
ir::Type* GetOrAddType(const std::string& descriptor);
+ // Returns the method id for the method, creating it if it has not been created yet.
+ const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
+ Prototype prototype);
+
private:
+ // Looks up the ir::Proto* corresponding to this given prototype, or creates one if it does not
+ // exist.
+ ir::Proto* GetOrEncodeProto(Prototype prototype);
+
std::shared_ptr<ir::DexFile> dex_file_;
// allocator_ is needed to be able to encode the image.
@@ -177,10 +299,29 @@
std::vector<std::unique_ptr<uint8_t[]>> string_data_;
// Keep track of what types we've defined so we can look them up later.
- std::map<std::string, ir::Type*> types_by_descriptor_;
+ std::unordered_map<std::string, ir::Type*> types_by_descriptor_;
+
+ struct MethodDescriptor {
+ TypeDescriptor type;
+ std::string name;
+ Prototype prototype;
+
+ inline bool operator<(const MethodDescriptor& rhs) const {
+ return std::make_tuple(type, name, prototype) <
+ std::make_tuple(rhs.type, rhs.name, rhs.prototype);
+ }
+ };
+
+ // Maps method declarations to their method index. This is needed to encode references to them.
+ // When we go to actually write the DEX file, slicer will re-assign these after correctly sorting
+ // the methods list.
+ std::map<MethodDescriptor, MethodDeclData> method_id_map_;
// Keep track of what strings we've defined so we can look them up later.
- std::map<std::string, ir::String*> strings_;
+ std::unordered_map<std::string, ir::String*> strings_;
+
+ // Keep track of already-encoded protos.
+ std::map<Prototype, ir::Proto*> proto_map_;
};
} // namespace dex
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
index 0d8b854..61c86b4 100644
--- a/startop/view_compiler/dex_builder_test.cc
+++ b/startop/view_compiler/dex_builder_test.cc
@@ -40,6 +40,12 @@
return loaded_dex_file != nullptr;
}
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static void foo() {}
+// }
TEST(DexBuilderTest, VerifyDexWithClassMethod) {
DexBuilder dex_file;
@@ -67,6 +73,12 @@
EXPECT_FALSE(EncodeAndVerify(&dex_file));
}
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo() { return 5; }
+// }
TEST(DexBuilderTest, VerifyDexReturn5) {
DexBuilder dex_file;
@@ -80,3 +92,51 @@
EXPECT_TRUE(EncodeAndVerify(&dex_file));
}
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo(int x) { return x; }
+// }
+TEST(DexBuilderTest, VerifyDexReturnIntParam) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ auto method{
+ cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+ method.BuildReturn(Value::Parameter(0));
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo(String s) { return s.length(); }
+// }
+TEST(DexBuilderTest, VerifyDexCallStringLength) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ MethodBuilder method{cbuilder.CreateMethod(
+ "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})};
+
+ Value result = method.MakeRegister();
+
+ MethodDeclData string_length =
+ dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
+ "length",
+ Prototype{TypeDescriptor::Int()});
+
+ method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+ method.BuildReturn(result);
+
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index f62b170..7db6940 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -18,6 +18,7 @@
import android.annotation.SdkConstant;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
@@ -229,7 +230,8 @@
callDetails.getTelecomCallId(),
response.getRejectCall(),
!response.getSkipCallLog(),
- !response.getSkipNotification());
+ !response.getSkipNotification(),
+ new ComponentName(getPackageName(), getClass().getName()));
} else {
mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index 2e0af279..d255ed1 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -16,6 +16,8 @@
package com.android.internal.telecom;
+import android.content.ComponentName;
+
/**
* Internal remote callback interface for call screening services.
*
@@ -30,5 +32,6 @@
String callId,
boolean shouldReject,
boolean shouldAddToCallLog,
- boolean shouldShowNotification);
+ boolean shouldShowNotification,
+ in ComponentName componentName);
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index d7024cf..61d60e3 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2756,6 +2756,13 @@
"content://telephony/carriers/enforce_managed");
/**
+ * The {@code content://} style URL to be called from Telephony to query current APNs.
+ * @hide
+ */
+ public static final Uri SIM_APN_LIST = Uri.parse(
+ "content://telephony/carriers/sim_apn_list");
+
+ /**
* The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
* @hide
*/
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index cac9f2b..9c64cf6 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -32,7 +32,20 @@
public static final int IWLAN = 5;
/** @hide */
- private AccessNetworkType() {};
+ private AccessNetworkType() {}
+
+ /** @hide */
+ public static String toString(int type) {
+ switch (type) {
+ case UNKNOWN: return "UNKNOWN";
+ case GERAN: return "GERAN";
+ case UTRAN: return "UTRAN";
+ case EUTRAN: return "EUTRAN";
+ case CDMA2000: return "CDMA2000";
+ case IWLAN: return "IWLAN";
+ default: return Integer.toString(type);
+ }
+ }
}
/**
@@ -47,7 +60,16 @@
public static final int WLAN = 2;
/** @hide */
- private TransportType() {};
+ private TransportType() {}
+
+ /** @hide */
+ public static String toString(int type) {
+ switch (type) {
+ case WWAN: return "WWAN";
+ case WLAN: return "WLAN";
+ default: return Integer.toString(type);
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 983e766..3f9a533 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1231,6 +1231,38 @@
public static final String KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL =
"show_precise_failed_cause_bool";
+ /**
+ * Boolean to decide whether lte is enabled.
+ * @hide
+ */
+ public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
+
+ /**
+ * Boolean to decide whether TD-SCDMA is supported.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
+
+ /**
+ * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY =
+ "support_tdscdma_roaming_networks_string_array";
+
+ /**
+ * Boolean to decide whether world mode is enabled.
+ * @hide
+ */
+ public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
+
+ /**
+ * Flatten {@link android.content.ComponentName} of the carrier's settings activity.
+ * @hide
+ */
+ public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
+ "carrier_settings_activity_component_name_string";
+
// These variables are used by the MMS service and exposed through another API,
// SmsManager. The variable names and string values are copied from there.
public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -2570,6 +2602,11 @@
sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
+ sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
+ sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
+ sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_WORLD_MODE_ENABLED_BOOL, false);
+ sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING, "");
sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 76a0026..6958d22 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -190,6 +190,7 @@
case CellInfo.TYPE_LTE: return CellIdentityLte.createFromParcelBody(in);
case CellInfo.TYPE_TDSCDMA:
return CellIdentityTdscdma.createFromParcelBody(in);
+ case CellInfo.TYPE_NR: return CellIdentityNr.createFromParcelBody(in);
default: throw new IllegalArgumentException("Bad Cell identity Parcel");
}
}
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
new file mode 100644
index 0000000..6b1b84c
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+import android.telephony.gsm.GsmCellLocation;
+
+import java.util.Objects;
+
+/**
+ * Information to represent a unique 5G NR cell.
+ */
+public final class CellIdentityNr extends CellIdentity {
+ private static final String TAG = "CellIdentityNr";
+
+ private final int mNrArfcn;
+ private final int mPci;
+ private final int mTac;
+
+ /**
+ *
+ * @param pci Physical Cell Id in range [0, 1007].
+ * @param tac 16-bit Tracking Area Code.
+ * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
+ * @param mccStr 3-digit Mobile Country Code in string format.
+ * @param mncStr 2 or 3-digit Mobile Network Code in string format.
+ * @param alphal long alpha Operator Name String or Enhanced Operator Name String.
+ * @param alphas short alpha Operator Name String or Enhanced Operator Name String.
+ *
+ * @hide
+ */
+ public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
+ String alphal, String alphas) {
+ super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
+ mPci = pci;
+ mTac = tac;
+ mNrArfcn = nrArfcn;
+ }
+
+ /**
+ * @return a CellLocation object for this CellIdentity.
+ * @hide
+ */
+ @Override
+ public CellLocation asCellLocation() {
+ return new GsmCellLocation();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CellIdentityNr)) {
+ return false;
+ }
+
+ CellIdentityNr o = (CellIdentityNr) other;
+ return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn;
+ }
+
+ /**
+ * Get the Absolute Radio Frequency Channel Number.
+ * @return Integer value in range [0, 3279165] or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ @Override
+ public int getChannelNumber() {
+ return mNrArfcn;
+ }
+
+ /**
+ * Get the physical cell id.
+ * @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ public int getPci() {
+ return mPci;
+ }
+
+ /**
+ * Get the tracking area code.
+ * @return a 16 bit integer or {@link CellInfo#UNAVAILABLE} if unknown.
+ */
+ public int getTac() {
+ return mTac;
+ }
+
+ /**
+ * @return Mobile Country Code in string format, or {@code null} if unknown.
+ */
+ public String getMccString() {
+ return mMccStr;
+ }
+
+ /**
+ * @return Mobile Network Code in string fomrat, or {@code null} if unknown.
+ */
+ public String getMncString() {
+ return mMncStr;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(TAG + ":{")
+ .append(" mPci = ").append(mPci)
+ .append(" mTac = ").append(mTac)
+ .append(" mNrArfcn = ").append(mNrArfcn)
+ .append(" mMcc = ").append(mMccStr)
+ .append(" mMnc = ").append(mMncStr)
+ .append(" mAlphaLong = ").append(mAlphaLong)
+ .append(" mAlphaShort = ").append(mAlphaShort)
+ .append(" }")
+ .toString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int type) {
+ super.writeToParcel(dest, CellInfo.TYPE_NR);
+ dest.writeInt(mPci);
+ dest.writeInt(mTac);
+ dest.writeInt(mNrArfcn);
+ }
+
+ /** Construct from Parcel, type has already been processed */
+ private CellIdentityNr(Parcel in) {
+ super(TAG, CellInfo.TYPE_NR, in);
+ mPci = in.readInt();
+ mTac = in.readInt();
+ mNrArfcn = in.readInt();
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<CellIdentityNr> CREATOR =
+ new Creator<CellIdentityNr>() {
+ @Override
+ public CellIdentityNr createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
+ return createFromParcelBody(in);
+ }
+
+ @Override
+ public CellIdentityNr[] newArray(int size) {
+ return new CellIdentityNr[size];
+ }
+ };
+
+ /** @hide */
+ protected static CellIdentityNr createFromParcelBody(Parcel in) {
+ return new CellIdentityNr(in);
+ }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 1c63e82..d0b26876 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -42,38 +42,51 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "TYPE_", value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA})
+ @IntDef(prefix = "TYPE_",
+ value = {TYPE_GSM, TYPE_CDMA, TYPE_LTE, TYPE_WCDMA, TYPE_TDSCDMA, TYPE_NR})
public @interface Type {}
+
/**
* Unknown cell identity type
* @hide
*/
- public static final int TYPE_UNKNOWN = 0;
+ public static final int TYPE_UNKNOWN = 0;
+
/**
* GSM cell identity type
* @hide
*/
- public static final int TYPE_GSM = 1;
+ public static final int TYPE_GSM = 1;
+
/**
* CDMA cell identity type
* @hide
*/
- public static final int TYPE_CDMA = 2;
+ public static final int TYPE_CDMA = 2;
+
/**
* LTE cell identity type
* @hide
*/
- public static final int TYPE_LTE = 3;
+ public static final int TYPE_LTE = 3;
+
/**
* WCDMA cell identity type
* @hide
*/
- public static final int TYPE_WCDMA = 4;
+ public static final int TYPE_WCDMA = 4;
+
/**
* TD-SCDMA cell identity type
* @hide
*/
- public static final int TYPE_TDSCDMA = 5;
+ public static final int TYPE_TDSCDMA = 5;
+
+ /**
+ * 5G cell identity type
+ * @hide
+ */
+ public static final int TYPE_NR = 6;
// Type to distinguish where time stamp gets recorded.
@@ -277,6 +290,7 @@
case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
case TYPE_TDSCDMA: return CellInfoTdscdma.createFromParcelBody(in);
+ case TYPE_NR: return CellInfoNr.createFromParcelBody(in);
default: throw new RuntimeException("Bad CellInfo Parcel");
}
}
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
new file mode 100644
index 0000000..11857a6
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * A {@link CellInfo} representing an 5G NR cell that provides identity and measurement info.
+ */
+public final class CellInfoNr extends CellInfo {
+ private static final String TAG = "CellInfoNr";
+
+ private final CellIdentityNr mCellIdentity;
+ private final CellSignalStrengthNr mCellSignalStrength;
+
+ private CellInfoNr(Parcel in) {
+ super(in);
+ mCellIdentity = CellIdentityNr.CREATOR.createFromParcel(in);
+ mCellSignalStrength = CellSignalStrengthNr.CREATOR.createFromParcel(in);
+ }
+
+ @Override
+ public CellIdentity getCellIdentity() {
+ return mCellIdentity;
+ }
+
+ @Override
+ public CellSignalStrength getCellSignalStrength() {
+ return mCellSignalStrength;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), mCellIdentity, mCellSignalStrength);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CellInfoNr)) {
+ return false;
+ }
+
+ CellInfoNr o = (CellInfoNr) other;
+ return super.equals(o) && mCellIdentity.equals(o.mCellIdentity)
+ && mCellSignalStrength.equals(o.mCellSignalStrength);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append(TAG + ":{")
+ .append(" " + super.toString())
+ .append(" " + mCellIdentity)
+ .append(" " + mCellSignalStrength)
+ .append(" }")
+ .toString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags, TYPE_NR);
+ mCellIdentity.writeToParcel(dest, flags);
+ mCellSignalStrength.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<CellInfoNr> CREATOR = new Creator<CellInfoNr>() {
+ @Override
+ public CellInfoNr createFromParcel(Parcel in) {
+ // Skip the type info.
+ in.readInt();
+ return new CellInfoNr(in);
+ }
+
+ @Override
+ public CellInfoNr[] newArray(int size) {
+ return new CellInfoNr[size];
+ }
+ };
+
+ /** @hide */
+ protected static CellInfoNr createFromParcelBody(Parcel in) {
+ return new CellInfoNr(in);
+ }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index d6856b3..2ff75e6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -19,7 +19,6 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Rlog;
import java.util.Objects;
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
new file mode 100644
index 0000000..8079242
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * 5G NR signal strength related information.
+ */
+public final class CellSignalStrengthNr extends CellSignalStrength implements Parcelable {
+ /**
+ * The value is used to indicate that the asu level is unknown.
+ * Reference: 3GPP TS 27.007 section 8.69.
+ * @hide
+ */
+ public static final int UNKNOWN_ASU_LEVEL = 99;
+
+ private static final String TAG = "CellSignalStrengthNr";
+
+ /**
+ * These threshold values are copied from LTE.
+ * TODO: make it configurable via CarrierConfig.
+ */
+ private static final int SIGNAL_GREAT_THRESHOLD = -95;
+ private static final int SIGNAL_GOOD_THRESHOLD = -105;
+ private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+
+ private int mCsiRsrp;
+ private int mCsiRsrq;
+ private int mCsiSinr;
+ private int mSsRsrp;
+ private int mSsRsrq;
+ private int mSsSinr;
+
+ /**
+ * @param csiRsrp CSI reference signal received power.
+ * @param csiRsrq CSI reference signal received quality.
+ * @param csiSinr CSI signal-to-noise and interference ratio.
+ * @param ssRsrp SS reference signal received power.
+ * @param ssRsrq SS reference signal received quality.
+ * @param ssSinr SS signal-to-noise and interference ratio.
+ * @hide
+ */
+ public CellSignalStrengthNr(
+ int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
+ mCsiRsrp = csiRsrp;
+ mCsiRsrq = csiRsrq;
+ mCsiSinr = csiSinr;
+ mSsRsrp = ssRsrp;
+ mSsRsrq = ssRsrq;
+ mSsSinr = ssSinr;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -140 dBm to -44 dBm.
+ * @return SS reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getSsRsrp() {
+ return mSsRsrp;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -20 dB to -3 dB.
+ * @return SS reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getSsRsrq() {
+ return mSsRsrq;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+ * Range: -23 dB to 40 dB
+ * @return SS signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+ * unreported value.
+ */
+ public int getSsSinr() {
+ return mSsSinr;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -140 dBm to -44 dBm.
+ * @return CSI reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getCsiRsrp() {
+ return mCsiRsrp;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215.
+ * Range: -20 dB to -3 dB.
+ * @return CSI reference signal received quality, {@link CellInfo#UNAVAILABLE} means unreported
+ * value.
+ */
+ public int getCsiRsrq() {
+ return mCsiRsrq;
+ }
+
+ /**
+ * Reference: 3GPP TS 38.215 Sec 5.1.*, 3GPP TS 38.133 10.1.16.1
+ * Range: -23 dB to 23 dB
+ * @return CSI signal-to-noise and interference ratio, {@link CellInfo#UNAVAILABLE} means
+ * unreported value.
+ */
+ public int getCsiSinr() {
+ return mCsiSinr;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mCsiRsrp);
+ dest.writeInt(mCsiRsrq);
+ dest.writeInt(mCsiSinr);
+ dest.writeInt(mSsRsrp);
+ dest.writeInt(mSsRsrq);
+ dest.writeInt(mSsSinr);
+ }
+
+ private CellSignalStrengthNr(Parcel in) {
+ mCsiRsrp = in.readInt();
+ mCsiRsrq = in.readInt();
+ mCsiSinr = in.readInt();
+ mSsRsrp = in.readInt();
+ mSsRsrq = in.readInt();
+ mSsSinr = in.readInt();
+ }
+
+ /** @hide */
+ @Override
+ public void setDefaultValues() {
+ mCsiRsrp = CellInfo.UNAVAILABLE;
+ mCsiRsrq = CellInfo.UNAVAILABLE;
+ mCsiSinr = CellInfo.UNAVAILABLE;
+ mSsRsrp = CellInfo.UNAVAILABLE;
+ mSsRsrq = CellInfo.UNAVAILABLE;
+ mSsSinr = CellInfo.UNAVAILABLE;
+ }
+
+ @Override
+ public int getLevel() {
+ if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+ return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+ return SIGNAL_STRENGTH_GREAT;
+ } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+ return SIGNAL_STRENGTH_GOOD;
+ } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+ return SIGNAL_STRENGTH_MODERATE;
+ } else {
+ return SIGNAL_STRENGTH_POOR;
+ }
+ }
+
+ /**
+ * Calculates the NR signal as an asu value between 0..97, 99 is unknown.
+ * Asu is calculated based on 3GPP RSRP, refer to 3GPP TS 27.007 section 8.69.
+ * @return an integer represent the asu level of the signal strength.
+ */
+ @Override
+ public int getAsuLevel() {
+ int asuLevel;
+ int nrDbm = getDbm();
+ if (nrDbm == CellInfo.UNAVAILABLE) {
+ asuLevel = UNKNOWN_ASU_LEVEL;
+ } else if (nrDbm <= -140) {
+ asuLevel = 0;
+ } else if (nrDbm >= -43) {
+ asuLevel = 97;
+ } else {
+ asuLevel = nrDbm + 140;
+ }
+ return asuLevel;
+ }
+
+ @Override
+ public int getDbm() {
+ return mCsiRsrp;
+ }
+
+ /** @hide */
+ @Override
+ public CellSignalStrength copy() {
+ return new CellSignalStrengthNr(
+ mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CellSignalStrengthNr) {
+ CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
+ return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
+ && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append(TAG + ":{")
+ .append(" csiRsrp = " + mCsiRsrp)
+ .append(" csiRsrq = " + mCsiRsrq)
+ .append(" csiSinr = " + mCsiSinr)
+ .append(" ssRsrp = " + mSsRsrp)
+ .append(" ssRsrq = " + mSsRsrq)
+ .append(" ssSinr = " + mSsSinr)
+ .append(" }")
+ .toString();
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<CellSignalStrengthNr> CREATOR =
+ new Parcelable.Creator<CellSignalStrengthNr>() {
+ @Override
+ public CellSignalStrengthNr createFromParcel(Parcel in) {
+ return new CellSignalStrengthNr(in);
+ }
+
+ @Override
+ public CellSignalStrengthNr[] newArray(int size) {
+ return new CellSignalStrengthNr[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index d7169b2..c6887ab 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -342,6 +342,12 @@
*/
public static final int TOO_MANY_ONGOING_CALLS = 75;
+ /**
+ * Indicates that a new outgoing call cannot be placed because OTASP provisioning is currently
+ * in process.
+ */
+ public static final int OTASP_PROVISIONING_IN_PROCESS = 76;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -505,6 +511,8 @@
return "CALLING_DISABLED";
case TOO_MANY_ONGOING_CALLS:
return "TOO_MANY_ONGOING_CALLS";
+ case OTASP_PROVISIONING_IN_PROCESS:
+ return "OTASP_PROVISIONING_IN_PROCESS";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0ba18ee..31770ec 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -51,6 +51,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.euicc.EuiccManager;
+import android.telephony.ims.ImsMmTelManager;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -134,7 +135,7 @@
* A content {@link Uri} used to receive updates on wfc enabled user setting.
* <p>
* Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
- * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+ * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()}
* while your app is running. You can also use a {@link JobService} to ensure your app
* is notified of changes to the {@link Uri} even when it is not running.
* Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -147,10 +148,28 @@
public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
/**
- * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+ * A content {@link Uri} used to receive updates on advanced calling user setting.
* <p>
* Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
- * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * subscription advanced calling enabled
+ * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running.
+ * You can also use a {@link JobService} to ensure your app is notified of changes to the
+ * {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri ADVANCED_CALLING_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "advanced_calling");
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc mode setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()}
* while your app is running. You can also use a {@link JobService} to ensure your app
* is notified of changes to the {@link Uri} even when it is not running.
* Note, however, that using a {@link JobService} does not guarantee timely delivery of
@@ -160,9 +179,59 @@
* @hide
*/
@SystemApi
- public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
- CONTENT_URI, "enhanced_4g");
+ public static final Uri WFC_MODE_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc_mode");
+ /**
+ * A content {@link Uri} used to receive updates on wfc roaming mode setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ROAMING_MODE_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "wfc_roaming_mode");
+
+ /**
+ * A content {@link Uri} used to receive updates on vt(video telephony over IMS) enabled
+ * setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri VT_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "vt_enabled");
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc roaming enabled setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ROAMING_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "wfc_roaming_enabled");
/**
* TelephonyProvider unique key column name is the subscription id.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8a77f14..8414ed3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1285,9 +1285,10 @@
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*
@@ -1295,7 +1296,7 @@
* MEID for CDMA.
*/
@Deprecated
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId() {
try {
@@ -1314,9 +1315,10 @@
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*
@@ -1326,7 +1328,7 @@
* MEID for CDMA.
*/
@Deprecated
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
@@ -1346,13 +1348,14 @@
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*/
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei() {
return getImei(getSlotIndex());
@@ -1362,15 +1365,16 @@
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*
* @param slotIndex of which IMEI is returned
*/
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
@@ -1415,13 +1419,14 @@
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*/
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid() {
return getMeid(getSlotIndex());
@@ -1430,15 +1435,16 @@
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
- * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app
- * that owns a managed profile on the device; for more details see <a
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
+ * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
+ * managed profile on the device; for more details see <a
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*
* @param slotIndex of which MEID is returned
*/
- @SuppressAutoDoc // No support for device / profile owner.
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid(int slotIndex) {
ITelephony telephony = getITelephony();
@@ -2936,7 +2942,7 @@
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
@@ -3098,7 +3104,7 @@
* href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
* access is deprecated and will be removed in a future release.
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSubscriberId() {
return getSubscriberId(getSubId());
@@ -8286,6 +8292,28 @@
}
/**
+ * Returns MNO carrier id of the current subscription’s MCCMNC.
+ * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used
+ * for MNO fallback when exact carrier id {@link #getSimCarrierId()}
+ * configurations are not found.
+ *
+ * @return MNO carrier id of the current subscription. Return the value same as carrier id
+ * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified.
+ * @hide
+ */
+ public int getSimMNOCarrierId() {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getSubscriptionMNOCarrierId(getSubId());
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return UNKNOWN_CARRIER_ID;
+ }
+
+ /**
* Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
* All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
* <p>Requires Permission:
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index aabefe3..2e9bffe 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1184,6 +1184,16 @@
}
/**
+ * @param apnType APN type
+ * @return APN type in string format
+ * @hide
+ */
+ public static String getApnTypeString(int apnType) {
+ String apnTypeString = APN_TYPE_INT_MAP.get(apnType);
+ return apnTypeString == null ? "Unknown" : apnTypeString;
+ }
+
+ /**
* @param types comma delimited list of APN types.
* @return bitmask of APN types.
* @hide
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 1141177..3b1ef3f 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -15,6 +15,7 @@
*/
package android.telephony.euicc;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -50,7 +51,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import android.annotation.CallbackExecutor;
import java.util.concurrent.Executor;
/**
@@ -119,6 +119,9 @@
/** Result code when the eUICC card with the given card Id is not found. */
public static final int RESULT_EUICC_NOT_FOUND = -2;
+ /** Result code indicating the caller is not the active LPA. */
+ public static final int RESULT_CALLER_NOT_ALLOWED = -3;
+
/**
* Callback to receive the result of an eUICC card API.
*
@@ -152,7 +155,7 @@
* Requests all the profiles on eUicc.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code and all the profiles.
*/
public void requestAllProfiles(String cardId, @CallbackExecutor Executor executor,
@@ -176,7 +179,7 @@
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code and profile.
*/
public void requestProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -201,7 +204,7 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param refresh Whether sending the REFRESH command to modem.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code.
*/
public void disableProfile(String cardId, String iccid, boolean refresh,
@@ -227,7 +230,7 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile to switch to.
* @param refresh Whether sending the REFRESH command to modem.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code and the EuiccProfileInfo enabled.
*/
public void switchToProfile(String cardId, String iccid, boolean refresh,
@@ -252,7 +255,7 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param nickname The nickname of the profile.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code.
*/
public void setNickname(String cardId, String iccid, String nickname,
@@ -276,7 +279,7 @@
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code.
*/
public void deleteProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -301,7 +304,7 @@
* @param cardId The Id of the eUICC.
* @param options Bits of the options of resetting which parts of the eUICC memory. See
* EuiccCard for details.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code.
*/
public void resetMemory(String cardId, @ResetOption int options,
@@ -324,7 +327,7 @@
* Requests the default SM-DP+ address from eUICC.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code and the default SM-DP+ address.
*/
public void requestDefaultSmdpAddress(String cardId, @CallbackExecutor Executor executor,
@@ -347,7 +350,7 @@
* Requests the SM-DS address from eUICC.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code and the SM-DS address.
*/
public void requestSmdsAddress(String cardId, @CallbackExecutor Executor executor,
@@ -371,7 +374,7 @@
*
* @param cardId The Id of the eUICC.
* @param defaultSmdpAddress The default SM-DP+ address to set.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback The callback to get the result code.
*/
public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress,
@@ -395,7 +398,7 @@
* Requests Rules Authorisation Table.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the rule authorisation table.
*/
public void requestRulesAuthTable(String cardId, @CallbackExecutor Executor executor,
@@ -418,7 +421,7 @@
* Requests the eUICC challenge for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the challenge.
*/
public void requestEuiccChallenge(String cardId, @CallbackExecutor Executor executor,
@@ -441,7 +444,7 @@
* Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the info1.
*/
public void requestEuiccInfo1(String cardId, @CallbackExecutor Executor executor,
@@ -464,7 +467,7 @@
* Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the info2.
*/
public void requestEuiccInfo2(String cardId, @CallbackExecutor Executor executor,
@@ -497,7 +500,7 @@
* GSMA RSP v2.0+.
* @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by
* SM-DP+ server.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and a byte array which represents a
* {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+.
*/
@@ -537,7 +540,7 @@
* SM-DP+ server.
* @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned
* by SM-DP+ server.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and a byte array which represents a
* {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+
*/
@@ -569,7 +572,7 @@
*
* @param cardId The Id of the eUICC.
* @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and a byte array which represents a
* {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+.
*/
@@ -598,7 +601,7 @@
* @param cardId The Id of the eUICC.
* @param transactionId the transaction ID returned by SM-DP+ server.
* @param reason the cancel reason.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and an byte[] which represents a
* {@code CancelSessionResponse} defined in GSMA RSP v2.0+.
*/
@@ -627,7 +630,7 @@
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the list of notifications.
*/
public void listNotifications(String cardId, @EuiccNotification.Event int events,
@@ -651,7 +654,7 @@
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the list of notifications.
*/
public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events,
@@ -675,7 +678,7 @@
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code and the notification.
*/
public void retrieveNotification(String cardId, int seqNumber,
@@ -699,7 +702,7 @@
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
- * @param executor The executor through which the callback should be invode.
+ * @param executor The executor through which the callback should be invoke.
* @param callback the callback to get the result code.
*/
public void removeNotificationFromList(String cardId, int seqNumber,
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 89ef339..f73036e 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -16,17 +16,20 @@
package android.telephony.ims;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.PersistableBundle;
import android.telecom.VideoProfile;
import android.util.Log;
import com.android.internal.telephony.PhoneConstants;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Parcelable object to handle IMS call profile.
* It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
@@ -206,17 +209,36 @@
public static final int DIALSTRING_USSD = 2;
/**
- * Values for causes that restrict call types
+ * Call is not restricted on peer side and High Definition media is supported
*/
- // Default cause not restricted at peer and HD is supported
public static final int CALL_RESTRICT_CAUSE_NONE = 0;
- // Service not supported by RAT at peer
+
+ /**
+ * High Definition media is not supported on the peer side due to the Radio Access Technology
+ * (RAT) it is are connected to.
+ */
public static final int CALL_RESTRICT_CAUSE_RAT = 1;
- // Service Disabled at peer
+
+ /**
+ * The service has been disabled on the peer side.
+ */
public static final int CALL_RESTRICT_CAUSE_DISABLED = 2;
- // HD is not supported
+
+ /**
+ * High definition media is not currently supported.
+ */
public static final int CALL_RESTRICT_CAUSE_HD = 3;
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CALL_RESTRICT_CAUSE_", value = {
+ CALL_RESTRICT_CAUSE_NONE,
+ CALL_RESTRICT_CAUSE_RAT,
+ CALL_RESTRICT_CAUSE_DISABLED,
+ CALL_RESTRICT_CAUSE_HD
+ })
+ public @interface CallRestrictCause {}
+
/**
* String extra properties
* oi : Originating identity (number), MT only
@@ -270,7 +292,7 @@
public int mCallType;
/** @hide */
@UnsupportedAppUsage
- public int mRestrictCause = CALL_RESTRICT_CAUSE_NONE;
+ public @CallRestrictCause int mRestrictCause = CALL_RESTRICT_CAUSE_NONE;
/**
* Extras associated with this {@link ImsCallProfile}.
@@ -285,7 +307,7 @@
* <li>{@code long[]}</li>
* <li>{@code double[]}</li>
* <li>{@code String[]}</li>
- * <li>{@link PersistableBundle}</li>
+ * <li>{@link android.os.PersistableBundle}</li>
* <li>{@link Boolean} (and boolean)</li>
* <li>{@code boolean[]}</li>
* <li>Other {@link Parcelable} classes in the {@code android.*} namespace.</li>
@@ -426,6 +448,14 @@
}
}
+ /**
+ * Set the call restrict cause, which provides the reason why a call has been restricted from
+ * using High Definition media.
+ */
+ public void setCallRestrictCause(@CallRestrictCause int cause) {
+ mRestrictCause = cause;
+ }
+
public void updateCallType(ImsCallProfile profile) {
mCallType = profile.mCallType;
}
@@ -494,7 +524,11 @@
return mCallType;
}
- public int getRestrictCause() {
+ /**
+ * @return The call restrict cause, which provides the reason why a call has been restricted
+ * from using High Definition media.
+ */
+ public @CallRestrictCause int getRestrictCause() {
return mRestrictCause;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b20b164..682141f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1311,6 +1311,18 @@
String getSubscriptionCarrierName(int subId);
/**
+ * Returns MNO carrier id of the current subscription’s MCCMNC.
+ * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used
+ * for MNO fallback when exact carrier id {@link #getSimCarrierId()}
+ * configurations are not found.
+ *
+ * @return MNO carrier id of the current subscription. Return the value same as carrier id
+ * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified.
+ * @hide
+ */
+ int getSubscriptionMNOCarrierId(int subId);
+
+ /**
* Action set from carrier signalling broadcast receivers to enable/disable metered apns
* Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
* @param subId the subscription ID that this action applies to.
diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
index 95f39d7..d07d77c 100644
--- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java
+++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.CellInfo;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -106,6 +107,17 @@
}
@Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{")
+ .append("scanStatus=" + scanStatus)
+ .append(", scanError=" + scanError)
+ .append(", networkInfos=" + networkInfos)
+ .append("}")
+ .toString();
+ }
+
+ @Override
public int hashCode () {
return ((scanStatus * 31)
+ (scanError * 23)
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index eb6be65..553e3fb 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -188,6 +188,13 @@
if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
return true;
}
+ // Calling packages with carrier privileges will also have access to device identifiers, but
+ // this may be removed in a future release.
+ if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus(
+ TELEPHONY_SUPPLIER, subId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
// else the calling package is not authorized to access the device identifiers; call
// a central method to report the failure based on the target SDK and if the calling package
// has the READ_PHONE_STATE permission or carrier privileges that were previously required
@@ -279,44 +286,51 @@
int uid, String callingPackage, String message) {
Log.wtf(LOG_TAG,
"reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
- // if the device identifier check is relaxed then revert to the READ_PHONE_STATE permission
- // check that was previously required to access device identifiers.
- boolean relaxDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 0;
- if (relaxDeviceIdentifierCheck) {
- return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
- } else {
+ // If the device identifier check is enabled then enforce the new access requirements for
+ // both 1P and 3P apps.
+ boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 1;
+ // Check if the application is a 3P app; if so then a separate setting is required to relax
+ // the check to begin flagging problems with 3P apps early.
+ boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, 0) == 1;
+ boolean is3PApp = true;
+ ApplicationInfo callingPackageInfo = null;
+ try {
+ callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+ if (callingPackageInfo.isSystemApp()) {
+ is3PApp = false;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // If the application info for the calling package could not be found then assume the
+ // calling app is a 3P app to detect any issues with the check
+ }
+ if (enableDeviceIdentifierCheck || (is3PApp && !relax3PDeviceIdentifierCheck)) {
boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
if (callingPackage != null) {
- try {
- // if the target SDK is pre-Q or the target Q behavior is disabled then check if
- // the calling package would have previously had access to device identifiers.
- ApplicationInfo callingPackageInfo =
- context.getPackageManager().getApplicationInfo(
- callingPackage, 0);
- if (callingPackageInfo != null && (
- callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
- || targetQBehaviorDisabled)) {
- if (context.checkPermission(
- android.Manifest.permission.READ_PHONE_STATE,
- pid,
- uid) == PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- if (SubscriptionManager.isValidSubscriptionId(subId)
- && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return false;
- }
+ // if the target SDK is pre-Q or the target Q behavior is disabled then check if
+ // the calling package would have previously had access to device identifiers.
+ if (callingPackageInfo != null && (
+ callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
+ || targetQBehaviorDisabled)) {
+ if (context.checkPermission(
+ android.Manifest.permission.READ_PHONE_STATE,
+ pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return false;
}
- } catch (PackageManager.NameNotFoundException e) {
- // If the application info for the calling package could not be found then
- // default to throwing the SecurityException.
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return false;
+ }
}
}
throw new SecurityException(message + ": The user " + uid
+ " does not meet the requirements to access device identifiers.");
+ } else {
+ return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
}
}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 04266c5..b9222a8 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -17,8 +17,8 @@
package android.net;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest;
@@ -252,6 +252,39 @@
}
}
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
static byte[] toByteArray(int... in) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index dfe31bd..bf42412 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -31,6 +31,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
+import android.net.NetworkMisc;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.test.TestLooper;
@@ -55,6 +56,7 @@
static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
@Mock ConnectivityService mConnectivity;
+ @Mock NetworkMisc mMisc;
@Mock INetworkManagementService mNms;
@Mock InterfaceConfiguration mConfig;
@Mock NetworkAgentInfo mNai;
@@ -78,6 +80,7 @@
mNai.networkInfo = new NetworkInfo(null);
mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
when(mNai.connService()).thenReturn(mConnectivity);
+ when(mNai.netMisc()).thenReturn(mMisc);
when(mNai.handler()).thenReturn(mHandler);
when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
@@ -103,9 +106,16 @@
mNai.networkInfo.setType(type);
for (NetworkInfo.DetailedState state : supportedDetailedStates) {
mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
- assertTrue(
- String.format("requiresClat expected for type=%d state=%s", type, state),
- Nat464Xlat.requiresClat(mNai));
+ String msg = String.format("requiresClat expected for type=%d state=%s",
+ type, state);
+
+ mMisc.skip464xlat = true;
+ String errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
+ assertFalse(errorMsg, Nat464Xlat.requiresClat(mNai));
+
+ mMisc.skip464xlat = false;
+ errorMsg = msg + String.format(" skip464xlat=%b", mMisc.skip464xlat);
+ assertTrue(errorMsg, Nat464Xlat.requiresClat(mNai));
}
}
}
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index 4be6534..0a9e964 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -19,7 +19,7 @@
srcs: ["java/**/*.java"],
- static_libs: ["android-support-test"],
+ static_libs: ["junit"],
libs: [
"android.test.runner",
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 0a517ab..0bc5221 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -306,8 +306,29 @@
break;
}
- if (entry->overlayable) {
- printer->Print(" OVERLAYABLE");
+ for (size_t i = 0; i < entry->overlayable_declarations.size(); i++) {
+ printer->Print((i == 0) ? " " : "|");
+ printer->Print("OVERLAYABLE");
+
+ if (entry->overlayable_declarations[i].policy) {
+ switch (entry->overlayable_declarations[i].policy.value()) {
+ case Overlayable::Policy::kProduct:
+ printer->Print("_PRODUCT");
+ break;
+ case Overlayable::Policy::kProductServices:
+ printer->Print("_PRODUCT_SERVICES");
+ break;
+ case Overlayable::Policy::kSystem:
+ printer->Print("_SYSTEM");
+ break;
+ case Overlayable::Policy::kVendor:
+ printer->Print("_VENDOR");
+ break;
+ case Overlayable::Policy::kPublic:
+ printer->Print("_PUBLIC");
+ break;
+ }
+ }
}
printer->Println();
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9a3f14c..4f25e09 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -99,7 +99,7 @@
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
bool allow_new = false;
- bool overlayable = false;
+ std::vector<Overlayable> overlayable_declarations;
std::string comment;
std::unique_ptr<Value> value;
@@ -133,11 +133,8 @@
}
}
- if (res->overlayable) {
- Overlayable overlayable;
- overlayable.source = res->source;
- overlayable.comment = res->comment;
- if (!table->SetOverlayable(res->name, overlayable, diag)) {
+ for (auto& overlayable : res->overlayable_declarations) {
+ if (!table->AddOverlayable(res->name, overlayable, diag)) {
return false;
}
}
@@ -673,7 +670,7 @@
if (can_be_bag) {
const auto bag_iter = elToBagMap.find(resource_type);
if (bag_iter != elToBagMap.end()) {
- // Ensure we have a name (unless this is a <public-group>).
+ // Ensure we have a name (unless this is a <public-group> or <overlayable>).
if (resource_type != "public-group" && resource_type != "overlayable") {
if (!maybe_name) {
diag_->Error(DiagMessage(out_resource->source)
@@ -1062,74 +1059,137 @@
bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
+ << "ignoring configuration '" << out_resource->config
+ << "' for <overlayable> tag");
}
- if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) {
- const StringPiece& policy = maybe_policy.value();
- if (policy != "system") {
- diag_->Error(DiagMessage(out_resource->source)
- << "<overlayable> has invalid policy '" << policy << "'");
- return false;
- }
- }
+ std::string comment;
+ std::vector<Overlayable::Policy> policies;
bool error = false;
- const size_t depth = parser->depth();
- while (xml::XmlPullParser::NextChildNode(parser, depth)) {
- if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
- // Skip text/comments.
+ const size_t start_depth = parser->depth();
+ while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
+ xml::XmlPullParser::Event event = parser->event();
+ if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) {
+ // Break the loop when exiting the overyabale element
+ break;
+ } else if (event == xml::XmlPullParser::Event::kEndElement
+ && parser->depth() == start_depth + 1) {
+ // Clear the current policies when exiting the policy element
+ policies.clear();
+ continue;
+ } else if (event == xml::XmlPullParser::Event::kComment) {
+ // Get the comment of individual item elements
+ comment = parser->comment();
+ continue;
+ } else if (event != xml::XmlPullParser::Event::kStartElement) {
+ // Skip to the next element
continue;
}
const Source item_source = source_.WithLine(parser->line_number());
- const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
+ const std::string& element_namespace = parser->element_namespace();
+
if (element_namespace.empty() && element_name == "item") {
- Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
- if (!maybe_name) {
- diag_->Error(DiagMessage(item_source)
- << "<item> within an <overlayable> tag must have a 'name' attribute");
+ if (!ParseOverlayableItem(parser, policies, comment, out_resource)) {
error = true;
- continue;
}
-
- Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
- if (!maybe_type) {
- diag_->Error(DiagMessage(item_source)
- << "<item> within an <overlayable> tag must have a 'type' attribute");
+ } else if (element_namespace.empty() && element_name == "policy") {
+ if (!policies.empty()) {
+ // If the policy list is not empty, then we are currently inside a policy element
+ diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested");
error = true;
- continue;
+ break;
+ } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+ // Parse the polices separated by vertical bar characters to allow for specifying multiple
+ // policies at once
+ for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
+ StringPiece trimmed_part = util::TrimWhitespace(part);
+ if (trimmed_part == "public") {
+ policies.push_back(Overlayable::Policy::kPublic);
+ } else if (trimmed_part == "product") {
+ policies.push_back(Overlayable::Policy::kProduct);
+ } else if (trimmed_part == "product_services") {
+ policies.push_back(Overlayable::Policy::kProductServices);
+ } else if (trimmed_part == "system") {
+ policies.push_back(Overlayable::Policy::kSystem);
+ } else if (trimmed_part == "vendor") {
+ policies.push_back(Overlayable::Policy::kVendor);
+ } else {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<policy> has unsupported type '" << trimmed_part << "'");
+ error = true;
+ continue;
+ }
+ }
}
-
- const ResourceType* type = ParseResourceType(maybe_type.value());
- if (type == nullptr) {
- diag_->Error(DiagMessage(out_resource->source)
- << "invalid resource type '" << maybe_type.value()
- << "' in <item> within an <overlayable>");
- error = true;
- continue;
- }
-
- ParsedResource child_resource;
- child_resource.name.type = *type;
- child_resource.name.entry = maybe_name.value().to_string();
- child_resource.source = item_source;
- child_resource.overlayable = true;
- if (options_.visibility) {
- child_resource.visibility_level = options_.visibility.value();
- }
- out_resource->child_resources.push_back(std::move(child_resource));
-
- xml::XmlPullParser::SkipCurrentElement(parser);
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> in "
+ << " <overlayable>");
error = true;
+ break;
}
}
+
return !error;
}
+bool ResourceParser::ParseOverlayableItem(xml::XmlPullParser* parser,
+ const std::vector<Overlayable::Policy>& policies,
+ const std::string& comment,
+ ParsedResource* out_resource) {
+ const Source item_source = source_.WithLine(parser->line_number());
+
+ Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+ if (!maybe_name) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'name' attribute");
+ return false;
+ }
+
+ Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+ if (!maybe_type) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'type' attribute");
+ return false;
+ }
+
+ const ResourceType* type = ParseResourceType(maybe_type.value());
+ if (type == nullptr) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value()
+ << "' in <item> within an <overlayable>");
+ return false;
+ }
+
+ ParsedResource child_resource;
+ child_resource.name.type = *type;
+ child_resource.name.entry = maybe_name.value().to_string();
+ child_resource.source = item_source;
+
+ if (policies.empty()) {
+ Overlayable overlayable;
+ overlayable.source = item_source;
+ overlayable.comment = comment;
+ child_resource.overlayable_declarations.push_back(overlayable);
+ } else {
+ for (Overlayable::Policy policy : policies) {
+ Overlayable overlayable;
+ overlayable.policy = policy;
+ overlayable.source = item_source;
+ overlayable.comment = comment;
+ child_resource.overlayable_declarations.push_back(overlayable);
+ }
+ }
+
+ if (options_.visibility) {
+ child_resource.visibility_level = options_.visibility.value();
+ }
+ out_resource->child_resources.push_back(std::move(child_resource));
+ return true;
+}
+
bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (ParseSymbolImpl(parser, out_resource)) {
out_resource->visibility_level = Visibility::Level::kUndefined;
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 06bb0c9..ebacd6f 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -96,6 +96,10 @@
bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource);
+ bool ParseOverlayableItem(xml::XmlPullParser* parser,
+ const std::vector<Overlayable::Policy>& policies,
+ const std::string& comment,
+ ParsedResource* out_resource);
bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 0dff664..c6f29ac 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -891,56 +891,162 @@
ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
}
-TEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) {
- std::string input = R"(
- <overlayable policy="illegal_policy">
- <item type="string" name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="attr" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="bad_type" name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(<overlayable policy="system" />)";
+TEST_F(ResourceParserTest, ParseOverlayable) {
+ std::string input = R"(<overlayable />)";
EXPECT_TRUE(TestParse(input));
- input = R"(<overlayable />)";
- EXPECT_TRUE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="string" name="foo" />
- <item type="dimen" name="foo" />
- </overlayable>)";
- ASSERT_TRUE(TestParse(input));
-
input = R"(
<overlayable>
- <item type="string" name="bar" />
+ <item type="string" name="foo" />
+ <item type="drawable" name="bar" />
</overlayable>)";
ASSERT_TRUE(TestParse(input));
- Maybe<ResourceTable::SearchResult> search_result =
- table_.FindResource(test::ParseNameOrDie("string/bar"));
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
- EXPECT_TRUE(search_result.value().entry->overlayable);
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+ search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+}
+
+TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
+ std::string input = R"(<overlayable />)";
+ EXPECT_TRUE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <item type="string" name="foo" />
+ <policy type="product">
+ <item type="string" name="bar" />
+ </policy>
+ <policy type="product_services">
+ <item type="string" name="baz" />
+ </policy>
+ <policy type="system">
+ <item type="string" name="fiz" />
+ </policy>
+ <policy type="vendor">
+ <item type="string" name="fuz" />
+ </policy>
+ <policy type="public">
+ <item type="string" name="faz" />
+ </policy>
+ </overlayable>)";
+ ASSERT_TRUE(TestParse(input));
+
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProductServices));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kSystem));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kVendor));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kPublic));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="illegal_policy">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="product">
+ <item name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="vendor">
+ <item type="string" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product_services">
+ <item type="string" name="foo" />
+ </policy>
+ <policy type="product|system">
+ <item type="string" name="bar" />
+ </policy>
+ </overlayable>)";
+ ASSERT_TRUE(TestParse(input));
+
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kVendor));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kSystem));
}
TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
@@ -950,6 +1056,85 @@
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable>
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable">
+ <policy type="product">
+ <item type="string" name="foo" />
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>
+
+ <overlayable>
+ <policy type="product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, PolicyAndNonPolicyOverlayableError) {
+ std::string input = R"(
+ <overlayable policy="product">
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable policy="">
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable policy="">
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable policy="product">
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, DuplicateOverlayableMultiplePolicyError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>
+ <overlayable>
+ <policy type="product_services|vendor">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, NestPolicyInOverlayableError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product">
+ <policy type="product_services">
+ <item type="string" name="foo" />
+ </policy>
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
}
TEST_F(ResourceParserTest, ParseIdItem) {
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 056a27b..bc8a4d1 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -625,17 +625,17 @@
return true;
}
-bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag) {
- return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
+ return AddOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
}
-bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
+bool ResourceTable::AddOverlayableMangled(const ResourceNameRef& name,
const Overlayable& overlayable, IDiagnostics* diag) {
- return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
+ return AddOverlayableImpl(name, overlayable, SkipNameValidator, diag);
}
-bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
NameValidator name_validator, IDiagnostics* diag) {
CHECK(diag != nullptr);
@@ -646,13 +646,28 @@
ResourceTablePackage* package = FindOrCreatePackage(name.package);
ResourceTableType* type = package->FindOrCreateType(name.type);
ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
- if (entry->overlayable) {
- diag->Error(DiagMessage(overlayable.source)
- << "duplicate overlayable declaration for resource '" << name << "'");
- diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
- return false;
+
+ for (auto& overlayable_declaration : entry->overlayable_declarations) {
+ // An overlayable resource cannot be declared twice with the same policy
+ if (overlayable.policy == overlayable_declaration.policy) {
+ diag->Error(DiagMessage(overlayable.source)
+ << "duplicate overlayable declaration for resource '" << name << "'");
+ diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+ return false;
+ }
+
+ // An overlayable resource cannot be declared once with a policy and without a policy because
+ // the policy becomes unused
+ if (!overlayable.policy || !overlayable_declaration.policy) {
+ diag->Error(DiagMessage(overlayable.source)
+ << "overlayable resource '" << name << "'"
+ << " declared once with a policy and once with no policy");
+ diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+ return false;
+ }
}
- entry->overlayable = overlayable;
+
+ entry->overlayable_declarations.push_back(overlayable);
return true;
}
@@ -688,7 +703,7 @@
new_entry->id = entry->id;
new_entry->visibility = entry->visibility;
new_entry->allow_new = entry->allow_new;
- new_entry->overlayable = entry->overlayable;
+ new_entry->overlayable_declarations = entry->overlayable_declarations;
for (const auto& config_value : entry->values) {
ResourceConfigValue* new_value =
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 1917d7e..3dd0a769 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -57,8 +57,27 @@
std::string comment;
};
-// The policy dictating whether an entry is overlayable at runtime by RROs.
+// Represents a declaration that a resource is overayable at runtime.
struct Overlayable {
+ // Represents the types overlays that are allowed to overlay the resource.
+ enum class Policy {
+ // The resource can be overlaid by any overlay.
+ kPublic,
+
+ // The resource can be overlaid by any overlay on the system partition.
+ kSystem,
+
+ // The resource can be overlaid by any overlay on the vendor partition.
+ kVendor,
+
+ // The resource can be overlaid by any overlay on the product partition.
+ kProduct,
+
+ // The resource can be overlaid by any overlay on the product services partition.
+ kProductServices,
+ };
+
+ Maybe<Policy> policy;
Source source;
std::string comment;
};
@@ -96,7 +115,8 @@
Maybe<AllowNew> allow_new;
- Maybe<Overlayable> overlayable;
+ // The declarations of this resource as overlayable for RROs
+ std::vector<Overlayable> overlayable_declarations;
// The resource's values for each configuration.
std::vector<std::unique_ptr<ResourceConfigValue>> values;
@@ -226,9 +246,9 @@
bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
const ResourceId& res_id, IDiagnostics* diag);
- bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag);
- bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag);
bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
@@ -303,7 +323,7 @@
bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
NameValidator name_validator, IDiagnostics* diag);
- bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
NameValidator name_validator, IDiagnostics* diag);
bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 05c6f15..7c28f07 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -242,21 +242,69 @@
ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
}
-TEST(ResourceTableTest, SetOverlayable) {
+TEST(ResourceTableTest, AddOverlayable) {
ResourceTable table;
const ResourceName name = test::ParseNameOrDie("android:string/foo");
Overlayable overlayable;
-
+ overlayable.policy = Overlayable::Policy::kProduct;
overlayable.comment = "first";
- ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
ASSERT_TRUE(result);
- ASSERT_TRUE(result.value().entry->overlayable);
- ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
- overlayable.comment = "second";
- ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+ Overlayable overlayable2;
+ overlayable2.comment = "second";
+ overlayable2.policy = Overlayable::Policy::kProductServices;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+ result = table.FindResource(name);
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].comment, StrEq("second"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST(ResourceTableTest, AddDuplicateOverlayableFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ Overlayable overlayable;
+ overlayable.policy = Overlayable::Policy::kProduct;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+ Overlayable overlayable2;
+ overlayable2.policy = Overlayable::Policy::kProduct;
+ ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneFirstFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ ASSERT_TRUE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
+
+ Overlayable overlayable2;
+ overlayable2.policy = Overlayable::Policy::kProduct;
+ ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneLastFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ Overlayable overlayable;
+ overlayable.policy = Overlayable::Policy::kProduct;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+ ASSERT_FALSE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
}
TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index d7a3771..bf9fe49 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -133,13 +133,25 @@
string comment = 2;
}
-// Whether a resource is overlayable by runtime resource overlays (RRO).
+// Represents a declaration that a resource is overayable at runtime.
message Overlayable {
+ enum Policy {
+ NONE = 0;
+ PUBLIC = 1;
+ SYSTEM = 2;
+ VENDOR = 3;
+ PRODUCT = 4;
+ PRODUCT_SERVICES = 5;
+ }
+
// Where this declaration was defined in source.
Source source = 1;
// Any comment associated with the declaration.
string comment = 2;
+
+ // The policy of the overlayable declaration
+ Policy policy = 3;
}
// An entry ID in the range [0x0000, 0xffff].
@@ -169,7 +181,7 @@
AllowNew allow_new = 4;
// Whether this resource can be overlaid by a runtime resource overlay (RRO).
- Overlayable overlayable = 5;
+ repeated Overlayable overlayable = 5;
// The set of values defined for this entry, each corresponding to a different
// configuration/variant.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 3a39a6b..ed70fb3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -398,7 +398,7 @@
if (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) {
Overlayable overlayable;
overlayable.source = source_.WithLine(0);
- if (!table_->SetOverlayableMangled(name, overlayable, diag_)) {
+ if (!table_->AddOverlayableMangled(name, overlayable, diag_)) {
return false;
}
}
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 8641a7c..8a86f63a 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -446,7 +446,7 @@
config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
- if (entry->overlayable) {
+ if (!entry->overlayable_declarations.empty()) {
config_masks[entry->id.value()] |=
util::HostToDevice32(ResTable_typeSpec::SPEC_OVERLAYABLE);
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index af19b98..cd1414c7e 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -634,7 +634,7 @@
.AddSimple("com.app.test:integer/overlayable", ResourceId(0x7f020000))
.Build();
- ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
+ ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
Overlayable{}, test::GetDiagnostics()));
ResTable res_table;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index d1b2fdb..f612914 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -437,15 +437,37 @@
entry->allow_new = std::move(allow_new);
}
- if (pb_entry.has_overlayable()) {
- const pb::Overlayable& pb_overlayable = pb_entry.overlayable();
-
+ for (const pb::Overlayable& pb_overlayable : pb_entry.overlayable()) {
Overlayable overlayable;
+ switch (pb_overlayable.policy()) {
+ case pb::Overlayable::NONE:
+ overlayable.policy = {};
+ break;
+ case pb::Overlayable::PUBLIC:
+ overlayable.policy = Overlayable::Policy::kPublic;
+ break;
+ case pb::Overlayable::PRODUCT:
+ overlayable.policy = Overlayable::Policy::kProduct;
+ break;
+ case pb::Overlayable::PRODUCT_SERVICES:
+ overlayable.policy = Overlayable::Policy::kProductServices;
+ break;
+ case pb::Overlayable::SYSTEM:
+ overlayable.policy = Overlayable::Policy::kSystem;
+ break;
+ case pb::Overlayable::VENDOR:
+ overlayable.policy = Overlayable::Policy::kVendor;
+ break;
+ default:
+ *out_error = "unknown overlayable policy";
+ return false;
+ }
+
if (pb_overlayable.has_source()) {
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source);
}
overlayable.comment = pb_overlayable.comment();
- entry->overlayable = std::move(overlayable);
+ entry->overlayable_declarations.push_back(overlayable);
}
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 7e35ea7..f1e96d6 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -310,11 +310,31 @@
pb_allow_new->set_comment(entry->allow_new.value().comment);
}
- if (entry->overlayable) {
- pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable();
- SerializeSourceToPb(entry->overlayable.value().source, &source_pool,
+ for (const Overlayable& overlayable : entry->overlayable_declarations) {
+ pb::Overlayable* pb_overlayable = pb_entry->add_overlayable();
+ if (overlayable.policy) {
+ switch (overlayable.policy.value()) {
+ case Overlayable::Policy::kPublic:
+ pb_overlayable->set_policy(pb::Overlayable::PUBLIC);
+ break;
+ case Overlayable::Policy::kProduct:
+ pb_overlayable->set_policy(pb::Overlayable::PRODUCT);
+ break;
+ case Overlayable::Policy::kProductServices:
+ pb_overlayable->set_policy(pb::Overlayable::PRODUCT_SERVICES);
+ break;
+ case Overlayable::Policy::kSystem:
+ pb_overlayable->set_policy(pb::Overlayable::SYSTEM);
+ break;
+ case Overlayable::Policy::kVendor:
+ pb_overlayable->set_policy(pb::Overlayable::VENDOR);
+ break;
+ }
+ }
+
+ SerializeSourceToPb(overlayable.source, &source_pool,
pb_overlayable->mutable_source());
- pb_overlayable->set_comment(entry->overlayable.value().comment);
+ pb_overlayable->set_comment(overlayable.comment);
}
for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 3c4d41a..95dbbeb 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -93,7 +93,7 @@
util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
// Make an overlayable resource.
- ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
+ ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
Overlayable{}, test::GetDiagnostics()));
pb::ResourceTable pb_table;
@@ -106,7 +106,7 @@
ResourceTable new_table;
std::string error;
- ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
EXPECT_THAT(error, IsEmpty());
Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
@@ -160,7 +160,8 @@
new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
- EXPECT_TRUE(search_result.value().entry->overlayable);
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
}
TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
@@ -464,4 +465,59 @@
"night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
}
+TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kSystem)
+ .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kProduct)
+ .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kProductServices)
+ .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kVendor)
+ .AddOverlayable("com.app.a:bool/baz", Overlayable::Policy::kPublic)
+ .AddOverlayable("com.app.a:bool/biz", {})
+ .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
+ .Build();
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+
+ MockFileCollection files;
+ ResourceTable new_table;
+ std::string error;
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ Maybe<ResourceTable::SearchResult> result =
+ new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kSystem));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProduct));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProductServices));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kVendor));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kPublic));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(result.value().entry->overlayable_declarations[0].policy);
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
+ ASSERT_TRUE(result);
+ EXPECT_THAT(result.value().entry->overlayable_declarations.size(), Eq(0));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index afb8ae0..d777e22 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -101,7 +101,7 @@
return true;
}
-static bool MergeEntry(IAaptContext* context, const Source& src, bool overlay,
+static bool MergeEntry(IAaptContext* context, const Source& src,
ResourceEntry* dst_entry, ResourceEntry* src_entry,
bool strict_visibility) {
if (strict_visibility
@@ -134,17 +134,35 @@
dst_entry->allow_new = std::move(src_entry->allow_new);
}
- if (src_entry->overlayable) {
- if (dst_entry->overlayable && !overlay) {
- context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source)
- << "duplicate overlayable declaration for resource '"
- << src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source)
- << "previous declaration here");
- return false;
+ for (auto& src_overlayable : src_entry->overlayable_declarations) {
+ for (auto& dst_overlayable : dst_entry->overlayable_declarations) {
+ // An overlayable resource cannot be declared twice with the same policy
+ if (src_overlayable.policy == dst_overlayable.policy) {
+ context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+ << "duplicate overlayable declaration for resource '"
+ << src_entry->name << "'");
+ context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+ << "previous declaration here");
+ return false;
+ }
+
+ // An overlayable resource cannot be declared once with a policy and without a policy because
+ // the policy becomes unused
+ if (!src_overlayable.policy || !dst_overlayable.policy) {
+ context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+ << "overlayable resource '" << src_entry->name
+ << "' declared once with a policy and once with no "
+ << "policy");
+ context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+ << "previous declaration here");
+ return false;
+ }
}
- dst_entry->overlayable = std::move(src_entry->overlayable);
}
+
+ dst_entry->overlayable_declarations.insert(dst_entry->overlayable_declarations.end(),
+ src_entry->overlayable_declarations.begin(),
+ src_entry->overlayable_declarations.end());
return true;
}
@@ -244,7 +262,7 @@
continue;
}
- if (!MergeEntry(context_, src, overlay, dst_entry, src_entry.get(), options_.strict_visibility)) {
+ if (!MergeEntry(context_, src, dst_entry, src_entry.get(), options_.strict_visibility)) {
error = true;
continue;
}
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 79a734b..d6579d3 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -436,4 +436,97 @@
Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")))));
}
+TEST_F(TableMergerTest, AddOverlayable) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProductServices)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
+
+ const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
+ Maybe<ResourceTable::SearchResult> result = final_table.FindResource(name);
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST_F(TableMergerTest, AddDuplicateOverlayableFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneFirstFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", {})
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneLastFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", {})
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 414758e..2e717ff 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -248,6 +248,7 @@
if (!split_entry->id) {
split_entry->id = entry->id;
split_entry->visibility = entry->visibility;
+ split_entry->overlayable_declarations = entry->overlayable_declarations;
}
// Copy the selected values into the new Split Entry.
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index f33ae31..03b59e0 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -135,6 +135,15 @@
return *this;
}
+ResourceTableBuilder& ResourceTableBuilder::AddOverlayable(const StringPiece& name,
+ const Maybe<Overlayable::Policy> p) {
+ ResourceName res_name = ParseNameOrDie(name);
+ Overlayable overlayable;
+ overlayable.policy = p;
+ CHECK(table_->AddOverlayable(res_name, overlayable, GetDiagnostics()));
+ return *this;
+}
+
StringPool* ResourceTableBuilder::string_pool() {
return &table_->string_pool;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 9159599..d68c24d 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -73,6 +73,8 @@
const ResourceId& id, std::unique_ptr<Value> value);
ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
Visibility::Level level, bool allow_new = false);
+ ResourceTableBuilder& AddOverlayable(const android::StringPiece& name,
+ Maybe<Overlayable::Policy> policy);
StringPool* string_pool();
std::unique_ptr<ResourceTable> Build();
diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
new file mode 100644
index 0000000..f472a02
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.net.wifi.INetworkRequestUserSelectionCallback;
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for network request match callback.
+ *
+ * @hide
+ */
+oneway interface INetworkRequestMatchCallback
+{
+ void onUserSelectionCallbackRegistration(in INetworkRequestUserSelectionCallback userSelectionCallback);
+
+ void onMatch(in List<WifiConfiguration> wificonfigurations);
+
+ void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration);
+
+ void onUserSelectionConnectFailure(in WifiConfiguration wificonfiguration);
+}
diff --git a/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
new file mode 100644
index 0000000..524cefb
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for providing user selection in response to
+ * network request match callback.
+ * @hide
+ */
+oneway interface INetworkRequestUserSelectionCallback
+{
+ void select(in WifiConfiguration wificonfiguration);
+
+ void reject();
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 12f50c8..1fd68ec 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ITrafficStateCallback;
import android.net.wifi.PasspointManagementObjectDefinition;
@@ -185,5 +186,9 @@
void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
void unregisterTrafficStateCallback(int callbackIdentifier);
+
+ void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier);
+
+ void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 3a4e88b..9b9247d 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -86,9 +86,9 @@
public static final int PROTOCOL_WPA = 1;
/**
* @hide
- * Security protocol type: WPA version 2, also called RSN.
+ * Security protocol type: RSN, for WPA version 2, and version 3.
*/
- public static final int PROTOCOL_WPA2 = 2;
+ public static final int PROTOCOL_RSN = 2;
/**
* @hide
* Security protocol type:
@@ -138,7 +138,21 @@
* Used for Hotspot 2.0.
*/
public static final int KEY_MGMT_OSEN = 7;
-
+ /**
+ * @hide
+ * Security key management scheme: SAE.
+ */
+ public static final int KEY_MGMT_SAE = 8;
+ /**
+ * @hide
+ * Security key management scheme: OWE.
+ */
+ public static final int KEY_MGMT_OWE = 9;
+ /**
+ * @hide
+ * Security key management scheme: SUITE_B_192.
+ */
+ public static final int KEY_MGMT_EAP_SUITE_B_192 = 10;
/**
* @hide
* No cipher suite.
@@ -159,6 +173,11 @@
* Cipher suite: CCMP
*/
public static final int CIPHER_CCMP = 3;
+ /**
+ * @hide
+ * Cipher suite: GCMP
+ */
+ public static final int CIPHER_GCMP_256 = 4;
/**
* The detected signal level in dBm, also known as the RSSI.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0330614..8fc9b97 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -23,6 +23,7 @@
import android.net.IpConfiguration;
import android.net.IpConfiguration.ProxySettings;
import android.net.MacAddress;
+import android.net.NetworkSpecifier;
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
@@ -47,7 +48,11 @@
/**
* A class representing a configured Wi-Fi network, including the
* security configuration.
+ *
+ * @deprecated Use {@link WifiNetworkConfigBuilder} to create {@link NetworkSpecifier} and
+ * {@link WifiNetworkSuggestion}. This will become a system use only object in the future.
*/
+@Deprecated
public class WifiConfiguration implements Parcelable {
private static final String TAG = "WifiConfiguration";
/**
@@ -125,10 +130,26 @@
*/
public static final int FT_EAP = 7;
+ /**
+ * Simultaneous Authentication of Equals
+ */
+ public static final int SAE = 8;
+
+ /**
+ * Opportunististic Wireless Encryption
+ */
+ public static final int OWE = 9;
+
+ /**
+ * SUITE_B_192 192 bit level
+ */
+ public static final int SUITE_B_192 = 10;
+
public static final String varName = "key_mgmt";
public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
- "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
+ "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
+ "SAE", "OWE", "SUITE_B_192"};
}
/**
@@ -142,7 +163,7 @@
* is discouraged. WPA-2 (RSN) should be used instead. */
@Deprecated
public static final int WPA = 0;
- /** WPA2/IEEE 802.11i */
+ /** RSN WPA2/WPA3/IEEE 802.11i */
public static final int RSN = 1;
/** HS2.0 r2 OSEN
* @hide
@@ -190,10 +211,14 @@
public static final int TKIP = 1;
/** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
public static final int CCMP = 2;
+ /**
+ * AES in Galois/Counter Mode
+ */
+ public static final int GCMP_256 = 3;
public static final String varName = "pairwise";
- public static final String[] strings = { "NONE", "TKIP", "CCMP" };
+ public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256" };
}
/**
@@ -203,6 +228,7 @@
* TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
* WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
* WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
+ * GCMP_256 = AES in Galois/Counter Mode
* </pre>
*/
public static class GroupCipher {
@@ -226,12 +252,64 @@
* @hide
*/
public static final int GTK_NOT_USED = 4;
+ /**
+ * AES in Galois/Counter Mode
+ */
+ public static final int GCMP_256 = 5;
public static final String varName = "group";
public static final String[] strings =
{ /* deprecated */ "WEP40", /* deprecated */ "WEP104",
- "TKIP", "CCMP", "GTK_NOT_USED" };
+ "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256" };
+ }
+
+ /**
+ * Recognized group management ciphers.
+ * <pre>
+ * BIP_CMAC_256 = Cipher-based Message Authentication Code 256 bits
+ * BIP_GMAC_128 = Galois Message Authentication Code 128 bits
+ * BIP_GMAC_256 = Galois Message Authentication Code 256 bits
+ * </pre>
+ */
+ public static class GroupMgmtCipher {
+ private GroupMgmtCipher() { }
+
+ /** CMAC-256 = Cipher-based Message Authentication Code */
+ public static final int BIP_CMAC_256 = 0;
+
+ /** GMAC-128 = Galois Message Authentication Code */
+ public static final int BIP_GMAC_128 = 1;
+
+ /** GMAC-256 = Galois Message Authentication Code */
+ public static final int BIP_GMAC_256 = 2;
+
+ private static final String varName = "groupMgmt";
+
+ private static final String[] strings = { "BIP_CMAC_256",
+ "BIP_GMAC_128", "BIP_GMAC_256"};
+ }
+
+ /**
+ * Recognized suiteB ciphers.
+ * <pre>
+ * ECDHE_ECDSA
+ * ECDHE_RSA
+ * </pre>
+ * @hide
+ */
+ public static class SuiteBCipher {
+ private SuiteBCipher() { }
+
+ /** Diffie-Hellman with Elliptic Curve_ECDSA signature */
+ public static final int ECDHE_ECDSA = 0;
+
+ /** Diffie-Hellman with_RSA signature */
+ public static final int ECDHE_RSA = 1;
+
+ private static final String varName = "SuiteB";
+
+ private static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" };
}
/** Possible status of a network configuration. */
@@ -409,6 +487,17 @@
*/
public BitSet allowedGroupCiphers;
/**
+ * The set of group management ciphers supported by this configuration.
+ * See {@link GroupMgmtCipher} for descriptions of the values.
+ */
+ public BitSet allowedGroupMgmtCiphers;
+ /**
+ * The set of SuiteB ciphers supported by this configuration.
+ * To be used for WPA3-Enterprise mode.
+ * See {@link SuiteBCipher} for descriptions of the values.
+ */
+ public BitSet allowedSuiteBCiphers;
+ /**
* The enterprise configuration details specifying the EAP method,
* certificates and other settings associated with the EAP.
*/
@@ -733,7 +822,8 @@
public boolean isOpenNetwork() {
final int cardinality = allowedKeyManagement.cardinality();
final boolean hasNoKeyMgmt = cardinality == 0
- || (cardinality == 1 && allowedKeyManagement.get(KeyMgmt.NONE));
+ || (cardinality == 1 && (allowedKeyManagement.get(KeyMgmt.NONE)
+ || allowedKeyManagement.get(KeyMgmt.OWE)));
boolean hasNoWepKeys = true;
if (wepKeys != null) {
@@ -1538,6 +1628,8 @@
allowedAuthAlgorithms = new BitSet();
allowedPairwiseCiphers = new BitSet();
allowedGroupCiphers = new BitSet();
+ allowedGroupMgmtCiphers = new BitSet();
+ allowedSuiteBCiphers = new BitSet();
wepKeys = new String[4];
for (int i = 0; i < wepKeys.length; i++) {
wepKeys[i] = null;
@@ -1591,7 +1683,8 @@
@UnsupportedAppUsage
public boolean isEnterprise() {
return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
- || allowedKeyManagement.get(KeyMgmt.IEEE8021X))
+ || allowedKeyManagement.get(KeyMgmt.IEEE8021X)
+ || allowedKeyManagement.get(KeyMgmt.SUITE_B_192))
&& enterpriseConfig != null
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
}
@@ -1609,6 +1702,7 @@
append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
.append(" PRIO: ").append(this.priority)
.append(" HIDDEN: ").append(this.hiddenSSID)
+ .append(" PMF: ").append(this.requirePMF)
.append('\n');
@@ -1721,10 +1815,35 @@
}
}
}
- sbuf.append('\n').append(" PSK: ");
+ sbuf.append('\n');
+ sbuf.append(" GroupMgmtCiphers:");
+ for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) {
+ if (this.allowedGroupMgmtCiphers.get(gmc)) {
+ sbuf.append(" ");
+ if (gmc < GroupMgmtCipher.strings.length) {
+ sbuf.append(GroupMgmtCipher.strings[gmc]);
+ } else {
+ sbuf.append("??");
+ }
+ }
+ }
+ sbuf.append('\n');
+ sbuf.append(" SuiteBCiphers:");
+ for (int sbc = 0; sbc < this.allowedSuiteBCiphers.size(); sbc++) {
+ if (this.allowedSuiteBCiphers.get(sbc)) {
+ sbuf.append(" ");
+ if (sbc < SuiteBCipher.strings.length) {
+ sbuf.append(SuiteBCipher.strings[sbc]);
+ } else {
+ sbuf.append("??");
+ }
+ }
+ }
+ sbuf.append('\n').append(" PSK/SAE: ");
if (this.preSharedKey != null) {
sbuf.append('*');
}
+
sbuf.append("\nEnterprise config:\n");
sbuf.append(enterpriseConfig);
@@ -1887,6 +2006,12 @@
return KeyMgmt.WPA_EAP;
} else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return KeyMgmt.IEEE8021X;
+ } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+ return KeyMgmt.SAE;
+ } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+ return KeyMgmt.OWE;
+ } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ return KeyMgmt.SUITE_B_192;
}
return KeyMgmt.NONE;
}
@@ -1918,6 +2043,12 @@
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else if (wepKeys[0] != null) {
key = SSID + "WEP";
+ } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
} else {
key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
}
@@ -2086,6 +2217,8 @@
allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone();
allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone();
+ allowedGroupMgmtCiphers = (BitSet) source.allowedGroupMgmtCiphers.clone();
+ allowedSuiteBCiphers = (BitSet) source.allowedSuiteBCiphers.clone();
enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
defaultGwMacAddress = source.defaultGwMacAddress;
@@ -2128,6 +2261,7 @@
recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
mRandomizedMacAddress = source.mRandomizedMacAddress;
macRandomizationSetting = source.macRandomizationSetting;
+ requirePMF = source.requirePMF;
}
}
@@ -2163,6 +2297,8 @@
writeBitSet(dest, allowedAuthAlgorithms);
writeBitSet(dest, allowedPairwiseCiphers);
writeBitSet(dest, allowedGroupCiphers);
+ writeBitSet(dest, allowedGroupMgmtCiphers);
+ writeBitSet(dest, allowedSuiteBCiphers);
dest.writeParcelable(enterpriseConfig, flags);
@@ -2231,6 +2367,8 @@
config.allowedAuthAlgorithms = readBitSet(in);
config.allowedPairwiseCiphers = readBitSet(in);
config.allowedGroupCiphers = readBitSet(in);
+ config.allowedGroupMgmtCiphers = readBitSet(in);
+ config.allowedSuiteBCiphers = readBitSet(in);
config.enterpriseConfig = in.readParcelable(null);
config.setIpConfiguration(in.readParcelable(null));
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9adbe67..954b51f 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -25,19 +25,17 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -52,7 +50,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import com.android.server.net.NetworkPinner;
import dalvik.system.CloseGuard;
@@ -1035,7 +1032,17 @@
* </ul>
* @return a list of network configurations in the form of a list
* of {@link WifiConfiguration} objects.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list.
*/
+ @Deprecated
public List<WifiConfiguration> getConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
@@ -1135,7 +1142,17 @@
* @return the ID of the newly created network description. This is used in
* other operations to specified the network to be acted upon.
* Returns {@code -1} on failure.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int addNetwork(WifiConfiguration config) {
if (config == null) {
return -1;
@@ -1160,7 +1177,17 @@
* Returns {@code -1} on failure, including when the {@code networkId}
* field of the {@code WifiConfiguration} does not refer to an
* existing network.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int updateNetwork(WifiConfiguration config) {
if (config == null || config.networkId < 0) {
return -1;
@@ -1185,6 +1212,301 @@
}
/**
+ * Interface for indicating user selection from the list of networks presented in the
+ * {@link NetworkRequestMatchCallback#onMatch(List)}.
+ *
+ * The platform will implement this callback and pass it along with the
+ * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
+ * NetworkRequestUserSelectionCallback)}. The UI component handling
+ * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
+ * {@link #reject()} to return the user's selection back to the platform via this callback.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestUserSelectionCallback {
+ /**
+ * User selected this network to connect to.
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void select(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * User rejected the app's request.
+ */
+ void reject();
+ }
+
+ /**
+ * Interface for network request callback. Should be implemented by applications and passed when
+ * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
+ *
+ * This is meant to be implemented by a UI component to present the user with a list of networks
+ * matching the app's request. The user is allowed to pick one of these networks to connect to
+ * or reject the request by the app.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestMatchCallback {
+ /**
+ * Invoked to register a callback to be invoked to convey user selection. The callback
+ * object paased in this method is to be invoked by the UI component after the service sends
+ * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
+ * from that list.
+ *
+ * @param userSelectionCallback Callback object to send back the user selection.
+ */
+ void onUserSelectionCallbackRegistration(
+ @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
+
+ /**
+ * Invoked when a network request initiated by an app matches some networks in scan results.
+ * This may be invoked multiple times for a single network request as the platform finds new
+ * networks in scan results.
+ *
+ * @param wifiConfigurations List of {@link WifiConfiguration} objects corresponding to the
+ * networks matching the request.
+ */
+ void onMatch(@NonNull List<WifiConfiguration> wifiConfigurations);
+
+ /**
+ * Invoked on a successful connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
+ * user selected.
+ */
+ void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * Invoked on failure to establish connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
+ }
+
+ /**
+ * Callback proxy for NetworkRequestUserSelectionCallback objects.
+ * @hide
+ */
+ private class NetworkRequestUserSelectionCallbackProxy implements
+ NetworkRequestUserSelectionCallback {
+ private final INetworkRequestUserSelectionCallback mCallback;
+
+ NetworkRequestUserSelectionCallbackProxy(
+ INetworkRequestUserSelectionCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void select(@NonNull WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
+ + "wificonfiguration: " + wifiConfiguration);
+ }
+ try {
+ mCallback.select(wifiConfiguration);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onSelected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void reject() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
+ }
+ try {
+ mCallback.reject();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onRejected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Callback proxy for NetworkRequestMatchCallback objects.
+ * @hide
+ */
+ private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
+ private final Handler mHandler;
+ private final NetworkRequestMatchCallback mCallback;
+
+ NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
+ mHandler = new Handler(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onUserSelectionCallbackRegistration(
+ INetworkRequestUserSelectionCallback userSelectionCallback) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
+ + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionCallbackRegistration(
+ new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
+ });
+ }
+
+ @Override
+ public void onMatch(List<WifiConfiguration> wifiConfigurations) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch wificonfigurations: "
+ + wifiConfigurations);
+ }
+ mHandler.post(() -> {
+ mCallback.onMatch(wifiConfigurations);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectFailure(wifiConfiguration);
+ });
+ }
+ }
+
+ /**
+ * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * Caller can unregister a previously registered callback using
+ * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @param handler The Handler on whose thread to execute the callbacks of the {@code callback}
+ * object. If null, then the application's main thread will be used.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
+ @Nullable Handler handler) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
+ + ", handler=" + handler);
+
+ Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.registerNetworkRequestMatchCallback(
+ binder, new NetworkRequestMatchCallbackProxy(looper, callback),
+ callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void unregisterNetworkRequestMatchCallback(
+ @NonNull NetworkRequestMatchCallback callback) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
+
+ try {
+ mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
+ * for a detailed explanation of the parameters.
+ *<p>
+ * When the device decides to connect to one of the provided network suggestions, platform fires
+ * the associated {@code pendingIntent} if
+ * the network was created with {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()}
+ * flag set and the provided {@code pendingIntent} is non-null.
+ *<p>
+ * Registration of a non-null pending intent {@code pendingIntent} requires
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
+ *<p>
+ * NOTE:
+ * <li> These networks are just a suggestion to the platform. The platform will ultimately
+ * decide on which network the device connects to. </li>
+ * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
+ * currently connected to a suggested network which is being removed then the device will
+ * disconnect from that network.</li>
+ * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
+ * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
+ * suggestion back using this API.</li>
+ *
+ * @param networkSuggestions List of network suggestions provided by the app.
+ * @param pendingIntent Pending intent to be fired post connection for networks. These will be
+ * fired only when connecting to a network that was created with
+ * {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} flag set.
+ * Pending intent must hold a foreground service, else will be rejected.
+ * @return true on success, false if any of the suggestions match (See
+ * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
+ * @throws {@link SecurityException} if the caller is missing required permissions.
+ */
+ public boolean addNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+ @Nullable PendingIntent pendingIntent) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+
+ /**
+ * Remove a subset of or all of networks from previously provided suggestions by the app to the
+ * device.
+ * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
+ * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
+ *
+ * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
+ * to remove all the previous suggestions provided by the app.
+ * @return true on success, false if any of the suggestions do not match any suggestions
+ * previously provided by the app. Any matching suggestions are removed from the device and
+ * will not be considered for any further connection attempts.
+ */
+ public boolean removeNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+ /**
* 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.
@@ -1299,7 +1621,17 @@
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean removeNetwork(int netId) {
try {
return mService.removeNetwork(netId, mContext.getOpPackageName());
@@ -1314,10 +1646,8 @@
* network is initiated. This may result in the asynchronous delivery
* of state change events.
* <p>
- * <b>Note:</b> If an application's target SDK version is
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
- * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
- * instead be sent through another network, such as cellular data,
+ * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
+ * traffic may instead be sent through another network, such as cellular data,
* Bluetooth tethering, or Ethernet. For example, traffic will never use a
* Wi-Fi network that does not provide Internet access (e.g. a wireless
* printer), if another network that does offer Internet access (e.g.
@@ -1335,29 +1665,24 @@
* @param attemptConnect The way to select a particular network to connect to is specify
* {@code true} for this parameter.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
boolean success;
try {
success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
return success;
}
@@ -1372,7 +1697,17 @@
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disableNetwork(int netId) {
try {
return mService.disableNetwork(netId, mContext.getOpPackageName());
@@ -1385,7 +1720,17 @@
* Disassociate from the currently active access point. This may result
* in the asynchronous delivery of state change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disconnect() {
try {
mService.disconnect(mContext.getOpPackageName());
@@ -1400,7 +1745,17 @@
* disconnected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reconnect() {
try {
mService.reconnect(mContext.getOpPackageName());
@@ -1415,7 +1770,17 @@
* connected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reassociate() {
try {
mService.reassociate(mContext.getOpPackageName());
@@ -1490,7 +1855,12 @@
public static final int WIFI_FEATURE_SCAN_RAND = 0x2000000; // Random MAC & Probe seq
/** @hide */
public static final int WIFI_FEATURE_TX_POWER_LIMIT = 0x4000000; // Set Tx power limit
-
+ /** @hide */
+ public static final int WIFI_FEATURE_WPA3_SAE = 0x8000000; // WPA3-Personal SAE
+ /** @hide */
+ public static final int WIFI_FEATURE_WPA3_SUITE_B = 0x10000000; // WPA3-Enterprise Suite-B
+ /** @hide */
+ public static final int WIFI_FEATURE_OWE = 0x20000000; // Enhanced Open
private int getSupportedFeatures() {
try {
@@ -1715,7 +2085,10 @@
* even when Wi-Fi is turned off.
*
* To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
+ * @deprecated The ability for apps to trigger scan requests will be removed in a future
+ * release.
*/
+ @Deprecated
public boolean isScanAlwaysAvailable() {
try {
return mService.isScanAlwaysAvailable();
@@ -1821,7 +2194,12 @@
* @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
* either already in the requested state, or in progress toward the requested state.
* @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
+ *
+ * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
+ * enable/disable Wi-Fi regardless of application's target SDK. This API will have no effect
+ * and will always return false.
*/
+ @Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
@@ -3875,4 +4253,31 @@
private void updateVerboseLoggingEnabledFromService() {
mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0;
}
+
+ /**
+ * @return true if this device supports WPA3-Personal SAE
+ * @hide
+ */
+ @SystemApi
+ public boolean isWpa3SaeSupported() {
+ return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
+ }
+
+ /**
+ * @return true if this device supports WPA3-Enterprise Suite-B-192
+ * @hide
+ */
+ @SystemApi
+ public boolean isWpa3SuiteBSupported() {
+ return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
+ }
+
+ /**
+ * @return true if this device supports Wi-Fi Enhanced Open (OWE)
+ * @hide
+ */
+ @SystemApi
+ public boolean isOweSupported() {
+ return isFeatureSupported(WIFI_FEATURE_OWE);
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
new file mode 100644
index 0000000..55fde4c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkAgent;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used by wifi's {@link android.net.NetworkAgent}.
+ * @hide
+ */
+public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * Security credentials for the currently connected network.
+ */
+ private final WifiConfiguration mWifiConfiguration;
+
+ /**
+ * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
+ *
+ * Will only be filled when the device connects to a wifi network as a result of a
+ * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
+ * auto-connected to a wifi network.
+ */
+ private final int mOriginalRequestorUid;
+
+ public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
+ int originalRequestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ mWifiConfiguration = wifiConfiguration;
+ mOriginalRequestorUid = originalRequestorUid;
+ }
+
+ /**
+ * @hide
+ */
+ public static final Creator<WifiNetworkAgentSpecifier> CREATOR =
+ new Creator<WifiNetworkAgentSpecifier>() {
+ @Override
+ public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int originalRequestorUid = in.readInt();
+ return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
+ }
+
+ @Override
+ public WifiNetworkAgentSpecifier[] newArray(int size) {
+ return new WifiNetworkAgentSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mWifiConfiguration, flags);
+ dest.writeInt(mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(@Nullable NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkSpecifier) {
+ return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other);
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be "
+ + "compared");
+ }
+ return false;
+ }
+
+ /**
+ * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
+ * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+ */
+ public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
+ // None of these should be null by construction.
+ // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}.
+ // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}.
+ checkNotNull(ns);
+ checkNotNull(ns.ssidPatternMatcher);
+ checkNotNull(ns.bssidPatternMatcher);
+ checkNotNull(ns.wifiConfiguration.allowedKeyManagement);
+ checkNotNull(this.mWifiConfiguration.SSID);
+ checkNotNull(this.mWifiConfiguration.BSSID);
+ checkNotNull(this.mWifiConfiguration.allowedKeyManagement);
+
+ final String ssidWithQuotes = this.mWifiConfiguration.SSID;
+ checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
+ final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
+ if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) {
+ return false;
+ }
+ final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID);
+ final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first;
+ final MacAddress matchMask = ns.bssidPatternMatcher.second;
+ if (!bssid.matches(matchBaseAddress, matchMask)) {
+ return false;
+ }
+ if (!ns.wifiConfiguration.allowedKeyManagement.equals(
+ this.mWifiConfiguration.allowedKeyManagement)) {
+ return false;
+ }
+ if (ns.requestorUid != this.mOriginalRequestorUid) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mWifiConfiguration.SSID,
+ mWifiConfiguration.BSSID,
+ mWifiConfiguration.allowedKeyManagement,
+ mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkAgentSpecifier)) {
+ return false;
+ }
+ WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj;
+ return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
+ && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
+ && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
+ lhs.mWifiConfiguration.allowedKeyManagement)
+ && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
+ sb.append(", WifiConfiguration=").append(
+ mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
+ .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
+ .append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
+ + "for requests.");
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
new file mode 100644
index 0000000..67e2189
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.net.MacAddress;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * WifiNetworkConfigBuilder to use for creating Wi-Fi network configuration.
+ * <li>See {@link #buildNetworkSpecifier()} for creating a network specifier to use in
+ * {@link NetworkRequest}.</li>
+ * <li>See {@link #buildNetworkSuggestion()} for creating a network suggestion to use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.</li>
+ */
+public class WifiNetworkConfigBuilder {
+ private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
+ private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
+ private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN =
+ new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
+ new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
+ MacAddress.BROADCAST_ADDRESS;
+ private static final int UNASSIGNED_PRIORITY = -1;
+
+ /**
+ * SSID pattern match specified by the app.
+ */
+ private @Nullable PatternMatcher mSsidPatternMatcher;
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher;
+ /**
+ * Pre-shared key for use with WPA-PSK networks.
+ */
+ private @Nullable String mPskPassphrase;
+ /**
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the EAP.
+ */
+ private @Nullable WifiEnterpriseConfig mEnterpriseConfig;
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private boolean mIsHiddenSSID;
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsAppInteractionRequired;
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsUserInteractionRequired;
+ /**
+ * Whether this network is metered or not.
+ */
+ private boolean mIsMetered;
+ /**
+ * Priority of this network among other network suggestions provided by the app.
+ * The lower the number, the higher the priority (i.e value of 0 = highest priority).
+ */
+ private int mPriority;
+
+ public WifiNetworkConfigBuilder() {
+ mSsidPatternMatcher = null;
+ mBssidPatternMatcher = null;
+ mPskPassphrase = null;
+ mEnterpriseConfig = null;
+ mIsHiddenSSID = false;
+ mIsAppInteractionRequired = false;
+ mIsUserInteractionRequired = false;
+ mIsMetered = false;
+ mPriority = UNASSIGNED_PRIORITY;
+ }
+
+ /**
+ * Set the unicode SSID match pattern to use for filtering networks from scan results.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssidPattern Instance of {@link PatternMatcher} containing the UTF-8 encoded
+ * string pattern to use for matching the network's SSID.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setSsidPattern(@NonNull PatternMatcher ssidPattern) {
+ checkNotNull(ssidPattern);
+ mSsidPatternMatcher = ssidPattern;
+ return this;
+ }
+
+ /**
+ * Set the unicode SSID for the network.
+ * <p>
+ * <li>For network requests ({@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, sets the SSID to use for filtering networks from scan
+ * results. Will only match networks whose SSID is identical to the UTF-8 encoding of the
+ * specified value.</li>
+ * <li>For network suggestions ({@link WifiNetworkSuggestion}), built using
+ * {@link #buildNetworkSuggestion()}, sets the SSID for the network.</li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssid The SSID of the network. It must be valid Unicode.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the SSID is not valid unicode.
+ */
+ public WifiNetworkConfigBuilder setSsid(@NonNull String ssid) {
+ checkNotNull(ssid);
+ final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder();
+ if (!unicodeEncoder.canEncode(ssid)) {
+ throw new IllegalArgumentException("SSID is not a valid unicode string");
+ }
+ mSsidPatternMatcher = new PatternMatcher(ssid, PatternMatcher.PATTERN_LITERAL);
+ return this;
+ }
+
+ /**
+ * Set the BSSID match pattern to use for filtering networks from scan results.
+ * Will match all networks with BSSID which satisfies the following:
+ * {@code BSSID & mask == baseAddress}.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param baseAddress Base address for BSSID pattern.
+ * @param mask Mask for BSSID pattern.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssidPattern(
+ @NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ checkNotNull(baseAddress, mask);
+ mBssidPatternMatcher = Pair.create(baseAddress, mask);
+ return this;
+ }
+
+ /**
+ * Set the BSSID to use for filtering networks from scan results. Will only match network whose
+ * BSSID is identical to the specified value.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param bssid BSSID of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssid(@NonNull MacAddress bssid) {
+ checkNotNull(bssid);
+ mBssidPatternMatcher = Pair.create(bssid, MATCH_EXACT_BSSID_PATTERN_MASK);
+ return this;
+ }
+
+ /**
+ * Set the ASCII PSK passphrase for this network. Needed for authenticating to
+ * WPA_PSK networks.
+ *
+ * @param pskPassphrase PSK passphrase of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+ */
+ public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) {
+ checkNotNull(pskPassphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(pskPassphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ mPskPassphrase = pskPassphrase;
+ return this;
+ }
+
+ /**
+ * Set the associated enterprise configuration for this network. Needed for authenticating to
+ * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description.
+ *
+ * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setEnterpriseConfig(
+ @NonNull WifiEnterpriseConfig enterpriseConfig) {
+ checkNotNull(enterpriseConfig);
+ mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ return this;
+ }
+
+ /**
+ * Specifies whether this represents a hidden network.
+ * <p>
+ * <li>For network requests (see {@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, setting this disallows the usage of
+ * {@link #setSsidPattern(PatternMatcher)} since hidden networks need to be explicitly
+ * probed for.</li>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsHiddenSsid() {
+ mIsHiddenSSID = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the app needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} will be sent after
+ * successfully connecting to the network.
+ * Use this for captive portal type networks where the app needs to authenticate the user
+ * before the device can access the network.
+ * This setting will be ignored if the {@code PendingIntent} used to add this network
+ * suggestion is null.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no app interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsAppInteractionRequired() {
+ mIsAppInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the user needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no user interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsUserInteractionRequired() {
+ mIsUserInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specify the priority of this network among other network suggestions provided by the same app
+ * (priorities have no impact on suggestions by different apps). The lower the number, the
+ * higher the priority (i.e value of 0 = highest priority).
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to -1 (i.e unassigned priority).</li>
+ *
+ * @param priority Integer number representing the priority among suggestions by the app.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the priority value is negative.
+ */
+ public WifiNetworkConfigBuilder setPriority(int priority) {
+ if (priority < 0) {
+ throw new IllegalArgumentException("Invalid priority value " + priority);
+ }
+ mPriority = priority;
+ return this;
+ }
+
+ /**
+ * Specifies whether this network is metered.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e not metered).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsMetered() {
+ mIsMetered = true;
+ return this;
+ }
+
+ /**
+ * Set defaults for the various low level credential type fields in the newly created
+ * WifiConfiguration object.
+ *
+ * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
+ * WifiConfiguration)}.
+ *
+ * @param configuration provided WifiConfiguration object.
+ */
+ private static void setDefaultsInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+ }
+
+ private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ if (!TextUtils.isEmpty(mPskPassphrase)) {
+ // WPA_PSK network.
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ } else if (mEnterpriseConfig != null) {
+ // WPA_EAP network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ } else {
+ // Open network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ }
+ }
+
+ /**
+ * Helper method to build WifiConfiguration object from the builder.
+ * @return Instance of {@link WifiConfiguration}.
+ */
+ private WifiConfiguration buildWifiConfiguration() {
+ final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ setDefaultsInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.SSID needs quotes around unicode SSID.
+ if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
+ wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
+ }
+ setKeyMgmtInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ if (mPskPassphrase != null) {
+ wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\"";
+ }
+ wifiConfiguration.enterpriseConfig = mEnterpriseConfig;
+ wifiConfiguration.hiddenSSID = mIsHiddenSSID;
+ wifiConfiguration.priority = mPriority;
+ wifiConfiguration.meteredOverride =
+ mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NONE;
+ return wifiConfiguration;
+ }
+
+ private boolean hasSetAnyPattern() {
+ return mSsidPatternMatcher != null || mBssidPatternMatcher != null;
+ }
+
+ private void setMatchAnyPatternIfUnset() {
+ if (mSsidPatternMatcher == null) {
+ mSsidPatternMatcher = new PatternMatcher(MATCH_ALL_SSID_PATTERN_PATH,
+ PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+ if (mBssidPatternMatcher == null) {
+ mBssidPatternMatcher = MATCH_ALL_BSSID_PATTERN;
+ }
+ }
+
+ private boolean hasSetMatchNonePattern() {
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX
+ && mSsidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) {
+ return true;
+ }
+ if (mBssidPatternMatcher.equals(MATCH_NO_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean hasSetMatchAllPattern() {
+ if ((mSsidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH))
+ && mBssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Create a specifier object used to request a Wi-Fi network. The generated
+ * {@link NetworkSpecifier} should be used in
+ * {@link NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} when building
+ * the {@link NetworkRequest}.
+ *<p>
+ * Note: Apps can set a combination of network match params:
+ * <li> SSID Pattern using {@link #setSsidPattern(PatternMatcher)} OR Specific SSID using
+ * {@link #setSsid(String)}. </li>
+ * AND/OR
+ * <li> BSSID Pattern using {@link #setBssidPattern(MacAddress, MacAddress)} OR Specific BSSID
+ * using {@link #setBssid(MacAddress)} </li>
+ * to trigger connection to a network that matches the set params.
+ * The system will find the set of networks matching the request and present the user
+ * with a system dialog which will allow the user to select a specific Wi-Fi network to connect
+ * to or to deny the request.
+ *</p>
+ *
+ * For example:
+ * To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23":
+ * {@code
+ * final NetworkSpecifier specifier =
+ * new WifiNetworkConfigBuilder()
+ * .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
+ * .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
+ * MacAddress.fromString("ff:ff:ff:00:00:00"))
+ * .buildNetworkSpecifier()
+ * final NetworkRequest request =
+ * new NetworkRequest.Builder()
+ * .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ * .setNetworkSpecifier(specifier)
+ * .build();
+ * final ConnectivityManager connectivityManager =
+ * context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ * final NetworkCallback networkCallback = new NetworkCallback() {
+ * ...
+ * {@literal @}Override
+ * void onAvailable(...) {}
+ * // etc.
+ * };
+ * connectivityManager.requestNetwork(request, networkCallback);
+ * }
+ *
+ * @return Instance of {@link NetworkSpecifier}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public NetworkSpecifier buildNetworkSpecifier() {
+ if (!hasSetAnyPattern()) {
+ throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/setBssid"
+ + " should be invoked for specifier");
+ }
+ setMatchAnyPatternIfUnset();
+ if (hasSetMatchNonePattern()) {
+ throw new IllegalStateException("cannot set match-none pattern for specifier");
+ }
+ if (hasSetMatchAllPattern()) {
+ throw new IllegalStateException("cannot set match-all pattern for specifier");
+ }
+ if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) {
+ throw new IllegalStateException("setSsid should also be invoked when "
+ + "setIsHiddenSsid is invoked for network specifier");
+ }
+ if (mIsAppInteractionRequired || mIsUserInteractionRequired
+ || mPriority != -1 || mIsMetered) {
+ throw new IllegalStateException("none of setIsAppInteractionRequired/"
+ + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for "
+ + "specifier");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + " be invoked for network specifier");
+ }
+
+ return new WifiNetworkSpecifier(
+ mSsidPatternMatcher,
+ mBssidPatternMatcher,
+ buildWifiConfiguration(),
+ Process.myUid());
+ }
+
+ /**
+ * Create a network suggestion object use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ * See {@link WifiNetworkSuggestion}.
+ *
+ * @return Instance of {@link WifiNetworkSuggestion}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public WifiNetworkSuggestion buildNetworkSuggestion() {
+ if (mSsidPatternMatcher == null) {
+ throw new IllegalStateException("setSsid should be invoked for suggestion");
+ }
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL
+ || mBssidPatternMatcher != null) {
+ throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are"
+ + " allowed for suggestion");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + "be invoked for suggestion");
+ }
+
+ return new WifiNetworkSuggestion(
+ buildWifiConfiguration(),
+ mIsAppInteractionRequired,
+ mIsUserInteractionRequired,
+ Process.myUid());
+
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
new file mode 100644
index 0000000..4348399b
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.util.Pair;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used to request a Wi-Fi network. Apps should use the
+ * {@link WifiNetworkConfigBuilder} class to create an instance.
+ * @hide
+ */
+public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * SSID pattern match specified by the app.
+ */
+ public final PatternMatcher ssidPatternMatcher;
+
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ public final Pair<MacAddress, MacAddress> bssidPatternMatcher;
+
+ /**
+ * Security credentials for the network.
+ * <p>
+ * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from
+ * WifiConfiguration are not used. Instead we use the {@link #ssidPatternMatcher} &
+ * {@link #bssidPatternMatcher} fields embedded directly
+ * within {@link WifiNetworkSpecifier}.
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * The UID of the process initializing this network specifier. Validated by receiver using
+ * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
+ * matches the offered network.
+ */
+ public final int requestorUid;
+
+ public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
+ @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
+ @NonNull WifiConfiguration wifiConfiguration,
+ int requestorUid) {
+ checkNotNull(ssidPatternMatcher);
+ checkNotNull(bssidPatternMatcher);
+ checkNotNull(wifiConfiguration);
+
+ this.ssidPatternMatcher = ssidPatternMatcher;
+ this.bssidPatternMatcher = bssidPatternMatcher;
+ this.wifiConfiguration = wifiConfiguration;
+ this.requestorUid = requestorUid;
+ }
+
+ public static final Creator<WifiNetworkSpecifier> CREATOR =
+ new Creator<WifiNetworkSpecifier>() {
+ @Override
+ public WifiNetworkSpecifier createFromParcel(Parcel in) {
+ PatternMatcher ssidPatternMatcher = in.readParcelable(/* classLoader */null);
+ MacAddress baseAddress = in.readParcelable(null);
+ MacAddress mask = in.readParcelable(null);
+ Pair<MacAddress, MacAddress> bssidPatternMatcher =
+ Pair.create(baseAddress, mask);
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int requestorUid = in.readInt();
+ return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
+ wifiConfiguration, requestorUid);
+ }
+
+ @Override
+ public WifiNetworkSpecifier[] newArray(int size) {
+ return new WifiNetworkSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(ssidPatternMatcher, flags);
+ dest.writeParcelable(bssidPatternMatcher.first, flags);
+ dest.writeParcelable(bssidPatternMatcher.second, flags);
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeInt(requestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
+ }
+ // Specific requests are checked for equality although testing for equality of 2 patterns do
+ // not make much sense!
+ return equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ ssidPatternMatcher.getPath(),
+ ssidPatternMatcher.getType(),
+ bssidPatternMatcher,
+ wifiConfiguration.allowedKeyManagement,
+ requestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSpecifier)) {
+ return false;
+ }
+ WifiNetworkSpecifier lhs = (WifiNetworkSpecifier) obj;
+ return Objects.equals(this.ssidPatternMatcher.getPath(),
+ lhs.ssidPatternMatcher.getPath())
+ && Objects.equals(this.ssidPatternMatcher.getType(),
+ lhs.ssidPatternMatcher.getType())
+ && Objects.equals(this.bssidPatternMatcher,
+ lhs.bssidPatternMatcher)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && requestorUid == lhs.requestorUid;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("WifiNetworkSpecifierWifiNetworkSpecifier [")
+ .append(", SSID Match pattern=").append(ssidPatternMatcher)
+ .append(", BSSID Match pattern=").append(bssidPatternMatcher)
+ .append(", WifiConfiguration=").append(
+ wifiConfiguration == null ? null : wifiConfiguration.configKey())
+ .append(", requestorUid=").append(requestorUid)
+ .append("]")
+ .toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ if (this.requestorUid != requestorUid) {
+ throw new SecurityException("mismatched UIDs");
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
new file mode 100644
index 0000000..04b9cb5
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Network Suggestion object is used to provide a Wi-Fi network for consideration when
+ * auto-connecting to networks. Apps cannot directly create this object, they must use
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} to obtain an instance
+ * of this object.
+ *<p>
+ * Apps can provide a list of such networks to the platform using
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ */
+public final class WifiNetworkSuggestion implements Parcelable {
+ /**
+ * Network configuration for the provided network.
+ * @hide
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} needs to be sent after
+ * successfully connecting to the network.
+ * @hide
+ */
+ public final boolean isAppInteractionRequired;
+
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ * @hide
+ */
+ public final boolean isUserInteractionRequired;
+
+ /**
+ * The UID of the process initializing this network suggestion.
+ * @hide
+ */
+ public final int suggestorUid;
+
+ /** @hide */
+ public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration,
+ boolean isAppInteractionRequired,
+ boolean isUserInteractionRequired,
+ int suggestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ this.wifiConfiguration = wifiConfiguration;
+ this.isAppInteractionRequired = isAppInteractionRequired;
+ this.isUserInteractionRequired = isUserInteractionRequired;
+ this.suggestorUid = suggestorUid;
+ }
+
+ public static final Creator<WifiNetworkSuggestion> CREATOR =
+ new Creator<WifiNetworkSuggestion>() {
+ @Override
+ public WifiNetworkSuggestion createFromParcel(Parcel in) {
+ return new WifiNetworkSuggestion(
+ in.readParcelable(null), // wifiConfiguration
+ in.readBoolean(), // isAppInteractionRequired
+ in.readBoolean(), // isUserInteractionRequired
+ in.readInt() // suggestorUid
+ );
+ }
+
+ @Override
+ public WifiNetworkSuggestion[] newArray(int size) {
+ return new WifiNetworkSuggestion[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeBoolean(isAppInteractionRequired);
+ dest.writeBoolean(isUserInteractionRequired);
+ dest.writeInt(suggestorUid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.allowedKeyManagement,
+ suggestorUid);
+ }
+
+ /**
+ * Equals for network suggestions.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSuggestion)) {
+ return false;
+ }
+ WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
+ return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && suggestorUid == lhs.suggestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
+ .append(", WifiConfiguration=").append(wifiConfiguration)
+ .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
+ .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
+ .append(", suggestorUid=").append(suggestorUid)
+ .append("]");
+ return sb.toString();
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 3b9f93e..5f3e1b2 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -155,7 +155,10 @@
@Test
public void testIsOpenNetwork_NotOpen_HasAuthType() {
for (int keyMgmt = 0; keyMgmt < WifiConfiguration.KeyMgmt.strings.length; keyMgmt++) {
- if (keyMgmt == WifiConfiguration.KeyMgmt.NONE) continue;
+ if (keyMgmt == WifiConfiguration.KeyMgmt.NONE
+ || keyMgmt == WifiConfiguration.KeyMgmt.OWE) {
+ continue;
+ }
WifiConfiguration config = new WifiConfiguration();
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(keyMgmt);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index e40b657a..ea41bb3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -43,6 +43,8 @@
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
+import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
+import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.net.wifi.WifiManager.SoftApCallback;
import android.net.wifi.WifiManager.TrafficStateCallback;
import android.os.Handler;
@@ -59,6 +61,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
/**
* Unit tests for {@link android.net.wifi.WifiManager}.
*/
@@ -67,16 +71,19 @@
private static final int ERROR_NOT_SET = -1;
private static final int ERROR_TEST_REASON = 5;
+ private static final int TEST_UID = 14553;
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String TEST_COUNTRY_CODE = "US";
@Mock Context mContext;
- @Mock IWifiManager mWifiService;
+ @Mock
+ android.net.wifi.IWifiManager mWifiService;
@Mock ApplicationInfo mApplicationInfo;
@Mock WifiConfiguration mApConfig;
@Mock IBinder mAppBinder;
@Mock SoftApCallback mSoftApCallback;
@Mock TrafficStateCallback mTrafficStateCallback;
+ @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
private Handler mHandler;
private TestLooper mLooper;
@@ -1163,4 +1170,84 @@
assertEquals(1, altLooper.dispatchAll());
verify(mTrafficStateCallback).onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT);
}
+
+ /**
+ * Verify the call to registerNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+
+ assertEquals(0, mLooper.dispatchAll());
+ callbackCaptor.getValue().onMatch(new ArrayList<WifiConfiguration>());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onMatch(anyList());
+
+ callbackCaptor.getValue().onUserSelectionConnectSuccess(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess(
+ any(WifiConfiguration.class));
+
+ callbackCaptor.getValue().onUserSelectionConnectFailure(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure(
+ any(WifiConfiguration.class));
+ }
+
+ /**
+ * Verify the call to unregisterNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception {
+ ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), any(INetworkRequestMatchCallback.class),
+ callbackIdentifier.capture());
+
+ mWifiManager.unregisterNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+ verify(mWifiService).unregisterNetworkRequestMatchCallback(
+ eq((int) callbackIdentifier.getValue()));
+ }
+
+ /**
+ * Verify the call to NetworkRequestUserSelectionCallback goes to
+ * WifiServiceImpl.
+ */
+ @Test
+ public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+ ArgumentCaptor<NetworkRequestUserSelectionCallback> userSelectionCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkRequestUserSelectionCallback.class);
+ callbackCaptor.getValue().onUserSelectionCallbackRegistration(
+ iUserSelectionCallback);
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ userSelectionCallbackCaptor.capture());
+
+ WifiConfiguration selected = new WifiConfiguration();
+ userSelectionCallbackCaptor.getValue().select(selected);
+ verify(iUserSelectionCallback).select(selected);
+
+ userSelectionCallbackCaptor.getValue().reject();
+ verify(iUserSelectionCallback).reject();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
new file mode 100644
index 0000000..1b0007c
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkAgentSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkAgentSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final int TEST_UID_1 = 8;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_SSID_PATTERN = "Test";
+ private static final String TEST_SSID_1 = "456test";
+ private static final String TEST_BSSID = "12:12:12:aa:0b:c0";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID_1 = "aa:cc:12:aa:0b:c0";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierParcel() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkAgentSpecifier parcelSpecifier =
+ WifiNetworkAgentSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ specifier.assertValidFromUid(TEST_UID);
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 equals specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierEqualsSame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotEqualsWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different SSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.SSID = TEST_SSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different BSSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenBssidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching.
+ * a) Create a network agent specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierSatisifiesNullAndAllMatch() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that invoking {@link NetworkSpecifier#satisfiedBy(NetworkSpecifier)} on 2
+ * {@link WifiNetworkAgentSpecifier} throws an exception.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifySame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID & BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching BSSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID and BSSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different key mgmt.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentKeyMgmt() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID_1);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ private WifiConfiguration createDefaultWifiConfiguration() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "\"" + TEST_SSID + "\"";
+ wifiConfiguration.BSSID = TEST_BSSID;
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ return wifiConfiguration;
+ }
+
+ private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
+ return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID);
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
new file mode 100644
index 0000000..8980ddb
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkConfigBuilder}.
+ */
+@SmallTest
+public class WifiNetworkConfigBuilderTest {
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID = "12:12:12:12:12:12";
+ private static final String TEST_PRESHARED_KEY = "Test123";
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for open network with SSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForOpenNetworkWithSsidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_PSK network with BSSID
+ * pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(".*", wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_SIMPLE_GLOB, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_MASK),
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_EAP network with
+ * SSID and BSSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .setEnterpriseConfig(enterpriseConfig)
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_LITERAL, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.BROADCAST_ADDRESS,
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
+ assertEquals(enterpriseConfig.getEapMethod(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
+ assertEquals(enterpriseConfig.getPhase2Method(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getPhase2Method());
+ }
+
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setSsid(String)} throws an exception
+ * when the string is not Unicode.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetSsidWithNonUnicodeString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid("\ud800")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception
+ * when the string is not ASCII encodable.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetPskPassphraseWithNonAsciiString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase("salvē")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when neither SSID nor BSSID patterns were set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithNoSsidAndBssidPattern() {
+ new WifiNetworkConfigBuilder().buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern1() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern2() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_ADVANCED_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern3() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_LITERAL))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBssidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setEnterpriseConfig(new WifiEnterpriseConfig())
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredAppInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsAppInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsUserInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredUserInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsUserInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setPriority(int)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSetPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPriority(4)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsMetered()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMetered() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsMetered()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for Open network which requires
+ * app interaction.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setIsAppInteractionRequired()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_EAP network which requires
+ * app interaction and has a priority of zero set.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsAppInteractionRequired()
+ .setPriority(0)
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(0, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_PSK network which requires
+ * user interaction and is metered.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsUserInteractionRequired()
+ .setIsMetered()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertFalse(suggestion.isAppInteractionRequired);
+ assertTrue(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssid(MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID),
+ MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssidPattern(MacAddress, MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssid() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsid(String)} is not set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithNoSsid() {
+ new WifiNetworkConfigBuilder()
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPriority(int)} throws an exception
+ * when the value is negative.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderWithInvalidPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPriority(-1)
+ .buildNetworkSuggestion();
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
new file mode 100644
index 0000000..856f0c7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSpecifierParcel() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSpecifier parcelSpecifier =
+ WifiNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create a network specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 is satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesSame() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = new WifiConfiguration();
+ wifiConfiguration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration1.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different SSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different BSSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenBssidDifferent() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
new file mode 100644
index 0000000..6bab60d
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static org.junit.Assert.*;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSuggestion}.
+ */
+@SmallTest
+public class WifiNetworkSuggestionTest {
+ private static final String TEST_SSID = "\"Test123\"";
+ private static final String TEST_SSID_1 = "\"Test1234\"";
+
+ /**
+ * Check that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSuggestionParcel() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, true, 0);
+
+ Parcel parcelW = Parcel.obtain();
+ suggestion.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSuggestion parcelSuggestion =
+ WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR);
+
+ // Two suggestion objects are considered equal if they point to the same network (i.e same
+ // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
+ // not considered for equality and hence needs to be checked for explicitly below.
+ assertEquals(suggestion, parcelSuggestion);
+ assertEquals(suggestion.isAppInteractionRequired,
+ parcelSuggestion.isAppInteractionRequired);
+ assertEquals(suggestion.isUserInteractionRequired,
+ parcelSuggestion.isUserInteractionRequired);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code true} for 2 network suggestions with the same
+ * SSID, key mgmt and UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsSame() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, true, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, true, 0);
+
+ assertEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * key mgmt and UID, but different SSID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenSsidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID_1;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and UID, but different key mgmt.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenKeyMgmtIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and key mgmt, but different UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration, false, false, 1);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+}