summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--api/current.txt60
-rw-r--r--api/system-current.txt10
-rw-r--r--api/test-current.txt26
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java2
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java8
-rw-r--r--cmds/webview_zygote/Android.mk51
-rw-r--r--cmds/webview_zygote/webview_zygote.cpp76
-rw-r--r--cmds/webview_zygote/webview_zygote32.rc22
-rw-r--r--cmds/webview_zygote/webview_zygote64.rc22
-rw-r--r--core/java/android/app/Dialog.java5
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java3
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java6
-rw-r--r--core/java/android/net/ConnectivityManager.java6
-rw-r--r--core/java/android/net/KeepalivePacketData.java14
-rw-r--r--core/java/android/net/NetworkCapabilities.java1
-rw-r--r--core/java/android/net/Uri.java19
-rw-r--r--core/java/android/net/metrics/NetworkMetrics.java3
-rw-r--r--core/java/android/os/ChildZygoteProcess.java44
-rw-r--r--core/java/android/os/ZygoteProcess.java55
-rw-r--r--core/java/android/provider/Settings.java21
-rw-r--r--core/java/android/se/omapi/ISecureElementListener.aidl1
-rw-r--r--core/java/android/se/omapi/SEService.java19
-rw-r--r--core/java/android/webkit/WebViewFactory.java4
-rw-r--r--core/java/android/webkit/WebViewZygote.java134
-rw-r--r--core/java/android/widget/AbsListView.java9
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java2
-rw-r--r--core/java/com/android/internal/os/WebViewZygoteInit.java29
-rw-r--r--core/java/com/android/internal/os/Zygote.java19
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java43
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java16
-rw-r--r--core/java/com/android/internal/os/ZygoteServer.java41
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java2
-rw-r--r--core/java/com/android/internal/view/menu/StandardMenuPopup.java12
-rw-r--r--core/java/com/android/server/SystemConfig.java18
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp24
-rw-r--r--core/jni/fd_utils.cpp8
-rw-r--r--core/proto/android/providers/settings.proto1
-rw-r--r--core/res/res/values/config.xml29
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/AndroidManifest.xml7
-rw-r--r--core/tests/coretests/res/layout/context_menu.xml54
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java3
-rw-r--r--core/tests/coretests/src/android/util/PollingCheck.java104
-rw-r--r--core/tests/coretests/src/android/view/menu/ContextMenuActivity.java54
-rw-r--r--core/tests/coretests/src/android/view/menu/ContextMenuTest.java93
-rw-r--r--core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java90
-rw-r--r--data/etc/Android.mk8
-rw-r--r--data/etc/hiddenapi-package-whitelist.xml101
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--media/java/android/media/AudioManager.java15
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java0
-rw-r--r--[-rwxr-xr-x]packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java0
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java1
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java3
-rw-r--r--services/core/java/com/android/server/NativeDaemonConnector.java14
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java167
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java77
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java30
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java2
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java13
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java44
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java3
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java6
-rw-r--r--services/core/java/com/android/server/pm/Installer.java6
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java10
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java7
-rw-r--r--services/core/java/com/android/server/pm/dex/DexoptOptions.java19
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java2
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java4
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java25
-rw-r--r--services/core/java/com/android/server/webkit/SystemImpl.java4
-rw-r--r--services/net/java/android/net/ip/IpClient.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java34
-rw-r--r--telecomm/java/android/telecom/Call.java30
-rw-r--r--telecomm/java/android/telecom/Connection.java59
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java12
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java13
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java2
-rw-r--r--telephony/java/android/telephony/LocationAccessPolicy.java160
-rw-r--r--telephony/java/android/telephony/MbmsDownloadSession.java86
-rw-r--r--telephony/java/android/telephony/MbmsStreamingSession.java42
-rw-r--r--telephony/java/android/telephony/ServiceState.java49
-rw-r--r--telephony/java/android/telephony/SignalStrength.java37
-rw-r--r--telephony/java/android/telephony/SmsManager.java245
-rw-r--r--telephony/java/android/telephony/SmsMessage.java26
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java6
-rw-r--r--telephony/java/android/telephony/Telephony.java17
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java146
-rw-r--r--telephony/java/android/telephony/UiccAccessRule.java9
-rw-r--r--telephony/java/android/telephony/data/DataProfile.java7
-rw-r--r--telephony/java/android/telephony/ims/ImsReasonInfo.java6
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java6
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java17
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java23
-rw-r--r--telephony/java/android/telephony/mbms/DownloadRequest.java189
-rw-r--r--telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java40
-rw-r--r--telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java30
-rw-r--r--telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java56
-rw-r--r--telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java40
-rw-r--r--telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java92
-rw-r--r--telephony/java/android/telephony/mbms/MbmsErrors.java4
-rw-r--r--telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java3
-rw-r--r--telephony/java/android/telephony/mbms/MbmsUtils.java2
-rw-r--r--telephony/java/android/telephony/mbms/StreamingService.java18
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl101
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl35
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java209
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java60
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java113
-rw-r--r--test-base/Android.bp22
-rw-r--r--test-base/Android.mk5
-rw-r--r--test-base/src/android/test/PerformanceTestCase.java5
-rw-r--r--test-legacy/Android.mk30
-rw-r--r--test-mock/Android.mk13
-rw-r--r--test-mock/api/android-test-mock-current.txt122
-rw-r--r--test-mock/api/android-test-mock-removed.txt1
-rw-r--r--test-runner/Android.bp8
-rw-r--r--test-runner/src/android/test/ComparisonFailure.java3
-rw-r--r--test-runner/src/android/test/TestSuiteProvider.java5
-rw-r--r--test-runner/src/junit/runner/BaseTestRunner.java2
-rw-r--r--tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java3
-rw-r--r--tests/net/java/android/net/IpSecTransformTest.java3
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java106
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java1
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java1
149 files changed, 3109 insertions, 1165 deletions
diff --git a/Android.mk b/Android.mk
index 71720a1740a5..2517f6b76319 100644
--- a/Android.mk
+++ b/Android.mk
@@ -151,7 +151,6 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
bouncycastle \
okhttp \
ext \
- icu4j \
framework \
voip-common \
android.test.mock \
@@ -694,6 +693,8 @@ LOCAL_SOURCE_FILES_ALL_GENERATED := true
LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto)
+# b/72714520
+LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/api/current.txt b/api/current.txt
index cd29286aacc6..8df028cd9c4c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35422,6 +35422,7 @@ package android.provider {
field public static final deprecated java.lang.String RADIO_NFC = "nfc";
field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
field public static final java.lang.String RINGTONE = "ringtone";
+ field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -37031,17 +37032,6 @@ package android.se.omapi {
method public byte[] transmit(byte[]) throws java.io.IOException;
}
- public abstract interface ISecureElementListener implements android.os.IInterface {
- method public abstract void serviceConnected() throws android.os.RemoteException;
- }
-
- public static abstract class ISecureElementListener.Stub extends android.os.Binder implements android.se.omapi.ISecureElementListener {
- ctor public ISecureElementListener.Stub();
- method public android.os.IBinder asBinder();
- method public static android.se.omapi.ISecureElementListener asInterface(android.os.IBinder);
- method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
- }
-
public class Reader {
method public void closeSessions();
method public java.lang.String getName();
@@ -37051,13 +37041,19 @@ package android.se.omapi {
}
public class SEService {
- ctor public SEService(android.content.Context, android.se.omapi.ISecureElementListener);
+ ctor public SEService(android.content.Context, android.se.omapi.SEService.SecureElementListener);
method public android.se.omapi.Reader[] getReaders();
method public java.lang.String getVersion();
method public boolean isConnected();
method public void shutdown();
}
+ public static abstract class SEService.SecureElementListener extends android.os.Binder {
+ ctor public SEService.SecureElementListener();
+ method public android.os.IBinder asBinder();
+ method public void serviceConnected();
+ }
+
public class Session {
method public void close();
method public void closeChannels();
@@ -39250,6 +39246,7 @@ package android.telecom {
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_RTT = 1024; // 0x400
field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -39380,6 +39377,7 @@ package android.telecom {
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
+ method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
method public final boolean isRingbackRequested();
method public void onAbort();
method public void onAnswer(int);
@@ -39398,8 +39396,10 @@ package android.telecom {
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onShowIncomingCallUi();
+ method public void onStartRtt(android.telecom.Connection.RttTextStream);
method public void onStateChanged(int);
method public void onStopDtmfTone();
+ method public void onStopRtt();
method public void onUnhold();
method public static java.lang.String propertiesToString(int);
method public final void putExtras(android.os.Bundle);
@@ -39407,6 +39407,10 @@ package android.telecom {
method public final void removeExtras(java.lang.String...);
method public void requestBluetoothAudio(java.lang.String);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
+ method public final void sendRemoteRttRequest();
+ method public final void sendRttInitiationFailure(int);
+ method public final void sendRttInitiationSuccess();
+ method public final void sendRttSessionRemotelyTerminated();
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -39461,6 +39465,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+ field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
@@ -39480,6 +39485,12 @@ package android.telecom {
field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
}
+ public static final class Connection.RttTextStream {
+ method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String readImmediately() throws java.io.IOException;
+ method public void write(java.lang.String) throws java.io.IOException;
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -39520,7 +39531,9 @@ package android.telecom {
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public android.net.Uri getAddress();
method public android.os.Bundle getExtras();
+ method public android.telecom.Connection.RttTextStream getRttTextStream();
method public int getVideoState();
+ method public boolean isRequestingRtt();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
}
@@ -40399,12 +40412,12 @@ package android.telephony {
public class MbmsDownloadSession implements java.lang.AutoCloseable {
method public int cancelDownload(android.telephony.mbms.DownloadRequest);
method public void close();
- method public static android.telephony.MbmsDownloadSession create(android.content.Context, android.telephony.mbms.MbmsDownloadSessionCallback, android.os.Handler);
- method public static android.telephony.MbmsDownloadSession create(android.content.Context, android.telephony.mbms.MbmsDownloadSessionCallback, int, android.os.Handler);
+ method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsDownloadSessionCallback);
+ method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsDownloadSessionCallback);
method public int download(android.telephony.mbms.DownloadRequest);
method public java.io.File getTempFileRootDirectory();
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
- method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback, android.os.Handler);
+ method public int registerStateCallback(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStateCallback);
method public void requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo);
method public void requestUpdateFileServices(java.util.List<java.lang.String>);
method public void resetDownloadKnowledge(android.telephony.mbms.DownloadRequest);
@@ -40432,10 +40445,10 @@ package android.telephony {
public class MbmsStreamingSession implements java.lang.AutoCloseable {
method public void close();
- method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, int, android.os.Handler);
- method public static android.telephony.MbmsStreamingSession create(android.content.Context, android.telephony.mbms.MbmsStreamingSessionCallback, android.os.Handler);
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsStreamingSessionCallback);
+ method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsStreamingSessionCallback);
method public void requestUpdateStreamingServices(java.util.List<java.lang.String>);
- method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler);
+ method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
}
public class NeighboringCellInfo implements android.os.Parcelable {
@@ -41263,20 +41276,23 @@ package android.telephony.gsm {
package android.telephony.mbms {
public final class DownloadRequest implements android.os.Parcelable {
- method public static android.telephony.mbms.DownloadRequest copy(android.telephony.mbms.DownloadRequest);
method public int describeContents();
+ method public android.net.Uri getDestinationUri();
method public java.lang.String getFileServiceId();
method public static int getMaxAppIntentSize();
method public static int getMaxDestinationUriSize();
method public android.net.Uri getSourceUri();
method public int getSubscriptionId();
+ method public byte[] toByteArray();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.mbms.DownloadRequest> CREATOR;
}
public static class DownloadRequest.Builder {
- ctor public DownloadRequest.Builder(android.net.Uri);
+ ctor public DownloadRequest.Builder(android.net.Uri, android.net.Uri);
method public android.telephony.mbms.DownloadRequest build();
+ method public static android.telephony.mbms.DownloadRequest.Builder fromDownloadRequest(android.telephony.mbms.DownloadRequest);
+ method public static android.telephony.mbms.DownloadRequest.Builder fromSerializedRequest(byte[]);
method public android.telephony.mbms.DownloadRequest.Builder setAppIntent(android.content.Intent);
method public android.telephony.mbms.DownloadRequest.Builder setServiceInfo(android.telephony.mbms.FileServiceInfo);
method public android.telephony.mbms.DownloadRequest.Builder setSubscriptionId(int);
@@ -41372,10 +41388,10 @@ package android.telephony.mbms {
method public java.util.Date getSessionStartTime();
}
- public class StreamingService {
+ public class StreamingService implements java.lang.AutoCloseable {
+ method public void close();
method public android.telephony.mbms.StreamingServiceInfo getInfo();
method public android.net.Uri getPlaybackUri();
- method public void stopStreaming();
field public static final int BROADCAST_METHOD = 1; // 0x1
field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
field public static final int REASON_END_OF_SESSION = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index d2c6bd064ac9..5a8f6e0fb748 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5103,7 +5103,6 @@ package android.telephony.ims.feature {
method public void setUiTtyMode(int, android.os.Message);
method public int shouldProcessCall(java.lang.String[]);
field public static final int PROCESS_CALL_CSFB = 1; // 0x1
- field public static final int PROCESS_CALL_EMERGENCY_CSFB = 2; // 0x2
field public static final int PROCESS_CALL_IMS = 0; // 0x0
}
@@ -5250,7 +5249,9 @@ package android.telephony.ims.stub {
method public final void onSmsReceived(int, java.lang.String, byte[]) throws java.lang.RuntimeException;
method public final void onSmsStatusReportReceived(int, int, java.lang.String, byte[]) throws java.lang.RuntimeException;
method public void sendSms(int, int, java.lang.String, java.lang.String, boolean, byte[]);
- field public static final int DELIVER_STATUS_ERROR = 2; // 0x2
+ field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2
+ field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3
+ field public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; // 0x4
field public static final int DELIVER_STATUS_OK = 1; // 0x1
field public static final int SEND_STATUS_ERROR = 2; // 0x2
field public static final int SEND_STATUS_ERROR_FALLBACK = 4; // 0x4
@@ -5287,12 +5288,7 @@ package android.telephony.ims.stub {
package android.telephony.mbms {
- public final class DownloadRequest implements android.os.Parcelable {
- method public byte[] getOpaqueData();
- }
-
public static class DownloadRequest.Builder {
- method public android.telephony.mbms.DownloadRequest.Builder setOpaqueData(byte[]);
method public android.telephony.mbms.DownloadRequest.Builder setServiceId(java.lang.String);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 50ad136fd8b8..bf3d0c251a4e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -426,32 +426,6 @@ package android.service.quicksettings {
}
-package android.telecom {
-
- public abstract class Connection extends android.telecom.Conferenceable {
- method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
- method public void onStartRtt(android.telecom.Connection.RttTextStream);
- method public void onStopRtt();
- method public final void sendRemoteRttRequest();
- method public final void sendRttInitiationFailure(int);
- method public final void sendRttInitiationSuccess();
- method public final void sendRttSessionRemotelyTerminated();
- field public static final int PROPERTY_IS_RTT = 256; // 0x100
- }
-
- public static final class Connection.RttTextStream {
- method public java.lang.String read() throws java.io.IOException;
- method public java.lang.String readImmediately() throws java.io.IOException;
- method public void write(java.lang.String) throws java.io.IOException;
- }
-
- public final class ConnectionRequest implements android.os.Parcelable {
- method public android.telecom.Connection.RttTextStream getRttTextStream();
- method public boolean isRequestingRtt();
- }
-
-}
-
package android.telephony {
public class MbmsDownloadSession implements java.lang.AutoCloseable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index ab075ee0e9f2..238cb65144a8 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -167,6 +167,8 @@ public class Am extends BaseCommand {
} else if (opt.equals("--no_window_animation")
|| opt.equals("--no-window-animation")) {
instrument.noWindowAnimation = true;
+ } else if (opt.equals("--no-hidden-api-checks")) {
+ instrument.disableHiddenApiChecks = true;
} else if (opt.equals("--user")) {
instrument.userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--abi")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index b69ef1c2fca5..432e8903ab2b 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -52,12 +52,17 @@ public class Instrument {
public boolean rawMode = false;
public boolean proto = false;
public boolean noWindowAnimation = false;
+ public boolean disableHiddenApiChecks = false;
public String abi = null;
public int userId = UserHandle.USER_CURRENT;
public Bundle args = new Bundle();
// Required
public String componentNameArg;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with ActivityManagerService.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
/**
* Construct the instrument command runner.
*/
@@ -416,7 +421,8 @@ public class Instrument {
}
// Start the instrumentation
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
+ int flags = disableHiddenApiChecks ? INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS : 0;
+ if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
diff --git a/cmds/webview_zygote/Android.mk b/cmds/webview_zygote/Android.mk
deleted file mode 100644
index 955e58ed933b..000000000000
--- a/cmds/webview_zygote/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := webview_zygote
-
-LOCAL_SRC_FILES := webview_zygote.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libbinder \
- liblog \
- libcutils \
- libutils
-
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-
-LOCAL_INIT_RC := webview_zygote32.rc
-
-# Always include the 32-bit version of webview_zygote. If the target is 64-bit,
-# also include the 64-bit webview_zygote.
-ifeq ($(TARGET_SUPPORTS_64_BIT_APPS),true)
- LOCAL_INIT_RC += webview_zygote64.rc
-endif
-
-LOCAL_MULTILIB := both
-
-LOCAL_MODULE_STEM_32 := webview_zygote32
-LOCAL_MODULE_STEM_64 := webview_zygote64
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/webview_zygote/webview_zygote.cpp b/cmds/webview_zygote/webview_zygote.cpp
deleted file mode 100644
index 88fee645b3ee..000000000000
--- a/cmds/webview_zygote/webview_zygote.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#define LOG_TAG "WebViewZygote"
-
-#include <sys/prctl.h>
-
-#include <android_runtime/AndroidRuntime.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-class WebViewRuntime : public AndroidRuntime {
-public:
- WebViewRuntime(char* argBlockStart, size_t argBlockSize)
- : AndroidRuntime(argBlockStart, argBlockSize) {}
-
- ~WebViewRuntime() override {}
-
- void onStarted() override {
- // Nothing to do since this is a zygote server.
- }
-
- void onVmCreated(JNIEnv*) override {
- // Nothing to do when the VM is created in the zygote.
- }
-
- void onZygoteInit() override {
- // Called after a new process is forked.
- sp<ProcessState> proc = ProcessState::self();
- proc->startThreadPool();
- }
-
- void onExit(int code) override {
- IPCThreadState::self()->stopProcess();
- AndroidRuntime::onExit(code);
- }
-};
-
-} // namespace android
-
-int main(int argc, char* const argv[]) {
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
- LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
- return 12;
- }
-
- size_t argBlockSize = 0;
- for (int i = 0; i < argc; ++i) {
- argBlockSize += strlen(argv[i]) + 1;
- }
-
- android::WebViewRuntime runtime(argv[0], argBlockSize);
- runtime.addOption("-Xzygote");
-
- android::Vector<android::String8> args;
- runtime.start("com.android.internal.os.WebViewZygoteInit", args, /*zygote=*/ true);
-}
diff --git a/cmds/webview_zygote/webview_zygote32.rc b/cmds/webview_zygote/webview_zygote32.rc
deleted file mode 100644
index b7decc8eba3b..000000000000
--- a/cmds/webview_zygote/webview_zygote32.rc
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-service webview_zygote32 /system/bin/webview_zygote32
- user webview_zygote
- socket webview_zygote stream 660 webview_zygote system
-
-on property:init.svc.zygote=stopped
- stop webview_zygote32
diff --git a/cmds/webview_zygote/webview_zygote64.rc b/cmds/webview_zygote/webview_zygote64.rc
deleted file mode 100644
index 2935b28cff55..000000000000
--- a/cmds/webview_zygote/webview_zygote64.rc
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-service webview_zygote64 /system/bin/webview_zygote64
- user webview_zygote
- socket webview_zygote stream 660 webview_zygote system
-
-on property:init.svc.zygote=stopped
- stop webview_zygote64
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index b162cb165fba..2eabd86c5da9 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -291,7 +291,10 @@ public class Dialog implements DialogInterface, Window.Callback,
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
- mDecor.setVisibility(View.VISIBLE);
+ if (mDecor.getVisibility() != View.VISIBLE) {
+ mDecor.setVisibility(View.VISIBLE);
+ sendShowMessage();
+ }
}
return;
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 0a0d21498032..605dbd21993f 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,9 +79,8 @@ public final class BluetoothUuid {
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
- /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
public static final ParcelUuid HearingAid =
- ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
+ ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 80fc8e3c2f16..8ea81a4aa99b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -35,6 +35,7 @@ import android.util.Printer;
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1459,7 +1460,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* @hide
*/
public boolean isAllowedToUseHiddenApi() {
- return isSystemApp();
+ boolean whitelisted =
+ SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+ return isSystemApp() || // TODO get rid of this once the whitelist has been populated
+ (whitelisted && (isSystemApp() || isUpdatedSystemApp()));
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2e701329dbfc..3a8a254e8b7e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1602,8 +1602,12 @@ public class ConnectivityManager {
/** The hardware returned an error. */
public static final int ERROR_HARDWARE_ERROR = -31;
+ /** The NAT-T destination port for IPsec */
public static final int NATT_PORT = 4500;
+ /** The minimum interval in seconds between keepalive packet transmissions */
+ public static final int MIN_INTERVAL = 10;
+
private final Network mNetwork;
private final PacketKeepaliveCallback mCallback;
private final Looper mLooper;
@@ -2662,7 +2666,7 @@ public class ConnectivityManager {
* A {@code NetworkCallback} is registered by calling
* {@link #requestNetwork(NetworkRequest, NetworkCallback)},
* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},
- * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is
+ * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is
* unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
* A {@code NetworkCallback} should be registered at most once at any time.
* A {@code NetworkCallback} that has been unregistered can be registered again.
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 08d4ff5da966..7436ad08789e 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -16,8 +16,8 @@
package android.net;
-import android.system.OsConstants;
-import android.net.ConnectivityManager;
+import static android.net.ConnectivityManager.PacketKeepalive.*;
+
import android.net.util.IpUtils;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,13 +25,10 @@ import android.system.OsConstants;
import android.util.Log;
import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import static android.net.ConnectivityManager.PacketKeepalive.*;
-
/**
* Represents the actual packets that are sent by the
* {@link android.net.ConnectivityManager.PacketKeepalive} API.
@@ -98,13 +95,6 @@ public class KeepalivePacketData implements Parcelable {
InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
throws InvalidPacketException {
- // FIXME: remove this and actually support IPv6 keepalives
- if (srcAddress instanceof Inet6Address && dstAddress instanceof Inet6Address) {
- // Optimistically returning an IPv6 Keepalive Packet with no data,
- // which currently only works on cellular
- return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, new byte[0]);
- }
-
if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 67521a0a0cf9..dae635de2a26 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -21,7 +21,6 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index d5377c717366..1bb4adcebc82 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.Nullable;
import android.content.Intent;
import android.os.Environment;
import android.os.Parcel;
@@ -23,6 +24,8 @@ import android.os.Parcelable;
import android.os.StrictMode;
import android.util.Log;
+import libcore.net.UriCodec;
+
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -38,8 +41,6 @@ import java.util.Objects;
import java.util.RandomAccess;
import java.util.Set;
-import libcore.net.UriCodec;
-
/**
* Immutable URI reference. A URI reference includes a URI and a fragment, the
* component of the URI following a '#'. Builds and parses URI references
@@ -174,6 +175,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the scheme or null if this is a relative URI
*/
+ @Nullable
public abstract String getScheme();
/**
@@ -208,6 +210,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the authority for this URI or null if not present
*/
+ @Nullable
public abstract String getAuthority();
/**
@@ -219,6 +222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the authority for this URI or null if not present
*/
+ @Nullable
public abstract String getEncodedAuthority();
/**
@@ -228,6 +232,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the user info for this URI or null if not present
*/
+ @Nullable
public abstract String getUserInfo();
/**
@@ -237,6 +242,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the user info for this URI or null if not present
*/
+ @Nullable
public abstract String getEncodedUserInfo();
/**
@@ -246,6 +252,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the host for this URI or null if not present
*/
+ @Nullable
public abstract String getHost();
/**
@@ -262,6 +269,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @return the decoded path, or null if this is not a hierarchical URI
* (like "mailto:nobody@google.com") or the URI is invalid
*/
+ @Nullable
public abstract String getPath();
/**
@@ -270,6 +278,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @return the encoded path, or null if this is not a hierarchical URI
* (like "mailto:nobody@google.com") or the URI is invalid
*/
+ @Nullable
public abstract String getEncodedPath();
/**
@@ -280,6 +289,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the decoded query or null if there isn't one
*/
+ @Nullable
public abstract String getQuery();
/**
@@ -290,6 +300,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the encoded query or null if there isn't one
*/
+ @Nullable
public abstract String getEncodedQuery();
/**
@@ -297,6 +308,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the decoded fragment or null if there isn't one
*/
+ @Nullable
public abstract String getFragment();
/**
@@ -304,6 +316,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the encoded fragment or null if there isn't one
*/
+ @Nullable
public abstract String getEncodedFragment();
/**
@@ -318,6 +331,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
*
* @return the decoded last segment or null if the path is empty
*/
+ @Nullable
public abstract String getLastPathSegment();
/**
@@ -1666,6 +1680,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
* @throws NullPointerException if key is null
* @return the decoded value or null if no parameter is found
*/
+ @Nullable
public String getQueryParameter(String key) {
if (isOpaque()) {
throw new UnsupportedOperationException(NOT_HIERARCHICAL);
diff --git a/core/java/android/net/metrics/NetworkMetrics.java b/core/java/android/net/metrics/NetworkMetrics.java
index 2425bba9e668..66d92c48087c 100644
--- a/core/java/android/net/metrics/NetworkMetrics.java
+++ b/core/java/android/net/metrics/NetworkMetrics.java
@@ -98,6 +98,9 @@ public class NetworkMetrics {
/** Accumulate a single netd sock_diag poll result reported by netd. */
public void addTcpStatsResult(int sent, int lost, int rttUs, int sentAckDiffMs) {
+ if (pendingSummary == null) {
+ pendingSummary = new Summary(netId, transports);
+ }
pendingSummary.tcpLossRate.count(lost, sent);
pendingSummary.roundTripTimeUs.count(rttUs);
pendingSummary.sentAckTimeDiffenceMs.count(sentAckDiffMs);
diff --git a/core/java/android/os/ChildZygoteProcess.java b/core/java/android/os/ChildZygoteProcess.java
new file mode 100644
index 000000000000..337a3e279a1a
--- /dev/null
+++ b/core/java/android/os/ChildZygoteProcess.java
@@ -0,0 +1,44 @@
+/*
+ * 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.os;
+
+import android.net.LocalSocketAddress;
+
+/**
+ * Represents a connection to a child-zygote process. A child-zygote is spawend from another
+ * zygote process using {@link startChildZygote()}.
+ *
+ * {@hide}
+ */
+public class ChildZygoteProcess extends ZygoteProcess {
+ /**
+ * The PID of the child zygote process.
+ */
+ private final int mPid;
+
+ ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) {
+ super(socketAddress, null);
+ mPid = pid;
+ }
+
+ /**
+ * Returns the PID of the child-zygote process.
+ */
+ public int getPid() {
+ return mPid;
+ }
+}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 4a976403e7a8..57418c8b9879 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
/*package*/ class ZygoteStartFailedEx extends Exception {
ZygoteStartFailedEx(String s) {
@@ -217,7 +218,8 @@ public class ZygoteProcess {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
+ zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -333,6 +335,8 @@ public class ZygoteProcess {
* @param abi the ABI the process should use.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
+ * @param startChildZygote Start a sub-zygote. This creates a new zygote process
+ * that has its state cloned from this zygote process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -348,6 +352,7 @@ public class ZygoteProcess {
String instructionSet,
String appDataDir,
String invokeWith,
+ boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -404,6 +409,10 @@ public class ZygoteProcess {
argsForZygote.add(invokeWith);
}
+ if (startChildZygote) {
+ argsForZygote.add("--start-child-zygote");
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
@@ -418,6 +427,18 @@ public class ZygoteProcess {
}
/**
+ * Closes the connections to the zygote, if they exist.
+ */
+ public void close() {
+ if (primaryZygoteState != null) {
+ primaryZygoteState.close();
+ }
+ if (secondaryZygoteState != null) {
+ secondaryZygoteState.close();
+ }
+ }
+
+ /**
* Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
* and retry if the zygote is unresponsive. This method is a no-op if a connection is
* already open.
@@ -549,4 +570,36 @@ public class ZygoteProcess {
}
Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
}
+
+ /**
+ * Starts a new zygote process as a child of this zygote. This is used to create
+ * secondary zygotes that inherit data from the zygote that this object
+ * communicates with. This returns a new ZygoteProcess representing a connection
+ * to the newly created zygote. Throws an exception if the zygote cannot be started.
+ */
+ public ChildZygoteProcess startChildZygote(final String processClass,
+ final String niceName,
+ int uid, int gid, int[] gids,
+ int runtimeFlags,
+ String seInfo,
+ String abi,
+ String instructionSet) {
+ // Create an unguessable address in the global abstract namespace.
+ final LocalSocketAddress serverAddress = new LocalSocketAddress(
+ processClass + "/" + UUID.randomUUID().toString());
+
+ final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};
+
+ Process.ProcessStartResult result;
+ try {
+ result = startViaZygote(processClass, niceName, uid, gid,
+ gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
+ abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
+ true /* startChildZygote */, extraArgs);
+ } catch (ZygoteStartFailedEx ex) {
+ throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
+ }
+
+ return new ChildZygoteProcess(serverAddress, result.pid);
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5dd4681112f9..36dcca69970c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3665,6 +3665,17 @@ public final class Settings {
public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
/**
+ * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+ * calls when supported by the device and carrier. Boolean value.
+ * 0 = OFF
+ * 1 = ON
+ */
+ public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+
+ /** @hide */
+ public static final Validator RTT_CALLING_MODE_VALIDATOR = sBooleanValidator;
+
+ /**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
@@ -3984,6 +3995,7 @@ public final class Settings {
DTMF_TONE_WHEN_DIALING,
DTMF_TONE_TYPE_WHEN_DIALING,
HEARING_AID,
+ RTT_CALLING_MODE,
TTY_MODE,
MASTER_MONO,
SOUND_EFFECTS_ENABLED,
@@ -4167,6 +4179,7 @@ public final class Settings {
VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+ VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
@@ -10371,6 +10384,14 @@ public final class Settings {
"storage_settings_clobber_threshold";
/**
+ * Exemptions to the hidden API blacklist.
+ *
+ * @hide
+ */
+ public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
+ "hidden_api_blacklist_exemptions";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/se/omapi/ISecureElementListener.aidl b/core/java/android/se/omapi/ISecureElementListener.aidl
index 3a99d634e4d1..e0c6e047c3d1 100644
--- a/core/java/android/se/omapi/ISecureElementListener.aidl
+++ b/core/java/android/se/omapi/ISecureElementListener.aidl
@@ -21,6 +21,7 @@ package android.se.omapi;
/**
* Interface to receive call-backs when the service is connected.
+ * @hide
*/
interface ISecureElementListener {
/**
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index b8937e69c143..d59e86a099b2 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -59,6 +59,21 @@ public class SEService {
*/
public static final int NO_SUCH_ELEMENT_ERROR = 2;
+ /**
+ * Interface to send call-backs to the application when the service is connected.
+ */
+ public abstract static class SecureElementListener extends ISecureElementListener.Stub {
+ @Override
+ public IBinder asBinder() {
+ return this;
+ }
+
+ /**
+ * Called by the framework when the service is connected.
+ */
+ public void serviceConnected() {};
+ }
+
private static final String TAG = "OMAPI.SEService";
private final Object mLock = new Object();
@@ -98,9 +113,9 @@ public class SEService {
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a ISecureElementListener object. Can be <code>null</code>.
+ * a SecureElementListener object. Can be <code>null</code>.
*/
- public SEService(Context context, ISecureElementListener listener) {
+ public SEService(Context context, SecureElementListener listener) {
if (context == null) {
throw new NullPointerException("context must not be null");
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 668cfba94071..d06a20ba3e98 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -463,7 +463,7 @@ public final class WebViewFactory {
*/
public static int onWebViewProviderChanged(PackageInfo packageInfo) {
String[] nativeLibs = null;
- String originalSourceDir = packageInfo.applicationInfo.sourceDir;
+ ApplicationInfo originalAppInfo = new ApplicationInfo(packageInfo.applicationInfo);
try {
fixupStubApplicationInfo(packageInfo.applicationInfo,
AppGlobals.getInitialApplication().getPackageManager());
@@ -474,7 +474,7 @@ public final class WebViewFactory {
Log.e(LOGTAG, "error preparing webview native library", t);
}
- WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir);
+ WebViewZygote.onWebViewProviderChanged(packageInfo, originalAppInfo);
return prepareWebViewInSystemServer(nativeLibs);
}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 0204dff9bf9d..d2923c4b8d12 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -17,31 +17,25 @@
package android.webkit;
import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.Build;
-import android.os.SystemService;
+import android.os.ChildZygoteProcess;
+import android.os.Process;
import android.os.ZygoteProcess;
import android.text.TextUtils;
-import android.util.AndroidRuntimeException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.TimeoutException;
/** @hide */
public class WebViewZygote {
private static final String LOGTAG = "WebViewZygote";
- private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
- private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
- private static final String WEBVIEW_ZYGOTE_SOCKET = "webview_zygote";
-
/**
* Lock object that protects all other static members.
*/
@@ -52,14 +46,7 @@ public class WebViewZygote {
* is not running or is not connected.
*/
@GuardedBy("sLock")
- private static ZygoteProcess sZygote;
-
- /**
- * Variable that allows us to determine whether the WebView zygote Service has already been
- * started.
- */
- @GuardedBy("sLock")
- private static boolean sStartedService = false;
+ private static ChildZygoteProcess sZygote;
/**
* Information about the selected WebView package. This is set from #onWebViewProviderChanged().
@@ -68,11 +55,11 @@ public class WebViewZygote {
private static PackageInfo sPackage;
/**
- * Cache key for the selected WebView package's classloader. This is set from
+ * Original ApplicationInfo for the selected WebView package before stub fixup. This is set from
* #onWebViewProviderChanged().
*/
@GuardedBy("sLock")
- private static String sPackageCacheKey;
+ private static ApplicationInfo sPackageOriginalAppInfo;
/**
* Flag for whether multi-process WebView is enabled. If this is false, the zygote
@@ -85,7 +72,7 @@ public class WebViewZygote {
synchronized (sLock) {
if (sZygote != null) return sZygote;
- waitForServiceStartAndConnect();
+ connectToZygoteIfNeededLocked();
return sZygote;
}
}
@@ -107,82 +94,43 @@ public class WebViewZygote {
sMultiprocessEnabled = enabled;
// When toggling between multi-process being on/off, start or stop the
- // service. If it is enabled and the zygote is not yet started, bring up the service.
- // Otherwise, bring down the service. The name may be null if the package
- // information has not yet been resolved.
- final String serviceName = getServiceNameLocked();
- if (serviceName == null) return;
-
+ // zygote. If it is enabled and the zygote is not yet started, launch it.
+ // Otherwise, kill it. The name may be null if the package information has
+ // not yet been resolved.
if (enabled) {
- if (!sStartedService) {
- SystemService.start(serviceName);
- sStartedService = true;
- }
+ connectToZygoteIfNeededLocked();
} else {
- SystemService.stop(serviceName);
- sStartedService = false;
- sZygote = null;
+ stopZygoteLocked();
}
}
}
- public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) {
+ public static void onWebViewProviderChanged(PackageInfo packageInfo,
+ ApplicationInfo originalAppInfo) {
synchronized (sLock) {
sPackage = packageInfo;
- sPackageCacheKey = cacheKey;
+ sPackageOriginalAppInfo = originalAppInfo;
// If multi-process is not enabled, then do not start the zygote service.
if (!sMultiprocessEnabled) {
return;
}
- final String serviceName = getServiceNameLocked();
- sZygote = null;
-
- // The service may enter the RUNNING state before it opens the socket,
- // so connectToZygoteIfNeededLocked() may still fail.
- if (SystemService.isStopped(serviceName)) {
- SystemService.start(serviceName);
- } else {
- SystemService.restart(serviceName);
- }
- sStartedService = true;
- }
- }
-
- private static void waitForServiceStartAndConnect() {
- if (!sStartedService) {
- throw new AndroidRuntimeException("Tried waiting for the WebView Zygote Service to " +
- "start running without first starting the service.");
- }
-
- String serviceName;
- synchronized (sLock) {
- serviceName = getServiceNameLocked();
- }
- try {
- SystemService.waitForState(serviceName, SystemService.State.RUNNING, 5000);
- } catch (TimeoutException e) {
- Log.e(LOGTAG, "Timed out waiting for " + serviceName);
- return;
- }
-
- synchronized (sLock) {
- connectToZygoteIfNeededLocked();
+ stopZygoteLocked();
}
}
@GuardedBy("sLock")
- private static String getServiceNameLocked() {
- if (sPackage == null)
- return null;
-
- if (Arrays.asList(Build.SUPPORTED_64_BIT_ABIS).contains(
- sPackage.applicationInfo.primaryCpuAbi)) {
- return WEBVIEW_ZYGOTE_SERVICE_64;
+ private static void stopZygoteLocked() {
+ if (sZygote != null) {
+ // Close the connection and kill the zygote process. This will not cause
+ // child processes to be killed by itself. But if this is called in response to
+ // setMultiprocessEnabled() or onWebViewProviderChanged(), the WebViewUpdater
+ // will kill all processes that depend on the WebView package.
+ sZygote.close();
+ Process.killProcess(sZygote.getPid());
+ sZygote = null;
}
-
- return WEBVIEW_ZYGOTE_SERVICE_32;
}
@GuardedBy("sLock")
@@ -196,14 +144,17 @@ public class WebViewZygote {
return;
}
- final String serviceName = getServiceNameLocked();
- if (!SystemService.isRunning(serviceName)) {
- Log.e(LOGTAG, serviceName + " is not running");
- return;
- }
-
try {
- sZygote = new ZygoteProcess(WEBVIEW_ZYGOTE_SOCKET, null);
+ sZygote = Process.zygoteProcess.startChildZygote(
+ "com.android.internal.os.WebViewZygoteInit",
+ "webview_zygote",
+ Process.WEBVIEW_ZYGOTE_UID,
+ Process.WEBVIEW_ZYGOTE_UID,
+ null, // gids
+ 0, // runtimeFlags
+ "webview_zygote", // seInfo
+ sPackage.applicationInfo.primaryCpuAbi, // abi
+ null); // instructionSet
// All the work below is usually done by LoadedApk, but the zygote can't talk to
// PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
@@ -218,14 +169,21 @@ public class WebViewZygote {
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
- ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
+ // In the case where the ApplicationInfo has been modified by the stub WebView,
+ // we need to use the original ApplicationInfo to determine what the original classpath
+ // would have been to use as a cache key.
+ LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
+ final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
+ TextUtils.join(File.pathSeparator, zipPaths);
+
+ ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
- sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey,
+ sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
Build.SUPPORTED_ABIS[0]);
} catch (Exception e) {
- Log.e(LOGTAG, "Error connecting to " + serviceName, e);
- sZygote = null;
+ Log.e(LOGTAG, "Error connecting to webview zygote", e);
+ stopZygoteLocked();
}
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 91e2f7d4ddd0..6c7455d35397 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3866,6 +3866,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private void onTouchDown(MotionEvent ev) {
mHasPerformedLongPress = false;
mActivePointerId = ev.getPointerId(0);
+ hideSelector();
if (mTouchMode == TOUCH_MODE_OVERFLING) {
// Stopped the fling. It is a scroll.
@@ -5226,17 +5227,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
mRecycler.fullyDetachScrapViews();
+ boolean selectorOnScreen = false;
if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
final int childIndex = mSelectedPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
positionSelector(mSelectedPosition, getChildAt(childIndex));
+ selectorOnScreen = true;
}
} else if (mSelectorPosition != INVALID_POSITION) {
final int childIndex = mSelectorPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
- positionSelector(INVALID_POSITION, getChildAt(childIndex));
+ positionSelector(mSelectorPosition, getChildAt(childIndex));
+ selectorOnScreen = true;
}
- } else {
+ }
+ if (!selectorOnScreen) {
mSelectorRect.setEmpty();
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 895be082c679..bb5a0ad86dd4 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -230,7 +230,7 @@ public class RuntimeInit {
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
- private static Runnable findStaticMain(String className, String[] argv,
+ protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index cadb66ae6e08..32b580c2d277 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -18,9 +18,11 @@ package com.android.internal.os;
import android.app.ApplicationLoaders;
import android.net.LocalSocket;
+import android.net.LocalServerSocket;
import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewFactory;
@@ -118,18 +120,35 @@ class WebViewZygoteInit {
}
public static void main(String argv[]) {
- sServer = new WebViewZygoteServer();
+ Log.i(TAG, "Starting WebViewZygoteInit");
+
+ String socketName = null;
+ for (String arg : argv) {
+ Log.i(TAG, arg);
+ if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+ socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
+ }
+ }
+ if (socketName == null) {
+ throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
+ }
- // Zygote goes into its own process group.
try {
- Os.setpgid(0, 0);
+ Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
} catch (ErrnoException ex) {
- throw new RuntimeException("Failed to setpgid(0,0)", ex);
+ throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
}
+ sServer = new WebViewZygoteServer();
+
final Runnable caller;
try {
- sServer.registerServerSocket("webview_zygote");
+ sServer.registerServerSocketAtAbstractName(socketName);
+
+ // Add the abstract socket to the FD whitelist so that the native zygote code
+ // can properly detach it after forking.
+ Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
+
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 89d63f60ebdd..e23cbf815b87 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -71,6 +71,13 @@ public final class Zygote {
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+ /**
+ * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
+ * in the abstract socket namespace. This socket name is what the new child zygote
+ * should listen for connections on.
+ */
+ public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
+
private Zygote() {}
/** Called for some security initialization before any fork. */
@@ -102,6 +109,8 @@ public final class Zygote {
* @param fdsToIgnore null-ok an array of ints, either null or holding
* one or more POSIX file descriptor numbers that are to be ignored
* in the file descriptor table check.
+ * @param startChildZygote if true, the new child process will itself be a
+ * new zygote process.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
*
@@ -110,13 +119,13 @@ public final class Zygote {
*/
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, String instructionSet, String appDataDir) {
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
- fdsToIgnore, instructionSet, appDataDir);
+ fdsToIgnore, startChildZygote, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
@@ -130,7 +139,7 @@ public final class Zygote {
native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, String instructionSet, String appDataDir);
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir);
/**
* Called to do any initialization before starting an application.
@@ -190,8 +199,8 @@ public final class Zygote {
native protected static void nativeUnmountStorageOnInit();
private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
- String instructionSet) {
- VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, instructionSet);
+ boolean isZygote, String instructionSet) {
+ VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
}
/**
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 6a87b1f4d3fd..a32fb4316d12 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -221,8 +221,8 @@ class ZygoteConnection {
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
- parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
- parsedArgs.appDataDir);
+ parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
+ parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {
@@ -233,7 +233,8 @@ class ZygoteConnection {
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
- return handleChildProc(parsedArgs, descriptors, childPipeFd);
+ return handleChildProc(parsedArgs, descriptors, childPipeFd,
+ parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
@@ -415,6 +416,14 @@ class ZygoteConnection {
boolean preloadDefault;
/**
+ * Whether this is a request to start a zygote process as a child of this zygote.
+ * Set with --start-child-zygote. The remaining arguments must include the
+ * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that
+ * should be used for communication.
+ */
+ boolean startChildZygote;
+
+ /**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
@@ -565,6 +574,8 @@ class ZygoteConnection {
preloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
preloadDefault = true;
+ } else if (arg.equals("--start-child-zygote")) {
+ startChildZygote = true;
} else {
break;
}
@@ -587,6 +598,20 @@ class ZygoteConnection {
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
}
+
+ if (startChildZygote) {
+ boolean seenChildSocketArg = false;
+ for (String arg : remainingArgs) {
+ if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+ seenChildSocketArg = true;
+ break;
+ }
+ }
+ if (!seenChildSocketArg) {
+ throw new IllegalArgumentException("--start-child-zygote specified " +
+ "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
+ }
+ }
}
}
@@ -739,9 +764,10 @@ class ZygoteConnection {
* @param parsedArgs non-null; zygote args
* @param descriptors null-ok; new file descriptors for stdio if available.
* @param pipeFd null-ok; pipe for communication back to Zygote.
+ * @param isZygote whether this new child process is itself a new Zygote.
*/
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
- FileDescriptor pipeFd) {
+ FileDescriptor pipeFd, boolean isZygote) {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
@@ -778,8 +804,13 @@ class ZygoteConnection {
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
- return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
- null /* classLoader */);
+ if (!isZygote) {
+ return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
+ null /* classLoader */);
+ } else {
+ return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
+ parsedArgs.remainingArgs, null /* classLoader */);
+ }
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4a3bb3cca1fc..a05454f53bf8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -576,7 +576,8 @@ public class ZygoteInit {
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null);
+ targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
+ "server-dexopt");
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -755,7 +756,7 @@ public class ZygoteInit {
throw new RuntimeException("No ABI list supplied.");
}
- zygoteServer.registerServerSocket(socketName);
+ zygoteServer.registerServerSocketFromEnv(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
@@ -870,5 +871,16 @@ public class ZygoteInit {
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
+ /**
+ * The main function called when starting a child zygote process. This is used as an
+ * alternative to zygoteInit(), which skips calling into initialization routines that
+ * start the Binder threadpool.
+ */
+ static final Runnable childZygoteInit(
+ int targetSdkVersion, String[] argv, ClassLoader classLoader) {
+ RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
+ return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
+ }
+
private static final native void nativeZygoteInit();
}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 8baa15a058de..fecf9b9da5dd 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -44,9 +44,21 @@ class ZygoteServer {
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
+ /**
+ * Listening socket that accepts new server connections.
+ */
private LocalServerSocket mServerSocket;
/**
+ * Whether or not mServerSocket's underlying FD should be closed directly.
+ * If mServerSocket is created with an existing FD, closing the socket does
+ * not close the FD and it must be closed explicitly. If the socket is created
+ * with a name instead, then closing the socket will close the underlying FD
+ * and it should not be double-closed.
+ */
+ private boolean mCloseSocketFd;
+
+ /**
* Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
*/
private boolean mIsForkChild;
@@ -59,11 +71,12 @@ class ZygoteServer {
}
/**
- * Registers a server socket for zygote command connections
+ * Registers a server socket for zygote command connections. This locates the server socket
+ * file descriptor through an ANDROID_SOCKET_ environment variable.
*
* @throws RuntimeException when open fails
*/
- void registerServerSocket(String socketName) {
+ void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
@@ -78,6 +91,7 @@ class ZygoteServer {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
+ mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
@@ -86,6 +100,22 @@ class ZygoteServer {
}
/**
+ * Registers a server socket for zygote command connections. This opens the server socket
+ * at the specified name in the abstract socket namespace.
+ */
+ void registerServerSocketAtAbstractName(String socketName) {
+ if (mServerSocket == null) {
+ try {
+ mServerSocket = new LocalServerSocket(socketName);
+ mCloseSocketFd = false;
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "Error binding to abstract socket '" + socketName + "'", ex);
+ }
+ }
+ }
+
+ /**
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
*/
@@ -112,7 +142,7 @@ class ZygoteServer {
if (mServerSocket != null) {
FileDescriptor fd = mServerSocket.getFileDescriptor();
mServerSocket.close();
- if (fd != null) {
+ if (fd != null && mCloseSocketFd) {
Os.close(fd);
}
}
@@ -219,6 +249,11 @@ class ZygoteServer {
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
+ } finally {
+ // Reset the child flag, in the event that the child process is a child-
+ // zygote. The flag will not be consulted this loop pass after the Runnable
+ // is returned.
+ mIsForkChild = false;
}
}
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 6af41a51f0dd..324f923674eb 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -256,7 +256,7 @@ public class MenuPopupHelper implements MenuHelper {
final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
if (hgrav == Gravity.RIGHT) {
- xOffset += mAnchorView.getWidth();
+ xOffset -= mAnchorView.getWidth();
}
popup.setHorizontalOffset(xOffset);
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index d9ca5be0502e..445379b1d9f4 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -263,7 +263,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
subPopup.setPresenterCallback(mPresenterCallback);
subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu));
- subPopup.setGravity(mDropDownGravity);
// Pass responsibility for handling onDismiss to the submenu.
subPopup.setOnDismissListener(mOnDismissListener);
@@ -273,8 +272,17 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On
mMenu.close(false /* closeAllMenus */);
// Show the new sub-menu popup at the same location as this popup.
- final int horizontalOffset = mPopup.getHorizontalOffset();
+ int horizontalOffset = mPopup.getHorizontalOffset();
final int verticalOffset = mPopup.getVerticalOffset();
+
+ // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT,
+ // So, again to display sub-menu popup in same xOffset, add the Anchor width.
+ final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
+ mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (hgrav == Gravity.RIGHT) {
+ horizontalOffset += mAnchorView.getWidth();
+ }
+
if (subPopup.tryShow(horizontalOffset, verticalOffset)) {
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 77788921635f..bdb5f99f1f35 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -60,6 +60,7 @@ public class SystemConfig {
private static final int ALLOW_PERMISSIONS = 0x04;
private static final int ALLOW_APP_CONFIGS = 0x08;
private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
+ private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x20;
private static final int ALLOW_ALL = ~0;
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
@@ -134,6 +135,9 @@ public class SystemConfig {
// These are the permitted backup transport service components
final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
+ // Package names that are exempted from private API blacklisting
+ final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>();
+
// These are the packages of carrier-associated apps which should be disabled until used until
// a SIM is inserted which grants carrier privileges to that carrier app.
final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
@@ -204,6 +208,10 @@ public class SystemConfig {
return mSystemUserBlacklistedApps;
}
+ public ArraySet<String> getHiddenApiWhitelistedApps() {
+ return mHiddenApiPackageWhitelist;
+ }
+
public ArraySet<ComponentName> getDefaultVrComponents() {
return mDefaultVrComponents;
}
@@ -327,6 +335,7 @@ public class SystemConfig {
boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
+ boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -569,6 +578,15 @@ public class SystemConfig {
XmlUtils.skipCurrentTag(parser);
} else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
readPrivAppPermissions(parser);
+ } else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<hidden-api-whitelisted-app> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mHiddenApiPackageWhitelist.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
} else {
XmlUtils.skipCurrentTag(parser);
continue;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fa86c7537d16..3f95cf460748 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -516,7 +516,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
jint mount_external,
jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
- jintArray fdsToIgnore,
+ jintArray fdsToIgnore, bool is_child_zygote,
jstring instructionSet, jstring dataDir) {
SetSignalHandlers();
@@ -699,7 +699,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
UnsetChldSignalHandler();
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
- is_system_server, instructionSet);
+ is_system_server, is_child_zygote, instructionSet);
if (env->ExceptionCheck()) {
RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
}
@@ -748,8 +748,7 @@ 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,
+ jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir) {
jlong capabilities = 0;
@@ -786,13 +785,22 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
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);
return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
- se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
+ se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
+ instructionSet, appDataDir);
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
@@ -803,7 +811,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
- NULL, NULL, NULL);
+ NULL, false, NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -877,7 +885,7 @@ static const JNINativeMethod gMethods[] = {
{ "nativeSecurityInit", "()V",
(void *) com_android_internal_os_Zygote_nativeSecurityInit },
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -892,7 +900,7 @@ static const JNINativeMethod gMethods[] = {
int register_com_android_internal_os_Zygote(JNIEnv* env) {
gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
- "(IZLjava/lang/String;)V");
+ "(IZZLjava/lang/String;)V");
return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
}
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 956b7249660f..1383bbd77b73 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -313,10 +313,12 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
return false;
}
- // This is a local socket with an abstract address, we do not accept it.
+ // This is a local socket with an abstract address. Remove the leading NUL byte and
+ // add a human-readable "ABSTRACT/" prefix.
if (unix_addr->sun_path[0] == '\0') {
- LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with abstract address.";
- return false;
+ *result = "ABSTRACT/";
+ result->append(&unix_addr->sun_path[1], path_len - 1);
+ return true;
}
// If we're here, sun_path must refer to a null terminated filesystem
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ef6eb0913da4..f78ebcaa1f79 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -335,6 +335,7 @@ message GlobalSettingsProto {
SettingProto uninstalled_instant_app_min_cache_period = 290;
SettingProto uninstalled_instant_app_max_cache_period = 291;
SettingProto unused_static_shared_lib_min_cache_period = 292;
+ SettingProto hidden_api_blacklist_exemptions = 293;
}
message SecureSettingsProto {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 701ed556bc70..23159f7b2fdc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1578,6 +1578,9 @@
<!-- Operating volatage for bluetooth controller. 0 by default-->
<integer translatable="false" name="config_bluetooth_operating_voltage_mv">0</integer>
+ <!-- Max number of connected audio devices supported by Bluetooth stack -->
+ <integer name="config_bluetooth_max_connected_audio_devices">1</integer>
+
<!-- Whether supported profiles should be reloaded upon enabling bluetooth -->
<bool name="config_bluetooth_reload_supported_profiles_when_enabled">false</bool>
@@ -2400,6 +2403,32 @@
in the display pipeline plus some slack just to be sure. -->
<integer name="config_drawLockTimeoutMillis">120</integer>
+ <!-- An array of device capabilities defined by GSMA SGP.22 v2.0.
+ The first item is the capability name that the device supports. The second item is the
+ major version. The minor and revision versions are default to 0s.
+ The device capabilities and their definition in the spec are:
+ gsm : gsmSupportedRelease
+ utran : utranSupportedRelease
+ cdma1x : cdma2000onexSupportedRelease
+ hrpd : cdma2000hrpdSupportedRelease
+ ehrpd : cdma2000ehrpdSupportedRelease
+ eutran : eutranSupportedRelease
+ nfc : contactlessSupportedRelease
+ crl : rspCrlSupportedVersion
+ -->
+ <string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
+ <!-- Example:
+ <item>"gsm,11"</item>
+ <item>"utran,11"</item>
+ <item>"cdma1x,1"</item>
+ <item>"hrpd,3"</item>
+ <item>"ehrpd,12"</item>
+ <item>"eutran,11"</item>
+ <item>"nfc,1"</item>
+ <item>"crl,1"</item>
+ -->
+ </string-array>
+
<!-- default telephony hardware configuration for this platform.
-->
<!-- this string array should be overridden by the device to present a list
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0aec47e66aa1..6396c4cdc935 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -395,6 +395,7 @@
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+ <java-symbol type="integer" name="config_bluetooth_max_connected_audio_devices" />
<java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
@@ -1195,6 +1196,7 @@
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" />
<java-symbol type="array" name="config_callBarringMMI" />
<java-symbol type="array" name="config_globalActionsList" />
+ <java-symbol type="array" name="config_telephonyEuiccDeviceCapabilities" />
<java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="array" name="config_keySystemUuidMapping" />
<java-symbol type="array" name="config_gpsParameters" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index ab9912a438d4..c0a8acda628e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1041,6 +1041,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml
new file mode 100644
index 000000000000..3b9e2bdb3130
--- /dev/null
+++ b/core/tests/coretests/res/layout/context_menu.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/context_menu_target_ltr"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="50px"
+ android:layout_marginEnd="50px">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="LTR"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/context_menu_target_rtl"
+ android:orientation="horizontal"
+ android:layoutDirection="rtl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="50px"
+ android:layout_marginEnd="50px">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="RTL"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ee276ef11957..757a70ca834e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -413,7 +413,8 @@ public class SettingsBackupTest {
Settings.Global.WTF_IS_FATAL,
Settings.Global.ZEN_MODE,
Settings.Global.ZEN_MODE_CONFIG_ETAG,
- Settings.Global.ZEN_MODE_RINGER_LEVEL);
+ Settings.Global.ZEN_MODE_RINGER_LEVEL,
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java
new file mode 100644
index 000000000000..468b9b2a4864
--- /dev/null
+++ b/core/tests/coretests/src/android/util/PollingCheck.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import org.junit.Assert;
+
+/**
+ * Utility used for testing that allows to poll for a certain condition to happen within a timeout.
+ *
+ * Code copied from com.android.compatibility.common.util.PollingCheck
+ */
+public abstract class PollingCheck {
+
+ private static final long DEFAULT_TIMEOUT = 3000;
+ private static final long TIME_SLICE = 50;
+ private final long mTimeout;
+
+ /**
+ * The condition that the PollingCheck should use to proceed successfully.
+ */
+ public interface PollingCheckCondition {
+
+ /**
+ * @return Whether the polling condition has been met.
+ */
+ boolean canProceed();
+ }
+
+ public PollingCheck(long timeout) {
+ mTimeout = timeout;
+ }
+
+ protected abstract boolean check();
+
+ /**
+ * Start running the polling check.
+ */
+ public void run() {
+ if (check()) {
+ return;
+ }
+
+ long timeout = mTimeout;
+ while (timeout > 0) {
+ try {
+ Thread.sleep(TIME_SLICE);
+ } catch (InterruptedException e) {
+ Assert.fail("unexpected InterruptedException");
+ }
+
+ if (check()) {
+ return;
+ }
+
+ timeout -= TIME_SLICE;
+ }
+
+ Assert.fail("unexpected timeout");
+ }
+
+ /**
+ * Instantiate and start polling for a given condition with a default 3000ms timeout.
+ *
+ * @param condition The condition to check for success.
+ */
+ public static void waitFor(final PollingCheckCondition condition) {
+ new PollingCheck(DEFAULT_TIMEOUT) {
+ @Override
+ protected boolean check() {
+ return condition.canProceed();
+ }
+ }.run();
+ }
+
+ /**
+ * Instantiate and start polling for a given condition.
+ *
+ * @param timeout Time out in ms
+ * @param condition The condition to check for success.
+ */
+ public static void waitFor(long timeout, final PollingCheckCondition condition) {
+ new PollingCheck(timeout) {
+ @Override
+ protected boolean check() {
+ return condition.canProceed();
+ }
+ }.run();
+ }
+}
+
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
new file mode 100644
index 000000000000..830b3d549773
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
@@ -0,0 +1,54 @@
+/*
+ * 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.menu;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+public class ContextMenuActivity extends Activity {
+
+ static final String LABEL_ITEM = "Item";
+ static final String LABEL_SUBMENU = "Submenu";
+ static final String LABEL_SUBITEM = "Subitem";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.context_menu);
+ registerForContextMenu(getTargetLtr());
+ registerForContextMenu(getTargetRtl());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ menu.add(LABEL_ITEM);
+ menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM);
+ }
+
+ View getTargetLtr() {
+ return findViewById(R.id.context_menu_target_ltr);
+ }
+
+ View getTargetRtl() {
+ return findViewById(R.id.context_menu_target_rtl);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
new file mode 100644
index 000000000000..59d4e55d8d45
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.menu;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.support.test.filters.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
+import android.util.PollingCheck;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.espresso.ContextMenuUtils;
+
+@MediumTest
+public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
+
+ public ContextMenuTest() {
+ super("com.android.frameworks.coretests", ContextMenuActivity.class);
+ }
+
+ public void testContextMenuPositionLtr() throws InterruptedException {
+ testMenuPosition(getActivity().getTargetLtr());
+ }
+
+ public void testContextMenuPositionRtl() throws InterruptedException {
+ testMenuPosition(getActivity().getTargetRtl());
+ }
+
+ private void testMenuPosition(View target) throws InterruptedException {
+ final int minScreenDimension = getMinScreenDimension();
+ if (minScreenDimension < 320) {
+ // Assume there is insufficient room for the context menu to be aligned properly.
+ return;
+ }
+
+ int offsetX = target.getWidth() / 2;
+ int offsetY = target.getHeight() / 2;
+
+ getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY));
+
+ PollingCheck.waitFor(
+ () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU));
+
+ ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+
+ ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU);
+
+ PollingCheck.waitFor(
+ () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM));
+
+ if (minScreenDimension < getCascadingMenuTreshold()) {
+ // A non-cascading submenu should be displayed at the same location as its parent.
+ // Not testing cascading submenu position, as it is positioned differently.
+ ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+ }
+ }
+
+ /**
+ * Returns the minimum of the default display's width and height.
+ */
+ private int getMinScreenDimension() {
+ final WindowManager windowManager = (WindowManager) getActivity().getSystemService(
+ Context.WINDOW_SERVICE);
+ final Display display = windowManager.getDefaultDisplay();
+ final Point displaySize = new Point();
+ display.getRealSize(displaySize);
+ return Math.min(displaySize.x, displaySize.y);
+ }
+
+ /**
+ * Returns the minimum display size where cascading submenus are supported.
+ */
+ private int getCascadingMenuTreshold() {
+ // Use the same dimension resource as in MenuPopupHelper.createPopup().
+ return getActivity().getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.cascading_menus_min_smallest_width);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
index c8218aa490f2..487a881082e7 100644
--- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -17,25 +17,32 @@
package android.widget.espresso;
import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
-import com.android.internal.view.menu.ListMenuItemView;
-
import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.matcher.ViewMatchers;
+import android.view.View;
import android.widget.MenuPopupWindow.MenuDropDownListView;
+import com.android.internal.view.menu.ListMenuItemView;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
/**
* Espresso utility methods for the context menu.
*/
@@ -82,10 +89,15 @@ public final class ContextMenuUtils {
private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
boolean enabled) {
onContextMenu().check(matches(
- hasDescendant(allOf(
- isAssignableFrom(ListMenuItemView.class),
- enabled ? isEnabled() : not(isEnabled()),
- hasDescendant(withText(itemLabel))))));
+ hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled))));
+ }
+
+ private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) {
+ return allOf(
+ isAssignableFrom(ListMenuItemView.class),
+ hasDescendant(withText(itemLabel)),
+ enabled ? isEnabled() : not(isEnabled()),
+ isDisplayingAtLeast(90));
}
/**
@@ -107,4 +119,70 @@ public final class ContextMenuUtils {
public static void assertContextMenuContainsItemDisabled(String itemLabel) {
asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
}
+
+ /**
+ * Asserts that the context menu window is aligned to a given view with a given offset.
+ *
+ * @param anchor Anchor view.
+ * @param offsetX x offset
+ * @param offsetY y offset.
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) {
+ int [] expectedLocation = new int[2];
+ anchor.getLocationOnScreen(expectedLocation);
+ expectedLocation[0] += offsetX;
+ expectedLocation[1] += offsetY;
+
+ final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+ onContextMenu().check(matches(new TypeSafeMatcher<View>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("root view ");
+ description.appendText(rtl ? "right" : "left");
+ description.appendText("=");
+ description.appendText(Integer.toString(offsetX));
+ description.appendText(", top=");
+ description.appendText(Integer.toString(offsetY));
+ }
+
+ @Override
+ public boolean matchesSafely(View view) {
+ View rootView = view.getRootView();
+ int [] actualLocation = new int[2];
+ rootView.getLocationOnScreen(actualLocation);
+ if (rtl) {
+ actualLocation[0] += rootView.getWidth();
+ }
+ return expectedLocation[0] == actualLocation[0]
+ && expectedLocation[1] == actualLocation[1];
+ }
+ }));
+ }
+
+ /**
+ * Check is the menu item is clickable (i.e. visible and enabled).
+ *
+ * @param itemLabel Label of the item.
+ * @return True if the menu item is clickable.
+ */
+ public static boolean isMenuItemClickable(String itemLabel) {
+ try {
+ onContextMenu().check(matches(
+ hasDescendant(getVisibleMenuItemMatcher(itemLabel, true))));
+ return true;
+ } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+ return false;
+ }
+ }
+
+ /**
+ * Click on a menu item with the specified label
+ * @param itemLabel Label of the item.
+ */
+ public static void clickMenuItem(String itemLabel) {
+ onView(getVisibleMenuItemMatcher(itemLabel, true))
+ .inRoot(withDecorView(hasFocus())).perform(click());
+ }
}
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index b2c68401d7e7..936ad22d4fc5 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -39,3 +39,11 @@ LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hiddenapi-package-whitelist.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/sysconfig
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
new file mode 100644
index 000000000000..1d46d42a9750
--- /dev/null
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -0,0 +1,101 @@
+<?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
+ -->
+
+<!--
+This XML file declares which system apps should be exempted from the hidden API blacklisting, i.e.
+which apps should be allowed to access the entire private API.
+-->
+
+<config>
+ <hidden-api-whitelisted-app package="android.car.cluster.loggingrenderer" />
+ <hidden-api-whitelisted-app package="android.car.input.service" />
+ <hidden-api-whitelisted-app package="android.car.usb.handler" />
+ <hidden-api-whitelisted-app package="android.ext.services" />
+ <hidden-api-whitelisted-app package="android.ext.shared" />
+ <hidden-api-whitelisted-app package="com.android.backupconfirm" />
+ <hidden-api-whitelisted-app package="com.android.bluetooth" />
+ <hidden-api-whitelisted-app package="com.android.bluetoothdebug" />
+ <hidden-api-whitelisted-app package="com.android.bluetoothmidiservice" />
+ <hidden-api-whitelisted-app package="com.android.calllogbackup" />
+ <hidden-api-whitelisted-app package="com.android.captiveportallogin" />
+ <hidden-api-whitelisted-app package="com.android.car" />
+ <hidden-api-whitelisted-app package="com.android.car.hvac" />
+ <hidden-api-whitelisted-app package="com.android.car.mapsplaceholder" />
+ <hidden-api-whitelisted-app package="com.android.car.media" />
+ <hidden-api-whitelisted-app package="com.android.car.media.localmediaplayer" />
+ <hidden-api-whitelisted-app package="com.android.car.radio" />
+ <hidden-api-whitelisted-app package="com.android.car.settings" />
+ <hidden-api-whitelisted-app package="com.android.car.systemupdater" />
+ <hidden-api-whitelisted-app package="com.android.car.trust" />
+ <hidden-api-whitelisted-app package="com.android.carrierconfig" />
+ <hidden-api-whitelisted-app package="com.android.carrierdefaultapp" />
+ <hidden-api-whitelisted-app package="com.android.cellbroadcastreceiver" />
+ <hidden-api-whitelisted-app package="com.android.certinstaller" />
+ <hidden-api-whitelisted-app package="com.android.customlocale2" />
+ <hidden-api-whitelisted-app package="com.android.defcontainer" />
+ <hidden-api-whitelisted-app package="com.android.documentsui" />
+ <hidden-api-whitelisted-app package="com.android.egg" />
+ <hidden-api-whitelisted-app package="com.android.email.policy" />
+ <hidden-api-whitelisted-app package="com.android.emergency" />
+ <hidden-api-whitelisted-app package="com.android.externalstorage" />
+ <hidden-api-whitelisted-app package="com.android.fakeoemfeatures" />
+ <hidden-api-whitelisted-app package="com.android.gallery" />
+ <hidden-api-whitelisted-app package="com.android.hotspot2" />
+ <hidden-api-whitelisted-app package="com.android.inputdevices" />
+ <hidden-api-whitelisted-app package="com.android.keychain" />
+ <hidden-api-whitelisted-app package="com.android.location.fused" />
+ <hidden-api-whitelisted-app package="com.android.managedprovisioning" />
+ <hidden-api-whitelisted-app package="com.android.mms.service" />
+ <hidden-api-whitelisted-app package="com.android.mtp" />
+ <hidden-api-whitelisted-app package="com.android.nfc" />
+ <hidden-api-whitelisted-app package="com.android.osu" />
+ <hidden-api-whitelisted-app package="com.android.packageinstaller" />
+ <hidden-api-whitelisted-app package="com.android.pacprocessor" />
+ <hidden-api-whitelisted-app package="com.android.phone" />
+ <hidden-api-whitelisted-app package="com.android.pmc" />
+ <hidden-api-whitelisted-app package="com.android.providers.blockednumber" />
+ <hidden-api-whitelisted-app package="com.android.providers.contacts" />
+ <hidden-api-whitelisted-app package="com.android.providers.downloads" />
+ <hidden-api-whitelisted-app package="com.android.providers.downloads.ui" />
+ <hidden-api-whitelisted-app package="com.android.providers.media" />
+ <hidden-api-whitelisted-app package="com.android.providers.settings" />
+ <hidden-api-whitelisted-app package="com.android.providers.telephony" />
+ <hidden-api-whitelisted-app package="com.android.providers.userdictionary" />
+ <hidden-api-whitelisted-app package="com.android.provision" />
+ <hidden-api-whitelisted-app package="com.android.proxyhandler" />
+ <hidden-api-whitelisted-app package="com.android.sdksetup" />
+ <hidden-api-whitelisted-app package="com.android.se" />
+ <hidden-api-whitelisted-app package="com.android.server.telecom" />
+ <hidden-api-whitelisted-app package="com.android.service.ims" />
+ <hidden-api-whitelisted-app package="com.android.service.ims.presence" />
+ <hidden-api-whitelisted-app package="com.android.settings" />
+ <hidden-api-whitelisted-app package="com.android.sharedstoragebackup" />
+ <hidden-api-whitelisted-app package="com.android.shell" />
+ <hidden-api-whitelisted-app package="com.android.stk" />
+ <hidden-api-whitelisted-app package="com.android.support.car.lenspicker" />
+ <hidden-api-whitelisted-app package="com.android.systemui" />
+ <hidden-api-whitelisted-app package="com.android.systemui.theme.dark" />
+ <hidden-api-whitelisted-app package="com.android.timezone.updater" />
+ <hidden-api-whitelisted-app package="com.android.traceur" />
+ <hidden-api-whitelisted-app package="com.android.tv.settings" />
+ <hidden-api-whitelisted-app package="com.android.vpndialogs" />
+ <hidden-api-whitelisted-app package="com.android.wallpaper.livepicker" />
+ <hidden-api-whitelisted-app package="com.android.wallpaperbackup" />
+ <hidden-api-whitelisted-app package="com.android.wallpapercropper" />
+ <hidden-api-whitelisted-app package="com.googlecode.android_scripting" />
+</config>
+
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 16c2b6894fc8..0af187c3fe45 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -147,6 +147,7 @@ applications that come with the platform
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
<permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 339c7678bef8..ede172c225ef 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3606,6 +3606,21 @@ public class AudioManager {
}
/**
+ * Indicate Hearing Aid connection state change.
+ * @param device Bluetooth device connected/disconnected
+ * @param state new connection state (BluetoothProfile.STATE_xxx)
+ * {@hide}
+ */
+ public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) {
+ final IAudioService service = getService();
+ try {
+ service.setHearingAidDeviceConnectionState(device, state);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Indicate A2DP source or sink connection state change.
* @param device Bluetooth device connected/disconnected
* @param state new connection state (BluetoothProfile.STATE_xxx)
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 6c6522328e8d..07b6bbdb2f42 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -143,6 +143,8 @@ interface IAudioService {
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
+ void setHearingAidDeviceConnectionState(in BluetoothDevice device, int state);
+
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 853cbbadbdac..853cbbadbdac 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index a1c8de566578..a1c8de566578 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 3cda9c9e3789..3cda9c9e3789 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index c3ff617bfaa7..c3ff617bfaa7 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index ee1219126fe3..ee1219126fe3 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 169aac9eb60f..169aac9eb60f 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 213002fb9726..213002fb9726 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index abcb989802e9..abcb989802e9 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index 31e675c2355b..31e675c2355b 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 3299cb2d1221..3299cb2d1221 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 28137ff64fb5..28137ff64fb5 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 58465f299578..58465f299578 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index ec45b7e91700..ec45b7e91700 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
index 1bbc878b56c9..1bbc878b56c9 100755..100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d256b12fe285..d32db8491b3a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -924,6 +924,9 @@ class SettingsProtoDumpUtil {
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED);
dumpSetting(s, p,
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+ GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+ dumpSetting(s, p,
Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 81b8622c548f..4320b6aa572c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -76,6 +76,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
@Override
public void handleSetListening(boolean listening) {
+ if (mController == null) return;
if (listening) {
mController.addCallback(mCallback);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 9e265e2295c3..52b4c0ac4e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -235,6 +235,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
public void handleSetListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
+ if (mController == null) return;
if (mListening) {
mController.addCallback(mZenCallback);
Prefs.registerListener(mContext, mPrefListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index b3ff4e5b890c..12daff1f12f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -98,6 +98,8 @@ public class NfcTile extends QSTileImpl<BooleanState> {
protected void handleUpdateState(BooleanState state, Object arg) {
final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+
+ if (getAdapter() == null) return;
state.value = getAdapter().isEnabled();
state.label = mContext.getString(R.string.quick_settings_nfc_label);
state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 23702736b0db..fdbb260f39bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -76,6 +76,7 @@ public class WifiTile extends QSTileImpl<SignalState> {
@Override
public void handleSetListening(boolean listening) {
+ if (mController == null) return;
if (listening) {
mController.addCallback(mSignalCallback);
} else {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index af55807ff1f0..93df50747723 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -342,7 +342,8 @@ final class RemoteFillService implements DeathRecipient {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mDestroyed || !mBinding) {
- mContext.unbindService(mServiceConnection);
+ // This is abnormal. Unbinding the connection has been requested already.
+ Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService.");
return;
}
mBinding = false;
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index b5a8332375f4..ad02aad6e4cd 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -134,21 +134,23 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
mCallbackHandler = new Handler(mLooper, this);
while (true) {
+ if (isShuttingDown()) break;
try {
listenToSocket();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
- String shutdownAct = SystemProperties.get(
- ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
- if (shutdownAct != null && shutdownAct.length() > 0) {
- // The device is in middle of shutdown.
- break;
- }
+ if (isShuttingDown()) break;
SystemClock.sleep(5000);
}
}
}
+ private static boolean isShuttingDown() {
+ String shutdownAct = SystemProperties.get(
+ ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
+ return shutdownAct != null && shutdownAct.length() > 0;
+ }
+
@Override
public boolean handleMessage(Message msg) {
final String event = (String) msg.obj;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5e5eacb5c767..8b5176e2c858 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DisconnectCause;
+import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneStateListener;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -55,6 +56,7 @@ import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.PhoneConstantConversions;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.BatteryStatsService;
@@ -96,7 +98,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
- int callerUserId;
+ int callerUid;
+ int callerPid;
int events;
@@ -120,7 +123,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " callback=" + callback
+ " onSubscriptionsChangedListenererCallback="
+ onSubscriptionsChangedListenerCallback
- + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
+ + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
+ " events=" + Integer.toHexString(events)
+ " canReadPhoneState=" + canReadPhoneState + "}";
}
@@ -374,26 +377,17 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void addOnSubscriptionsChangedListener(String callingPackage,
IOnSubscriptionsChangedListener callback) {
int callerUserId = UserHandle.getCallingUserId();
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
+ " callerUserId=" + callerUserId + " callback=" + callback
+ " callback.asBinder=" + callback.asBinder());
}
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
- "addOnSubscriptionsChangedListener");
- // SKIP checking for run-time permission since caller or self has PRIVILEGED permission
- } catch (SecurityException e) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE,
- "addOnSubscriptionsChangedListener");
-
- if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
- }
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+ mContext, callingPackage, "addOnSubscriptionsChangedListener")) {
+ return;
}
@@ -408,7 +402,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.onSubscriptionsChangedListenerCallback = callback;
r.callingPackage = callingPackage;
- r.callerUserId = callerUserId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
r.events = 0;
r.canReadPhoneState = true; // permission has been enforced above
if (DBG) {
@@ -479,6 +474,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private void listen(String callingPackage, IPhoneStateListener callback, int events,
boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -486,23 +483,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if (events != PhoneStateListener.LISTEN_NONE) {
- /* Checks permission and throws Security exception */
- checkListenerPermission(events);
-
- if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
- // SKIP checking for run-time permission since caller or self has PRIVILEGED
- // permission
- } catch (SecurityException e) {
- if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
- }
- }
+ // Checks permission and throws SecurityException for disallowed operations. For pre-M
+ // apps whose runtime permission has been revoked, we return immediately to skip sending
+ // events to the app without crashing it.
+ if (!checkListenerPermission(events, callingPackage, "listen")) {
+ return;
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
// register
IBinder b = callback.asBinder();
@@ -514,10 +502,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback = callback;
r.callingPackage = callingPackage;
- r.callerUserId = callerUserId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
| ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
- r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
+ r.canReadPhoneState =
+ isPhoneStateEvent && canReadPhoneState(callingPackage, "listen");
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -525,9 +515,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
} else {//APP specify subID
r.subId = subId;
}
- r.phoneId = SubscriptionManager.getPhoneId(r.subId);
-
- int phoneId = r.phoneId;
+ r.phoneId = phoneId;
r.events = events;
if (DBG) {
log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
@@ -572,8 +560,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellLocation = "
+ mCellLocation[phoneId]);
- r.callback.onCellLocationChanged(
- new Bundle(mCellLocation[phoneId]));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellLocationChanged(
+ new Bundle(mCellLocation[phoneId]));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -619,7 +609,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -675,21 +667,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- private boolean canReadPhoneState(String callingPackage) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) ==
- PackageManager.PERMISSION_GRANTED) {
- // SKIP checking for run-time permission since caller or self has PRIVILEGED permission
- return true;
- }
- boolean canReadPhoneState = mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
- if (canReadPhoneState &&
- mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ private boolean canReadPhoneState(String callingPackage, String message) {
+ try {
+ return TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+ mContext, callingPackage, message);
+ } catch (SecurityException e) {
return false;
}
- return canReadPhoneState;
}
private String getCallIncomingNumber(Record record, int phoneId) {
@@ -1013,14 +997,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyCellInfoForSubscriber: subId=" + subId
+ " cellInfo=" + cellInfo);
}
-
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
mCellInfo.set(phoneId, cellInfo);
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
- idMatch(r.subId, subId, phoneId)) {
+ idMatch(r.subId, subId, phoneId) &&
+ checkLocationAccess(r)) {
try {
if (DBG_LOC) {
log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1103,8 +1087,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyCallForwardingChangedForSubscriber: subId=" + subId
+ " cfi=" + cfi);
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
mCallForwarding[phoneId] = cfi;
for (Record r : mRecords) {
@@ -1131,8 +1115,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
mDataActivity[phoneId] = state;
for (Record r : mRecords) {
@@ -1173,8 +1157,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
+ " mRecords.size()=" + mRecords.size());
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
boolean modified = false;
if (state == TelephonyManager.DATA_CONNECTED) {
@@ -1297,13 +1281,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyCellLocationForSubscriber: subId=" + subId
+ " cellLocation=" + cellLocation);
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
mCellLocation[phoneId] = cellLocation;
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
- idMatch(r.subId, subId, phoneId)) {
+ idMatch(r.subId, subId, phoneId) &&
+ checkLocationAccess(r)) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1660,11 +1645,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
- if (checkNotifyPermission()) {
+ if (checkNotifyPermission()) {
return;
}
- enforceCarrierPrivilege();
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ SubscriptionManager.getDefaultSubscriptionId(), method);
}
private boolean checkNotifyPermission(String method) {
@@ -1682,23 +1668,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
== PackageManager.PERMISSION_GRANTED;
}
- private void enforceCarrierPrivilege() {
- TelephonyManager tm = TelephonyManager.getDefault();
- String[] pkgs = mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
- for (String pkg : pkgs) {
- if (tm.checkCarrierPrivilegesForPackage(pkg) ==
- TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return;
- }
- }
-
- String msg = "Carrier Privilege Permission Denial: from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid();
- if (DBG) log(msg);
- throw new SecurityException(msg);
- }
-
- private void checkListenerPermission(int events) {
+ private boolean checkListenerPermission(int events, String callingPackage, String message) {
if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
@@ -1712,22 +1682,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
- // SKIP checking for run-time permission since caller or self has PRIVILEGED
- // permission
- } catch (SecurityException e) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE, null);
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+ mContext, callingPackage, message)) {
+ return false;
}
}
if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
-
}
+
+ return true;
}
private void handleRemoveListLocked() {
@@ -1747,10 +1713,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
- valid = r.callerUserId == foregroundUser && r.matchPhoneStateListenerEvent(events);
+ valid = UserHandle.getUserId(r.callerUid) == foregroundUser
+ && r.matchPhoneStateListenerEvent(events);
if (DBG | DBG_LOC) {
log("validateEventsAndUserLocked: valid=" + valid
- + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser
+ + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
+ " r.events=" + r.events + " events=" + events);
}
} finally {
@@ -1782,6 +1749,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ private boolean checkLocationAccess(Record r) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return LocationAccessPolicy.canAccessCellLocation(mContext,
+ r.callingPackage, r.callerUid, r.callerPid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void checkPossibleMissNotify(Record r, int phoneId) {
int events = r.events;
@@ -1829,7 +1806,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1877,7 +1856,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
+ mCellLocation[phoneId]);
- r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0cce2d9ae56d..6c60b74bbd24 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -533,6 +533,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with Am.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
// How long to wait in getAssistContextExtras for the activity and foreground services
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -1738,6 +1742,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final ActivityManagerConstants mConstants;
+ // Encapsulates the global setting "hidden_api_blacklist_exemptions"
+ final HiddenApiBlacklist mHiddenApiBlacklist;
+
PackageManagerInternal mPackageManagerInt;
// VoiceInteraction session ID that changes for each new request except when
@@ -2687,6 +2694,42 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
+ * latest value via a content observer.
+ */
+ static class HiddenApiBlacklist extends ContentObserver {
+
+ private final Context mContext;
+ private boolean mBlacklistDisabled;
+
+ public HiddenApiBlacklist(Handler handler, Context context) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void registerObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+ false,
+ this);
+ update();
+ }
+
+ private void update() {
+ mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
+ }
+
+ boolean isDisabled() {
+ return mBlacklistDisabled;
+ }
+
+ public void onChange(boolean selfChange) {
+ update();
+ }
+ }
+
@VisibleForTesting
public ActivityManagerService(Injector injector) {
mInjector = injector;
@@ -2716,6 +2759,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mUiHandler = injector.getUiHandler(null);
mUserController = null;
mVrController = null;
+ mHiddenApiBlacklist = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2848,6 +2892,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
};
+ mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext);
+
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
@@ -3771,6 +3817,13 @@ public class ActivityManagerService extends IActivityManager.Stub
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
+ startProcessLocked(app, hostingType, hostingNameStr, false /* disableHiddenApiChecks */,
+ null /* abiOverride */, null /* entryPoint */, null /* entryPointArgs */);
+ }
+
+ private final void startProcessLocked(ProcessRecord app, String hostingType,
+ String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride,
+ String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
@@ -3891,9 +3944,11 @@ public class ActivityManagerService extends IActivityManager.Stub
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
- if (!app.info.isAllowedToUseHiddenApi()) {
- // This app is not allowed to use undocumented and private APIs.
- // Set up its runtime with the appropriate flag.
+ if (!app.info.isAllowedToUseHiddenApi() &&
+ !disableHiddenApiChecks &&
+ !mHiddenApiBlacklist.isDisabled()) {
+ // This app is not allowed to use undocumented and private APIs, or blacklisting is
+ // enabled. Set up its runtime with the appropriate flag.
runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS;
}
@@ -12414,6 +12469,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
+ return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
+ abiOverride);
+ }
+
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+ boolean disableHiddenApiChecks, String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -12445,8 +12506,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application",
- customProcess != null ? customProcess : app.processName, abiOverride,
- null /* entryPoint */, null /* entryPointArgs */);
+ customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
+ abiOverride, null /* entryPoint */, null /* entryPointArgs */);
}
return app;
@@ -14165,6 +14226,7 @@ public class ActivityManagerService extends IActivityManager.Stub
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
final boolean supportsLeanbackOnly =
mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
+ mHiddenApiBlacklist.registerObserver();
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
@@ -20110,7 +20172,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
"start instr");
- ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+ boolean disableHiddenApiChecks =
+ (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+ ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ abiOverride);
app.instr = activeInstr;
activeInstr.mFinished = false;
activeInstr.mRunningProcesses.add(app);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59c0ed1393e6..254f4038538a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2729,7 +2729,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" specified then send to all users.");
pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission.");
pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
- pw.println(" [--user <USER_ID> | current]");
+ pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]");
pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>");
pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the");
pw.println(" form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there");
@@ -2744,6 +2744,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" test runners.");
pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;");
pw.println(" current user if not specified.");
+ pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API.");
pw.println(" --no-window-animation: turn off window animations while running.");
pw.println(" --abi <ABI>: Launch the instrumented process with the selected ABI.");
pw.println(" This assumes that the process supports the selected ABI.");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4293d4510ede..cb96bacac914 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1494,17 +1494,6 @@ public class AudioService extends IAudioService.Stub
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
- // Check if volume update should be send to AVRCP
- if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
- (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
- synchronized (mA2dpAvrcpLock) {
- if (mA2dp != null && mAvrcpAbsVolSupported) {
- mA2dp.adjustAvrcpAbsoluteVolume(direction);
- }
- }
- }
-
if (isMuteAdjust) {
boolean state;
if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
@@ -1553,8 +1542,20 @@ public class AudioService extends IAudioService.Stub
0);
}
- // Check if volume update should be sent to Hdmi system audio.
int newIndex = mStreamStates[streamType].getIndex(device);
+
+ // Check if volume update should be send to AVRCP
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+ (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+ (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ synchronized (mA2dpAvrcpLock) {
+ if (mA2dp != null && mAvrcpAbsVolSupported) {
+ mA2dp.setAvrcpAbsoluteVolume(newIndex / 10);
+ }
+ }
+ }
+
+ // Check if volume update should be sent to Hdmi system audio.
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
}
@@ -4104,6 +4105,11 @@ public class AudioService extends IAudioService.Stub
}
}
+ @Override
+ public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
+ {
+ }
+
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
{
return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index d24f9c985ac4..0f8fc17047b9 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -172,7 +172,7 @@ public class KeepaliveTracker {
}
private int checkInterval() {
- return mInterval >= 10 ? SUCCESS : ERROR_INVALID_INTERVAL;
+ return mInterval >= MIN_INTERVAL ? SUCCESS : ERROR_INVALID_INTERVAL;
}
private int isValid() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a24f97e53570..505480ea537e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -285,7 +285,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
int delta = add ? +1 : -1;
switch (request.type) {
case REQUEST:
- case TRACK_DEFAULT:
mNumRequestNetworkRequests += delta;
break;
@@ -294,6 +293,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mNumBackgroundNetworkRequests += delta;
break;
+ case TRACK_DEFAULT:
case LISTEN:
break;
@@ -384,12 +384,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
/**
* Returns whether the network is a background network. A network is a background network if it
- * is satisfying no foreground requests and at least one background request. (If it did not have
- * a background request, it would be a speculative network that is only being kept up because
- * it might satisfy a request if it validated).
+ * does not have the NET_CAPABILITY_FOREGROUND capability, which implies it is satisfying no
+ * foreground request, is not lingering (i.e. kept for a while after being outscored), and is
+ * not a speculative network (i.e. kept pending validation when validation would have it
+ * outscore another foreground network). That implies it is being kept up by some background
+ * request (otherwise it would be torn down), maybe the mobile always-on request.
*/
public boolean isBackgroundNetwork() {
- return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
+ return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0
+ && !isLingering();
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 69dec2d46228..1767a21f576b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,6 +19,7 @@ package com.android.server.connectivity;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -99,6 +100,7 @@ import com.android.server.net.BaseNetworkObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1302,19 +1304,16 @@ public class Tethering extends BaseNetworkObserver {
protected void setUpstreamNetwork(NetworkState ns) {
String iface = null;
- if (ns != null && ns.linkProperties != null) {
+ if (ns != null) {
// Find the interface with the default IPv4 route. It may be the
// interface described by linkProperties, or one of the interfaces
// stacked on top of it.
- mLog.i("Finding IPv4 upstream interface on: " + ns.linkProperties);
- RouteInfo ipv4Default = RouteInfo.selectBestRoute(
- ns.linkProperties.getAllRoutes(), Inet4Address.ANY);
- if (ipv4Default != null) {
- iface = ipv4Default.getInterface();
- mLog.i("Found interface " + ipv4Default.getInterface());
- } else {
- mLog.i("No IPv4 upstream interface, giving up.");
- }
+ mLog.i("Looking for default routes on: " + ns.linkProperties);
+ final String iface4 = getIPv4DefaultRouteInterface(ns);
+ final String iface6 = getIPv6DefaultRouteInterface(ns);
+ mLog.i("IPv4/IPv6 upstream interface(s): " + iface4 + "/" + iface6);
+
+ iface = (iface4 != null) ? iface4 : null /* TODO: iface6 */;
}
if (iface != null) {
@@ -1957,6 +1956,31 @@ public class Tethering extends BaseNetworkObserver {
mTetherStates.remove(iface);
}
+ private static String getIPv4DefaultRouteInterface(NetworkState ns) {
+ if (ns == null) return null;
+ return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
+ }
+
+ private static String getIPv6DefaultRouteInterface(NetworkState ns) {
+ if (ns == null) return null;
+ // An upstream network's IPv6 capability is currently only useful if it
+ // can be 64share'd downstream (RFC 7278). For now, that means mobile
+ // upstream networks only.
+ if (ns.networkCapabilities == null ||
+ !ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ return null;
+ }
+
+ return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
+ }
+
+ private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
+ final RouteInfo ri = (lp != null)
+ ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
+ : null;
+ return (ri != null) ? ri.getInterface() : null;
+ }
+
private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index e5f4282eefe0..0cba76ba7346 100644..100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -660,7 +660,8 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
void startQueuedActions() {
assertRunOnServiceThread();
- for (HdmiCecFeatureAction action : mActions) {
+ // Use copied action list in that start() may remove itself.
+ for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
if (!action.started()) {
Slog.i(TAG, "Starting queued action:" + action);
action.start();
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 423201a5251f..3814ef348c87 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -144,6 +144,12 @@ public class BackgroundDexOptService extends JobService {
Intent intent = registerReceiver(null, filter);
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+ boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+
+ if (!present) {
+ // No battery, treat as if 100%, no possibility of draining battery.
+ return 100;
+ }
if (level < 0 || scale <= 0) {
// Battery data unavailable. This should never happen, so assume the worst.
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index a52bd4e8883b..ab3c9996c59a 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -286,14 +286,14 @@ public class Installer extends SystemService {
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
@Nullable String seInfo, boolean downgrade, int targetSdkVersion,
- @Nullable String profileName, @Nullable String dexMetadataPath)
- throws InstallerException {
+ @Nullable String profileName, @Nullable String dexMetadataPath,
+ @Nullable String compilationReason) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion, profileName, dexMetadataPath);
+ targetSdkVersion, profileName, dexMetadataPath, compilationReason);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 232743c699a8..b6804ba577e6 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -262,11 +262,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
int targetSdkVersion, @Nullable String profileName,
- @Nullable String dexMetadataPath) throws InstallerException {
+ @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason)
+ throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 6.
- builder.append("6 ");
+ // The version. Right now it's 7.
+ builder.append("7 ");
builder.append("dexopt");
@@ -285,6 +286,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
encodeParameter(builder, targetSdkVersion);
encodeParameter(builder, profileName);
encodeParameter(builder, dexMetadataPath);
+ encodeParameter(builder, dexoptCompilationReason);
commands.add(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 126ee8033051..51e035b1676d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,7 +34,6 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;
@@ -63,7 +62,8 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT;
-import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName;
+
import static dalvik.system.DexFile.getSafeModeCompilerFilter;
import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
@@ -236,7 +236,8 @@ public class PackageDexOptimizer {
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade(), profileName, dexMetadataPath);
+ packageStats, options.isDowngrade(), profileName, dexMetadataPath,
+ options.getCompilationReason());
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -261,7 +262,7 @@ public class PackageDexOptimizer {
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
- String profileName, String dexMetadataPath) {
+ String profileName, String dexMetadataPath, int compilationReason) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -288,7 +289,7 @@ public class PackageDexOptimizer {
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
- profileName, dexMetadataPath);
+ profileName, dexMetadataPath, getReasonName(compilationReason));
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -399,7 +400,7 @@ public class PackageDexOptimizer {
// Note this trades correctness for performance since the resulting slow down is
// unacceptable in some cases until b/64530081 is fixed.
String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
-
+ int reason = options.getCompilationReason();
try {
for (String isa : dexUseInfo.getLoaderIsas()) {
// Reuse the same dexopt path as for the primary apks. We don't need all the
@@ -410,7 +411,7 @@ public class PackageDexOptimizer {
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null,
- /*dexMetadataPath*/ null);
+ /*dexMetadataPath*/ null, getReasonName(reason));
}
return DEX_OPT_PERFORMED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3466f55596cb..900e18873193 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -575,6 +575,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Compilation reasons.
+ public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
public static final int REASON_INSTALL = 2;
@@ -9710,7 +9711,7 @@ public class PackageManagerService extends IPackageManager.Stub
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
final int elapsedTimeSeconds =
@@ -9737,7 +9738,7 @@ public class PackageManagerService extends IPackageManager.Stub
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
- final String compilerFilter, boolean bootComplete) {
+ final int compilationReason, boolean bootComplete) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
@@ -9837,13 +9838,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- String pkgCompilerFilter = compilerFilter;
+ int pkgCompilationReason = compilationReason;
if (useProfileForDexopt) {
// Use background dexopt mode to try and use the profile. Note that this does not
// guarantee usage of the profile.
- pkgCompilerFilter =
- PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_BACKGROUND_DEXOPT);
+ pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}
// checkProfiles is false to avoid merging profiles during boot which
@@ -9852,9 +9851,13 @@ public class PackageManagerService extends IPackageManager.Stub
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
+ if (compilationReason == REASON_FIRST_BOOT) {
+ // TODO: This doesn't cover the upgrade case, we should check for this too.
+ dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
+ }
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
- pkgCompilerFilter,
+ pkgCompilationReason,
dexoptFlags));
switch (primaryDexOptStaus) {
@@ -9954,8 +9957,8 @@ public class PackageManagerService extends IPackageManager.Stub
int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
(force ? DexoptOptions.DEXOPT_FORCE : 0) |
(bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
- return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter,
- splitName, flags));
+ return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+ targetCompilerFilter, splitName, flags));
}
/**
@@ -10064,7 +10067,8 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
- options.getCompilerFilter(), options.getSplitName(),
+ options.getCompilationReason(), options.getCompilerFilter(),
+ options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 19b0d9bc4b90..fce828581c54 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -123,4 +123,14 @@ public class PackageManagerServiceCompilerMapping {
return value;
}
+
+ public static String getReasonName(int reason) {
+ if (reason == PackageManagerService.REASON_UNKNOWN) {
+ return "unknown";
+ }
+ if (reason < 0 || reason >= REASON_STRINGS.length) {
+ throw new IllegalArgumentException("reason " + reason + " invalid");
+ }
+ return REASON_STRINGS[reason];
+ }
}
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 0e2730cbd944..3e63fb42f0ef 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -549,13 +549,12 @@ public class DexManager {
mPackageDexUsage.maybeWriteAsync();
}
- // Try to optimize the package according to the install reason.
- String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_INSTALL);
DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName)
.getDexUseInfoMap().get(dexPath);
- DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0);
+ // Try to optimize the package according to the install reason.
+ DexoptOptions options = new DexoptOptions(info.packageName,
+ PackageManagerService.REASON_INSTALL, /*flags*/0);
int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo,
options);
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index d4f95cb6b99f..a7a7686b2a6b 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -77,15 +77,21 @@ public final class DexoptOptions {
// It only applies for primary apk and it's always null if mOnlySecondaryDex is true.
private final String mSplitName;
+ // The reason for invoking dexopt (see PackageManagerService.REASON_* constants).
+ // A -1 value denotes an unknown reason.
+ private final int mCompilationReason;
+
public DexoptOptions(String packageName, String compilerFilter, int flags) {
- this(packageName, compilerFilter, /*splitName*/ null, flags);
+ this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, int compilerReason, int flags) {
- this(packageName, getCompilerFilterForReason(compilerReason), flags);
+ public DexoptOptions(String packageName, int compilationReason, int flags) {
+ this(packageName, compilationReason, getCompilerFilterForReason(compilationReason),
+ /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, String compilerFilter, String splitName, int flags) {
+ public DexoptOptions(String packageName, int compilationReason, String compilerFilter,
+ String splitName, int flags) {
int validityMask =
DEXOPT_CHECK_FOR_PROFILES_UPDATES |
DEXOPT_FORCE |
@@ -104,6 +110,7 @@ public final class DexoptOptions {
mCompilerFilter = compilerFilter;
mFlags = flags;
mSplitName = splitName;
+ mCompilationReason = compilationReason;
}
public String getPackageName() {
@@ -157,4 +164,8 @@ public final class DexoptOptions {
public int getFlags() {
return mFlags;
}
+
+ public int getCompilationReason() {
+ return mCompilationReason;
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index da14c360f16a..d21947665c32 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6791,7 +6791,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerDrawComplete = false;
mScreenOnListener = screenOnListener;
- if (mKeyguardDelegate != null) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
getKeyguardDrawnTimeout());
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 5a5471b1b4f5..33456491bcae 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -235,6 +235,10 @@ public class KeyguardServiceDelegate {
return false;
}
+ public boolean hasKeyguard() {
+ return mKeyguardState.deviceHasKeyguard;
+ }
+
public boolean isInputRestricted() {
if (mKeyguardService != null) {
mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b888ec21e708..f6e863b0aafb 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -847,6 +847,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ public void scheduleTimeoutLocked() {
+ // If we didn't reset it right away, do so after we couldn't connect to
+ // it for an extended amount of time to avoid having a black wallpaper.
+ final Handler fgHandler = FgThread.getHandler();
+ fgHandler.removeCallbacks(mResetRunnable);
+ fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
+ if (DEBUG_LIVE) {
+ Slog.i(TAG, "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
+ }
+ }
+
private void processDisconnect(final ServiceConnection connection) {
synchronized (mLock) {
// The wallpaper disappeared. If this isn't a system-default one, track
@@ -871,13 +882,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
- // If we didn't reset it right away, do so after we couldn't connect to
- // it for an extended amount of time to avoid having a black wallpaper.
- final Handler fgHandler = FgThread.getHandler();
- fgHandler.removeCallbacks(mResetRunnable);
- fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
- if (DEBUG_LIVE) {
- Slog.i(TAG, "Started wallpaper reconnect timeout for " + wpService);
+ clearWallpaperComponentLocked(mWallpaper);
+ if (bindWallpaperComponentLocked(
+ wpService, false, false, mWallpaper, null)) {
+ mWallpaper.connection.scheduleTimeoutLocked();
+ } else {
+ Slog.w(TAG, "Reverting to built-in wallpaper!");
+ clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
}
}
final String flattened = wpService.flattenToString();
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index bf769ed46bc1..1e334b83d8b0 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -304,6 +304,6 @@ public class SystemImpl implements SystemInterface {
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
- | PackageManager.MATCH_ANY_USER;
+ | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_ANY_USER;
}
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index d3a97b3851f4..1f370a574231 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -72,6 +72,7 @@ import java.util.Objects;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -100,6 +101,11 @@ public class IpClient extends StateMachine {
/**
* Callbacks for handling IpClient events.
+ *
+ * These methods are called by IpClient on its own thread. Implementations
+ * of this class MUST NOT carry out long-running computations or hold locks
+ * for which there might be contention with other code calling public
+ * methods of the same IpClient instance.
*/
public static class Callback {
// In order to receive onPreDhcpAction(), call #withPreDhcpAction()
@@ -545,6 +551,7 @@ public class IpClient extends StateMachine {
private final String mClatInterfaceName;
@VisibleForTesting
protected final Callback mCallback;
+ private final CountDownLatch mShutdownLatch;
private final INetworkManagementService mNwService;
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
@@ -597,6 +604,7 @@ public class IpClient extends StateMachine {
mInterfaceName = ifName;
mClatInterfaceName = CLAT_PREFIX + ifName;
mCallback = new LoggingCallbackWrapper(callback);
+ mShutdownLatch = new CountDownLatch(1);
mNwService = nwService;
mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
@@ -704,6 +712,7 @@ public class IpClient extends StateMachine {
@Override
protected void onQuitting() {
mCallback.onQuit();
+ mShutdownLatch.countDown();
}
// Shut down this IpClient instance altogether.
@@ -712,6 +721,17 @@ public class IpClient extends StateMachine {
sendMessage(CMD_TERMINATE_AFTER_STOP);
}
+ // In order to avoid deadlock, this method MUST NOT be called on the
+ // IpClient instance's thread. This prohibition includes code executed by
+ // when methods on the passed-in IpClient.Callback instance are called.
+ public void awaitShutdown() {
+ try {
+ mShutdownLatch.await();
+ } catch (InterruptedException e) {
+ mLog.e("Interrupted while awaiting shutdown: " + e);
+ }
+ }
+
public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
return new ProvisioningConfiguration.Builder();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index f559986a6f15..93064bc4ab92 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -118,7 +118,7 @@ public class DexoptOptionsTests {
public void testCreateDexoptOptionsSplit() {
int flags = DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE;
- DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, mSplitName, flags);
+ DexoptOptions opt = new DexoptOptions(mPackageName, -1, mCompilerFilter, mSplitName, flags);
assertEquals(mPackageName, opt.getPackageName());
assertEquals(mCompilerFilter, opt.getCompilerFilter());
assertEquals(mSplitName, opt.getSplitName());
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f53eb15d482b..763dffbb129d 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -34,6 +34,7 @@ import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
+import android.os.Binder;
import android.os.DeadObjectException;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -880,21 +881,26 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
private void initializeTelephonyAndPowerStateListeners() {
- // Get the current call state synchronously for the first recognition.
- mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
-
- // Register for call state changes when the first call to start recognition occurs.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
- // Register for power saver mode changes when the first call to start recognition
- // occurs.
- if (mPowerSaveModeListener == null) {
- mPowerSaveModeListener = new PowerSaveModeListener();
- mContext.registerReceiver(mPowerSaveModeListener,
- new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+ long token = Binder.clearCallingIdentity();
+ try {
+ // Get the current call state synchronously for the first recognition.
+ mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
+
+ // Register for call state changes when the first call to start recognition occurs.
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+ // Register for power saver mode changes when the first call to start recognition
+ // occurs.
+ if (mPowerSaveModeListener == null) {
+ mPowerSaveModeListener = new PowerSaveModeListener();
+ mContext.registerReceiver(mPowerSaveModeListener,
+ new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+ }
+ mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
+ .batterySaverEnabled;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
- .batterySaverEnabled;
}
// Sends an error callback to all models with a valid registered callback.
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2341f03d2ec5..a79f2c9eaf17 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -426,8 +426,14 @@ public final class Call {
*/
public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+ /**
+ * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
+ * {@link RttCall} object that is used to send and receive text.
+ */
+ public static final int PROPERTY_RTT = 0x00000400;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000400
+ // Next PROPERTY value: 0x00000800
//******************************************************************************************
private final String mTelecomCallId;
@@ -1190,6 +1196,23 @@ public final class Call {
return null;
}
}
+
+ /**
+ * Closes the underlying file descriptors
+ * @hide
+ */
+ public void close() {
+ try {
+ mReceiveStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ try {
+ mTransmitStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
}
/**
@@ -1665,7 +1688,7 @@ public final class Call {
* @return true if there is a connection, false otherwise.
*/
public boolean isRttActive() {
- return mRttCall != null;
+ return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT);
}
/**
@@ -1868,7 +1891,8 @@ public final class Call {
boolean isRttChanged = false;
boolean rttModeChanged = false;
- if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+ if (parcelableCall.getIsRttCallChanged()
+ && mDetails.hasProperty(Details.PROPERTY_RTT)) {
ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
InputStreamReader receiveStream = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 69cc3dedf256..9a53d8cd6f3e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -23,7 +23,6 @@ import com.android.internal.telecom.IVideoProvider;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
@@ -41,6 +40,8 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.view.Surface;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
@@ -400,9 +401,7 @@ public abstract class Connection extends Conferenceable {
/**
* Set by the framework to indicate that a connection has an active RTT session associated with
* it.
- * @hide
*/
- @TestApi
public static final int PROPERTY_IS_RTT = 1 << 8;
/**
@@ -796,6 +795,10 @@ public abstract class Connection extends Conferenceable {
builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
}
+ if (can(properties, PROPERTY_IS_RTT)) {
+ builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
+ }
+
builder.append("]");
return builder.toString();
}
@@ -843,9 +846,7 @@ public abstract class Connection extends Conferenceable {
/**
* Provides methods to read and write RTT data to/from the in-call app.
- * @hide
*/
- @TestApi
public static final class RttTextStream {
private static final int READ_BUFFER_SIZE = 1000;
private final InputStreamReader mPipeFromInCall;
@@ -861,18 +862,19 @@ public abstract class Connection extends Conferenceable {
mFdFromInCall = fromInCall;
mFdToInCall = toInCall;
mPipeFromInCall = new InputStreamReader(
- new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+ new FileInputStream(fromInCall.getFileDescriptor()));
mPipeToInCall = new OutputStreamWriter(
- new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+ new FileOutputStream(toInCall.getFileDescriptor()));
}
/**
* Writes the string {@param input} into the text stream to the UI for this RTT call. Since
* RTT transmits text in real-time, this method should be called as often as text snippets
* are received from the remote user, even if it is only one character.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @param input The message to send to the in-call app.
*/
public void write(String input) throws IOException {
@@ -885,9 +887,10 @@ public abstract class Connection extends Conferenceable {
* Reads a string from the in-call app, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @return A string containing text entered by the user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
@@ -902,6 +905,7 @@ public abstract class Connection extends Conferenceable {
/**
* Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
* be read.
+ *
* @return A string containing text entered by the user, or {@code null} if the user has
* not entered any new text yet.
*/
@@ -2618,36 +2622,27 @@ public abstract class Connection extends Conferenceable {
/**
* Informs listeners that a previously requested RTT session via
* {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} has succeeded.
- * @hide
+ * {@link #onStartRtt(RttTextStream)} has succeeded.
*/
- @TestApi
public final void sendRttInitiationSuccess() {
- setRttProperty();
mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
}
/**
* Informs listeners that a previously requested RTT session via
- * {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)}
+ * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)}
* has failed.
* @param reason One of the reason codes defined in {@link RttModifyStatus}, with the
* exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
- * @hide
*/
- @TestApi
public final void sendRttInitiationFailure(int reason) {
- unsetRttProperty();
mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
}
/**
* Informs listeners that a currently active RTT session has been terminated by the remote
* side of the coll.
- * @hide
*/
- @TestApi
public final void sendRttSessionRemotelyTerminated() {
mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
}
@@ -2655,9 +2650,7 @@ public abstract class Connection extends Conferenceable {
/**
* Informs listeners that the remote side of the call has requested an upgrade to include an
* RTT session in the call.
- * @hide
*/
- @TestApi
public final void sendRemoteRttRequest() {
mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this));
}
@@ -2931,17 +2924,13 @@ public abstract class Connection extends Conferenceable {
* request, respectively.
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
- * @hide
*/
- @TestApi
public void onStartRtt(@NonNull RttTextStream rttTextStream) {}
/**
* Notifies this {@link Connection} that it should terminate any existing RTT communication
* channel. No response to Telecom is needed for this method.
- * @hide
*/
- @TestApi
public void onStopRtt() {}
/**
@@ -2949,29 +2938,11 @@ public abstract class Connection extends Conferenceable {
* request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is
* indicated by the supplied {@link RttTextStream} being non-null, and rejection is
* indicated by {@code rttTextStream} being {@code null}
- * @hide
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
*/
- @TestApi
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
- /**
- * Internal method to set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void setRttProperty() {
- setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
- }
-
- /**
- * Internal method to un-set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void unsetRttProperty() {
- setConnectionProperties(getConnectionProperties() & (~PROPERTY_IS_RTT));
- }
-
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index e169e5f80741..b6e6b0ed8270 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,7 +16,6 @@
package android.telecom;
-import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -144,6 +143,8 @@ public final class ConnectionRequest implements Parcelable {
private final boolean mShouldShowIncomingCallUi;
private final ParcelFileDescriptor mRttPipeToInCall;
private final ParcelFileDescriptor mRttPipeFromInCall;
+ // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
+ private Connection.RttTextStream mRttTextStream;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -310,12 +311,13 @@ public final class ConnectionRequest implements Parcelable {
* send and receive RTT text to/from the in-call app.
* @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
* if this connection request is not requesting an RTT session upon connection establishment.
- * @hide
*/
- @TestApi
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
- return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ if (mRttTextStream == null) {
+ mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ }
+ return mRttTextStream;
} else {
return null;
}
@@ -324,9 +326,7 @@ public final class ConnectionRequest implements Parcelable {
/**
* Convenience method for determining whether the ConnectionRequest is requesting an RTT session
* @return {@code true} if RTT is requested, {@code false} otherwise.
- * @hide
*/
- @TestApi
public boolean isRequestingRtt() {
return mRttPipeFromInCall != null && mRttPipeToInCall != null;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 46d6b4201497..593e12b073bc 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -143,6 +143,7 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
private static final String SESSION_START_RTT = "CS.+RTT";
+ private static final String SESSION_UPDATE_RTT_PIPES = "CS.uRTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
private static final String SESSION_HANDOVER_FAILED = "CS.haF";
@@ -1864,7 +1865,6 @@ public abstract class ConnectionService extends Service {
Log.d(this, "stopRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopRtt").onStopRtt();
- findConnectionForAction(callId, "stopRtt").unsetRttProperty();
} else if (mConferenceById.containsKey(callId)) {
Log.w(this, "stopRtt called on a conference.");
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index f360680913c4..e8b2fa799903 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1800,7 +1800,14 @@ public class CarrierConfigManager {
public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
/**
- * List of thresholds of RSRP for determining the display level of LTE signal bar.
+ * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR,
+ * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
+ *
+ * Note that the min and max thresholds are fixed at -140 and -44, as explained in
+ * TS 36.133 9.1.4 - RSRP Measurement Report Mapping.
+ * <p>
+ * See SignalStrength#MAX_LTE_RSRP and SignalStrength#MIN_LTE_RSRP. Any signal level outside
+ * these boundaries is considered invalid.
* @hide
*/
public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY =
@@ -1855,7 +1862,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
- sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
+ sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
@@ -2118,12 +2125,10 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
new int[] {
- -140, /* SIGNAL_STRENGTH_NONE_OR_UNKNOWN */
-128, /* SIGNAL_STRENGTH_POOR */
-118, /* SIGNAL_STRENGTH_MODERATE */
-108, /* SIGNAL_STRENGTH_GOOD */
-98, /* SIGNAL_STRENGTH_GREAT */
- -44
});
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index f009fb145fc2..7e86966e2c1b 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -172,7 +172,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
}
/**
- * Get the timing advance value for LTE, as a value between 0..63.
+ * Get the timing advance value for LTE, as a value in range of 0..1282.
* Integer.MAX_VALUE is reported when there is no active RRC
* connection. Refer to 3GPP 36.213 Sec 4.2.3
* @return the LTE timing advance, if available.
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
new file mode 100644
index 000000000000..b362df9ff677
--- /dev/null
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.SparseBooleanArray;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper for performing location access checks.
+ * @hide
+ */
+public final class LocationAccessPolicy {
+ /**
+ * API to determine if the caller has permissions to get cell location.
+ *
+ * @param pkgName Package name of the application requesting access
+ * @param uid The uid of the package
+ * @param pid The pid of the package
+ * @return boolean true or false if permissions is granted
+ */
+ public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
+ int uid, int pid) throws SecurityException {
+ Trace.beginSection("TelephonyLocationCheck");
+ try {
+ // Always allow the phone process to access location. This avoid breaking legacy code
+ // that rely on public-facing APIs to access cell location, and it doesn't create a
+ // info leak risk because the cell location is stored in the phone process anyway.
+ if (uid == Process.PHONE_UID) {
+ return true;
+ }
+
+ // We always require the location permission and also require the
+ // location mode to be on for non-legacy apps. Legacy apps are
+ // required to be in the foreground to at least mitigate the case
+ // where a legacy app the user is not using tracks their location.
+ // Granting ACCESS_FINE_LOCATION to an app automatically grants it
+ // ACCESS_COARSE_LOCATION.
+
+ if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
+ PackageManager.PERMISSION_DENIED) {
+ return false;
+ }
+ final int opCode = AppOpsManager.permissionToOpCode(
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
+ .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
+ && !isLegacyForeground(context, pkgName, uid)) {
+ return false;
+ }
+ // If the user or profile is current, permission is granted.
+ // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
+ return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+ int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
+ return locationMode != Settings.Secure.LOCATION_MODE_OFF
+ && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
+ }
+
+ private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
+ int uid) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
+ try {
+ if (context.getPackageManager().getApplicationInfo(pkgName, 0)
+ .targetSdkVersion <= Build.VERSION_CODES.O) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, assume known app (more strict checking)
+ // Note: This case will never happen since checkPackage is
+ // called to verify validity before checking app's version.
+ }
+ return false;
+ }
+
+ private static boolean isForegroundApp(@NonNull Context context, int uid) {
+ final ActivityManager am = context.getSystemService(ActivityManager.class);
+ return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+ }
+
+ private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
+ return context.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean isCurrentProfile(@NonNull Context context, int uid) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int callingUserId = UserHandle.getUserId(uid);
+ if (callingUserId == currentUser) {
+ return true;
+ } else {
+ List<UserInfo> userProfiles = context.getSystemService(
+ UserManager.class).getProfiles(currentUser);
+ for (UserInfo user : userProfiles) {
+ if (user.id == callingUserId) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index da3d87bc7211..ce1b80c2c860 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -30,7 +30,6 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.telephony.mbms.DownloadStateCallback;
import android.telephony.mbms.FileInfo;
@@ -53,6 +52,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -107,11 +107,8 @@ public class MbmsDownloadSession implements AutoCloseable {
/**
* {@link Uri} extra that Android will attach to the intent supplied via
* {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)}
- * Indicates the location of the successfully downloaded file within the temp file root set
- * via {@link #setTempFileRootDirectory(File)}.
- * While you may use this file in-place, it is highly encouraged that you move
- * this file to a different location after receiving the download completion intent, as this
- * file resides within the temp file directory.
+ * Indicates the location of the successfully downloaded file within the directory that the
+ * app provided via the builder.
*
* Will always be set to a non-null value if
* {@link #EXTRA_MBMS_DOWNLOAD_RESULT} is set to {@link #RESULT_SUCCESSFUL}.
@@ -220,6 +217,8 @@ public class MbmsDownloadSession implements AutoCloseable {
*/
public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4;
+ private static final String DESTINATION_SANITY_CHECK_FILE_NAME = "destinationSanityCheckFile";
+
private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
private final Context mContext;
@@ -236,23 +235,20 @@ public class MbmsDownloadSession implements AutoCloseable {
private final Map<DownloadStateCallback, InternalDownloadStateCallback>
mInternalDownloadCallbacks = new HashMap<>();
- private MbmsDownloadSession(Context context, MbmsDownloadSessionCallback callback,
- int subscriptionId, Handler handler) {
+ private MbmsDownloadSession(Context context, Executor executor, int subscriptionId,
+ MbmsDownloadSessionCallback callback) {
mContext = context;
mSubscriptionId = subscriptionId;
- if (handler == null) {
- handler = new Handler(Looper.getMainLooper());
- }
- mInternalCallback = new InternalDownloadSessionCallback(callback, handler);
+ mInternalCallback = new InternalDownloadSessionCallback(callback, executor);
}
/**
* Create a new {@link MbmsDownloadSession} using the system default data subscription ID.
- * See {@link #create(Context, MbmsDownloadSessionCallback, int, Handler)}
+ * See {@link #create(Context, Executor, int, MbmsDownloadSessionCallback)}
*/
public static MbmsDownloadSession create(@NonNull Context context,
- @NonNull MbmsDownloadSessionCallback callback, @NonNull Handler handler) {
- return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler);
+ @NonNull Executor executor, @NonNull MbmsDownloadSessionCallback callback) {
+ return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
}
/**
@@ -279,24 +275,24 @@ public class MbmsDownloadSession implements AutoCloseable {
* {@link MbmsDownloadSession} that you received before calling this method again.
*
* @param context The instance of {@link Context} to use
- * @param callback A callback to get asynchronous error messages and file service updates.
+ * @param executor The executor on which you wish to execute callbacks.
* @param subscriptionId The data subscription ID to use
- * @param handler The {@link Handler} on which callbacks should be enqueued.
+ * @param callback A callback to get asynchronous error messages and file service updates.
* @return A new instance of {@link MbmsDownloadSession}, or null if an error occurred during
* setup.
*/
public static @Nullable MbmsDownloadSession create(@NonNull Context context,
- final @NonNull MbmsDownloadSessionCallback callback,
- int subscriptionId, @NonNull Handler handler) {
+ @NonNull Executor executor, int subscriptionId,
+ final @NonNull MbmsDownloadSessionCallback callback) {
if (!sIsInitialized.compareAndSet(false, true)) {
throw new IllegalStateException("Cannot have two active instances");
}
MbmsDownloadSession session =
- new MbmsDownloadSession(context, callback, subscriptionId, handler);
+ new MbmsDownloadSession(context, executor, subscriptionId, callback);
final int result = session.bindAndInitialize();
if (result != MbmsErrors.SUCCESS) {
sIsInitialized.set(false);
- handler.post(new Runnable() {
+ executor.execute(new Runnable() {
@Override
public void run() {
callback.onError(result, null);
@@ -500,6 +496,10 @@ public class MbmsDownloadSession implements AutoCloseable {
* {@link MbmsDownloadSession#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY} and store that as the temp
* file root directory.
*
+ * If the {@link DownloadRequest} has a destination that is not on the same filesystem as the
+ * temp file directory provided via {@link #getTempFileRootDirectory()}, an
+ * {@link IllegalArgumentException} will be thrown.
+ *
* Asynchronous errors through the callback may include any error not specific to the
* streaming use-case.
* @param request The request that specifies what should be downloaded.
@@ -522,6 +522,8 @@ public class MbmsDownloadSession implements AutoCloseable {
setTempFileRootDirectory(tempRootDirectory);
}
+ checkDownloadRequestDestination(request);
+
try {
int result = downloadService.download(request);
if (result == MbmsErrors.SUCCESS) {
@@ -568,21 +570,21 @@ public class MbmsDownloadSession implements AutoCloseable {
* this method will throw an {@link IllegalArgumentException}.
*
* @param request The {@link DownloadRequest} that you want updates on.
+ * @param executor The {@link Executor} on which calls to {@code callback} should be executed.
* @param callback The callback that should be called when the middleware has information to
* share on the download.
- * @param handler The {@link Handler} on which calls to {@code callback} should be enqueued on.
* @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
* and some other error code otherwise.
*/
public int registerStateCallback(@NonNull DownloadRequest request,
- @NonNull DownloadStateCallback callback, @NonNull Handler handler) {
+ @NonNull Executor executor, @NonNull DownloadStateCallback callback) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
}
InternalDownloadStateCallback internalCallback =
- new InternalDownloadStateCallback(callback, handler);
+ new InternalDownloadStateCallback(callback, executor);
try {
int result = downloadService.registerStateCallback(request, internalCallback,
@@ -604,7 +606,7 @@ public class MbmsDownloadSession implements AutoCloseable {
/**
* Un-register a callback previously registered via
- * {@link #registerStateCallback(DownloadRequest, DownloadStateCallback, Handler)}. After
+ * {@link #registerStateCallback(DownloadRequest, Executor, DownloadStateCallback)}. After
* this method is called, no further callbacks will be enqueued on the {@link Handler}
* provided upon registration, even if this method throws an exception.
*
@@ -692,7 +694,7 @@ public class MbmsDownloadSession implements AutoCloseable {
* The state will be delivered as a callback via
* {@link DownloadStateCallback#onStateUpdated(DownloadRequest, FileInfo, int)}. If no such
* callback has been registered via
- * {@link #registerStateCallback(DownloadRequest, DownloadStateCallback, Handler)}, this
+ * {@link #registerStateCallback(DownloadRequest, Executor, DownloadStateCallback)}, this
* method will be a no-op.
*
* If the middleware has no record of the
@@ -775,7 +777,7 @@ public class MbmsDownloadSession implements AutoCloseable {
* instance of {@link MbmsDownloadSessionCallback}, but callbacks that have already been
* enqueued will still be delivered.
*
- * It is safe to call {@link #create(Context, MbmsDownloadSessionCallback, int, Handler)} to
+ * It is safe to call {@link #create(Context, Executor, int, MbmsDownloadSessionCallback)} to
* obtain another instance of {@link MbmsDownloadSession} immediately after this method
* returns.
*
@@ -831,6 +833,36 @@ public class MbmsDownloadSession implements AutoCloseable {
}
}
+ private void checkDownloadRequestDestination(DownloadRequest request) {
+ File downloadRequestDestination = new File(request.getDestinationUri().getPath());
+ if (!downloadRequestDestination.isDirectory()) {
+ throw new IllegalArgumentException("The destination path must be a directory");
+ }
+ // Check if the request destination is okay to use by attempting to rename an empty
+ // file to there.
+ File testFile = new File(MbmsTempFileProvider.getEmbmsTempFileDir(mContext),
+ DESTINATION_SANITY_CHECK_FILE_NAME);
+ File testFileDestination = new File(downloadRequestDestination,
+ DESTINATION_SANITY_CHECK_FILE_NAME);
+
+ try {
+ if (!testFile.exists()) {
+ testFile.createNewFile();
+ }
+ if (!testFile.renameTo(testFileDestination)) {
+ throw new IllegalArgumentException("Destination provided in the download request " +
+ "is invalid -- files in the temp file directory cannot be directly moved " +
+ "there.");
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Got IOException while testing out the destination: "
+ + e);
+ } finally {
+ testFile.delete();
+ testFileDestination.delete();
+ }
+ }
+
private File getDownloadRequestTokenPath(DownloadRequest request) {
File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForService(mContext,
request.getFileServiceId());
diff --git a/telephony/java/android/telephony/MbmsStreamingSession.java b/telephony/java/android/telephony/MbmsStreamingSession.java
index fb2ff7b178b1..42c760d4dde8 100644
--- a/telephony/java/android/telephony/MbmsStreamingSession.java
+++ b/telephony/java/android/telephony/MbmsStreamingSession.java
@@ -24,9 +24,7 @@ import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.telephony.mbms.InternalStreamingSessionCallback;
import android.telephony.mbms.InternalStreamingServiceCallback;
@@ -42,6 +40,7 @@ import android.util.Log;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -89,14 +88,11 @@ public class MbmsStreamingSession implements AutoCloseable {
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
/** @hide */
- private MbmsStreamingSession(Context context, MbmsStreamingSessionCallback callback,
- int subscriptionId, Handler handler) {
+ private MbmsStreamingSession(Context context, Executor executor, int subscriptionId,
+ MbmsStreamingSessionCallback callback) {
mContext = context;
mSubscriptionId = subscriptionId;
- if (handler == null) {
- handler = new Handler(Looper.getMainLooper());
- }
- mInternalCallback = new InternalStreamingSessionCallback(callback, handler);
+ mInternalCallback = new InternalStreamingSessionCallback(callback, executor);
}
/**
@@ -117,25 +113,25 @@ public class MbmsStreamingSession implements AutoCloseable {
* {@link MbmsStreamingSession} that you received before calling this method again.
*
* @param context The {@link Context} to use.
+ * @param executor The executor on which you wish to execute callbacks.
+ * @param subscriptionId The subscription ID to use.
* @param callback A callback object on which you wish to receive results of asynchronous
* operations.
- * @param subscriptionId The subscription ID to use.
- * @param handler The handler you wish to receive callbacks on.
* @return An instance of {@link MbmsStreamingSession}, or null if an error occurred.
*/
public static @Nullable MbmsStreamingSession create(@NonNull Context context,
- final @NonNull MbmsStreamingSessionCallback callback, int subscriptionId,
- @NonNull Handler handler) {
+ @NonNull Executor executor, int subscriptionId,
+ final @NonNull MbmsStreamingSessionCallback callback) {
if (!sIsInitialized.compareAndSet(false, true)) {
throw new IllegalStateException("Cannot create two instances of MbmsStreamingSession");
}
- MbmsStreamingSession session = new MbmsStreamingSession(context, callback,
- subscriptionId, handler);
+ MbmsStreamingSession session = new MbmsStreamingSession(context, executor,
+ subscriptionId, callback);
final int result = session.bindAndInitialize();
if (result != MbmsErrors.SUCCESS) {
sIsInitialized.set(false);
- handler.post(new Runnable() {
+ executor.execute(new Runnable() {
@Override
public void run() {
callback.onError(result, null);
@@ -148,22 +144,22 @@ public class MbmsStreamingSession implements AutoCloseable {
/**
* Create a new {@link MbmsStreamingSession} using the system default data subscription ID.
- * See {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)}.
+ * See {@link #create(Context, Executor, int, MbmsStreamingSessionCallback)}.
*/
public static MbmsStreamingSession create(@NonNull Context context,
- @NonNull MbmsStreamingSessionCallback callback, @NonNull Handler handler) {
- return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler);
+ @NonNull Executor executor, @NonNull MbmsStreamingSessionCallback callback) {
+ return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
}
/**
* Terminates this instance. Also terminates
* any streaming services spawned from this instance as if
- * {@link StreamingService#stopStreaming()} had been called on them. After this method returns,
+ * {@link StreamingService#close()} had been called on them. After this method returns,
* no further callbacks originating from the middleware will be enqueued on the provided
* instance of {@link MbmsStreamingSessionCallback}, but callbacks that have already been
* enqueued will still be delivered.
*
- * It is safe to call {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)} to
+ * It is safe to call {@link #create(Context, Executor, int, MbmsStreamingSessionCallback)} to
* obtain another instance of {@link MbmsStreamingSession} immediately after this method
* returns.
*
@@ -237,20 +233,20 @@ public class MbmsStreamingSession implements AutoCloseable {
* {@link MbmsErrors.StreamingErrors}.
*
* @param serviceInfo The information about the service to stream.
+ * @param executor The executor on which you wish to execute callbacks for this stream.
* @param callback A callback that'll be called when something about the stream changes.
- * @param handler A handler that calls to {@code callback} should be called on.
* @return An instance of {@link StreamingService} through which the stream can be controlled.
* May be {@code null} if an error occurred.
*/
public @Nullable StreamingService startStreaming(StreamingServiceInfo serviceInfo,
- StreamingServiceCallback callback, @NonNull Handler handler) {
+ @NonNull Executor executor, StreamingServiceCallback callback) {
IMbmsStreamingService streamingService = mService.get();
if (streamingService == null) {
throw new IllegalStateException("Middleware not yet bound");
}
InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback(
- callback, handler);
+ callback, executor);
StreamingService serviceForApp = new StreamingService(
mSubscriptionId, streamingService, this, serviceInfo, serviceCallback);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cb867abb74d4..b6be3c5b6a03 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -178,7 +178,6 @@ public class ServiceState implements Parcelable {
/**
* Number of radio technologies for GSM, UMTS and CDMA.
- * @hide
*/
private static final int NEXT_RIL_RADIO_TECHNOLOGY = 20;
@@ -340,6 +339,8 @@ public class ServiceState implements Parcelable {
mIsEmergencyOnly = s.mIsEmergencyOnly;
mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
+ mChannelNumber = s.mChannelNumber;
+ mCellBandwidths = Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost;
mNetworkRegistrationStates = new ArrayList<>(s.mNetworkRegistrationStates);
}
@@ -1526,7 +1527,9 @@ public class ServiceState implements Parcelable {
*/
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates() {
- return mNetworkRegistrationStates;
+ synchronized (mNetworkRegistrationStates) {
+ return new ArrayList<>(mNetworkRegistrationStates);
+ }
}
/**
@@ -1539,11 +1542,15 @@ public class ServiceState implements Parcelable {
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
List<NetworkRegistrationState> list = new ArrayList<>();
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType) {
- list.add(networkRegistrationState);
+
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType) {
+ list.add(networkRegistrationState);
+ }
}
}
+
return list;
}
@@ -1557,12 +1564,36 @@ public class ServiceState implements Parcelable {
*/
@SystemApi
public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType
- && networkRegistrationState.getDomain() == domain) {
- return networkRegistrationState;
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType
+ && networkRegistrationState.getDomain() == domain) {
+ return networkRegistrationState;
+ }
}
}
+
return null;
}
+
+ /**
+ * @hide
+ */
+ public void addNetworkRegistrationState(NetworkRegistrationState regState) {
+ if (regState == null) return;
+
+ synchronized (mNetworkRegistrationStates) {
+ for (int i = 0; i < mNetworkRegistrationStates.size(); i++) {
+ NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i);
+ if (curRegState.getTransportType() == regState.getTransportType()
+ && curRegState.getDomain() == regState.getDomain()) {
+ mNetworkRegistrationStates.remove(i);
+ break;
+ }
+ }
+
+ mNetworkRegistrationStates.add(regState);
+ }
+ }
+
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index fc2ef2782b78..e508b19302f9 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -57,7 +57,9 @@ public class SignalStrength implements Parcelable {
*/
public static final int INVALID = Integer.MAX_VALUE;
- private static final int LTE_RSRP_THRESHOLDS_NUM = 6;
+ private static final int LTE_RSRP_THRESHOLDS_NUM = 4;
+ private static final int MAX_LTE_RSRP = -44;
+ private static final int MIN_LTE_RSRP = -140;
/** Parameters reported by the Radio */
private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
@@ -81,7 +83,8 @@ public class SignalStrength implements Parcelable {
// onSignalStrengthResult.
private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar.
- // The threshold of LTE RSRP for determining the display level of LTE signal bar.
+ // The threshold of LTE RSRP for determining the display level of LTE signal bar. Note that the
+ // min and max are fixed at MIN_LTE_RSRP (-140) and MAX_LTE_RSRP (-44).
private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM];
/**
@@ -319,7 +322,8 @@ public class SignalStrength implements Parcelable {
// TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
- mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID;
+ mLteRsrp = ((-mLteRsrp >= MIN_LTE_RSRP) && (-mLteRsrp <= MAX_LTE_RSRP)) ? -mLteRsrp
+ : SignalStrength.INVALID;
mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
: SignalStrength.INVALID;
@@ -735,24 +739,29 @@ public class SignalStrength implements Parcelable {
*/
public int getLteLevel() {
/*
- * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received
- * signal + noise RSRP = reference signal dBm RSRQ = quality of signal
- * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio
- * = -10log P1/P2 dB
+ * TS 36.214 Physical Layer Section 5.1.3
+ * TS 36.331 RRC
+ *
+ * RSSI = received signal + noise
+ * RSRP = reference signal dBm
+ * RSRQ = quality of signal dB = Number of Resource blocks*RSRP/RSSI
+ * SNR = gain = signal/noise ratio = -10log P1/P2 dB
*/
int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
- if (mLteRsrp > mLteRsrpThresholds[5]) {
- rsrpIconLevel = -1;
- } else if (mLteRsrp >= (mLteRsrpThresholds[4] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+ if (mLteRsrp > MAX_LTE_RSRP || mLteRsrp < MIN_LTE_RSRP) {
+ if (mLteRsrp != INVALID) {
+ Log.wtf(LOG_TAG, "getLteLevel - invalid lte rsrp: mLteRsrp=" + mLteRsrp);
+ }
} else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+ rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
} else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) {
- rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+ rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
} else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) {
+ rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+ } else if (mLteRsrp >= (mLteRsrpThresholds[0] - mLteRsrpBoost)) {
rsrpIconLevel = SIGNAL_STRENGTH_POOR;
- } else if (mLteRsrp >= mLteRsrpThresholds[0]) {
+ } else {
rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 9a45e7b9cc36..b44f830c45fe 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -391,6 +391,112 @@ public final class SmsManager {
}
/**
+ * Send a text based SMS with messaging options.
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is successfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending messages through same link or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ *
+ * @throws IllegalArgumentException if destinationAddress or text are empty
+ * {@hide}
+ */
+ public void sendTextMessage(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+ true /* persistMessage*/, priority, expectMore, validityPeriod);
+ }
+
+ private void sendTextMessageInternal(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
+ int priority, boolean expectMore, int validityPeriod) {
+ if (TextUtils.isEmpty(destinationAddress)) {
+ throw new IllegalArgumentException("Invalid destinationAddress");
+ }
+
+ if (TextUtils.isEmpty(text)) {
+ throw new IllegalArgumentException("Invalid message body");
+ }
+
+ if (priority < 0x00 || priority > 0x03) {
+ throw new IllegalArgumentException("Invalid priority");
+ }
+
+ if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ throw new IllegalArgumentException("Invalid validity period");
+ }
+
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
+ ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
+ sentIntent, deliveryIntent, persistMessage, priority, expectMore,
+ validityPeriod);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ /**
+ * Send a text based SMS without writing it into the SMS Provider.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
+ * privileges.
+ * </p>
+ *
+ * @see #sendTextMessage(String, String, String, PendingIntent,
+ * PendingIntent, int, boolean, int)
+ * @hide
+ */
+ public void sendTextMessageWithoutPersisting(
+ String destinationAddress, String scAddress, String text,
+ PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
+ boolean expectMore, int validityPeriod) {
+ sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+ false /* persistMessage */, priority, expectMore, validityPeriod);
+ }
+
+ /**
+ *
* Inject an SMS PDU into the android application framework.
*
* <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
@@ -545,6 +651,140 @@ public final class SmsManager {
}
/**
+ * Send a multi-part text based SMS with messaging options. The callee should have already
+ * divided the message into correctly sized parts by calling
+ * <code>divideMessage</code>.
+ *
+ * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
+ * {@link android.Manifest.permission#SEND_SMS} permission.</p>
+ *
+ * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
+ * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
+ * writes messages sent using this method to the SMS Provider (the default SMS app is always
+ * responsible for writing its sent messages to the SMS Provider). For information about
+ * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending messages through same link or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ *
+ * @throws IllegalArgumentException if destinationAddress or data are empty
+ * {@hide}
+ */
+ public void sendMultipartTextMessage(
+ String destinationAddress, String scAddress, ArrayList<String> parts,
+ ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
+ deliveryIntents, true /* persistMessage*/);
+ }
+
+ private void sendMultipartTextMessageInternal(
+ String destinationAddress, String scAddress, List<String> parts,
+ List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
+ boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
+ if (TextUtils.isEmpty(destinationAddress)) {
+ throw new IllegalArgumentException("Invalid destinationAddress");
+ }
+ if (parts == null || parts.size() < 1) {
+ throw new IllegalArgumentException("Invalid message body");
+ }
+
+ if (priority < 0x00 || priority > 0x03) {
+ throw new IllegalArgumentException("Invalid priority");
+ }
+
+ if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ throw new IllegalArgumentException("Invalid validity period");
+ }
+
+ if (parts.size() > 1) {
+ try {
+ ISms iccISms = getISmsServiceOrThrow();
+ if (iccISms != null) {
+ iccISms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
+ ActivityThread.currentPackageName(), destinationAddress, scAddress,
+ parts, sentIntents, deliveryIntents, persistMessage, priority,
+ expectMore, validityPeriod);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ } else {
+ PendingIntent sentIntent = null;
+ PendingIntent deliveryIntent = null;
+ if (sentIntents != null && sentIntents.size() > 0) {
+ sentIntent = sentIntents.get(0);
+ }
+ if (deliveryIntents != null && deliveryIntents.size() > 0) {
+ deliveryIntent = deliveryIntents.get(0);
+ }
+ sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
+ sentIntent, deliveryIntent, persistMessage, priority, expectMore,
+ validityPeriod);
+ }
+ }
+
+ /**
+ * Send a multi-part text based SMS without writing it into the SMS Provider.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
+ * privileges.
+ * </p>
+ *
+ * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
+ * ArrayList, int, boolean, int)
+ * @hide
+ **/
+ public void sendMultipartTextMessageWithoutPersisting(
+ String destinationAddress, String scAddress, List<String> parts,
+ List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
+ int priority, boolean expectMore, int validityPeriod) {
+ sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
+ deliveryIntents, false /* persistMessage*/, priority, expectMore,
+ validityPeriod);
+ }
+
+ /**
* Send a data based SMS to a specific application port.
*
* <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -1007,7 +1247,7 @@ public final class SmsManager {
* <code>getAllMessagesFromIcc</code>
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
*/
- private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
+ private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
if (records != null) {
int count = records.size();
@@ -1015,7 +1255,8 @@ public final class SmsManager {
SmsRawData data = records.get(i);
// List contains all records, including "free" records (null)
if (data != null) {
- SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
+ SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
+ getSubscriptionId());
if (sms != null) {
messages.add(sms);
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 6e083c21cd5b..ea74bac7208f 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -268,6 +268,31 @@ public class SmsMessage {
}
/**
+ * Create an SmsMessage from an SMS EF record.
+ *
+ * @param index Index of SMS record. This should be index in ArrayList
+ * returned by SmsManager.getAllMessagesFromSim + 1.
+ * @param data Record data.
+ * @param subId Subscription Id of the SMS
+ * @return An SmsMessage representing the record.
+ *
+ * @hide
+ */
+ public static SmsMessage createFromEfRecord(int index, byte[] data, int subId) {
+ SmsMessageBase wrappedMessage;
+
+ if (isCdmaVoice(subId)) {
+ wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
+ index, data);
+ } else {
+ wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
+ index, data);
+ }
+
+ return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
+ }
+
+ /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
@@ -827,6 +852,7 @@ public class SmsMessage {
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId);
return (PHONE_TYPE_CDMA == activePhone);
}
+
/**
* Decide if the carrier supports long SMS.
* {@hide}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 30e75b9bed91..d09d4263ccc5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -543,9 +543,9 @@ public class SubscriptionManager {
* onSubscriptionsChanged overridden.
*/
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
- String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (DBG) {
- logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
+ logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
+ " listener=" + listener);
}
try {
@@ -554,7 +554,7 @@ public class SubscriptionManager {
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
if (tr != null) {
- tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
+ tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
}
} catch (RemoteException ex) {
// Should not happen
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 63263bd37206..cb87d1fb1d56 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -1103,10 +1103,15 @@ public final class Telephony {
"android.provider.Telephony.MMS_DOWNLOADED";
/**
- * Broadcast Action: A debug code has been entered in the dialer. These "secret codes"
- * are used to activate developer menus by dialing certain codes. And they are of the
- * form {@code *#*#&lt;code&gt;#*#*}. The intent will have the data URI:
- * {@code android_secret_code://&lt;code&gt;}.
+ * Broadcast Action: A debug code has been entered in the dialer. This intent is
+ * broadcast by the system and OEM telephony apps may need to receive these broadcasts.
+ * These "secret codes" are used to activate developer menus by dialing certain codes.
+ * And they are of the form {@code *#*#&lt;code&gt;#*#*}. The intent will have the data
+ * URI: {@code android_secret_code://&lt;code&gt;}. It is possible that a manifest
+ * receiver would be woken up even if it is not currently running.
+ *
+ * <p>Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to
+ * send and receive.</p>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SECRET_CODE_ACTION =
@@ -2732,6 +2737,7 @@ public final class Telephony {
* This should be spread to other technologies,
* but is currently only used for LTE (14) and eHRPD (13).
* <P>Type: INTEGER</P>
+ * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
public static final String BEARER = "bearer";
@@ -2744,13 +2750,14 @@ public final class Telephony {
* Bitmask for a radio tech R is (1 << (R - 1))
* <P>Type: INTEGER</P>
* @hide
+ * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
public static final String BEARER_BITMASK = "bearer_bitmask";
/**
* Radio technology (network type) bitmask.
- * To check what values can be contained, refer to
+ * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
* {@link android.telephony.TelephonyManager}.
* Bitmask for a radio tech R is (1 << (R - 1))
* <P>Type: INTEGER</P>
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 71e7ca1fd30c..fdb31eb4e8ff 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -52,6 +52,7 @@ import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -3879,6 +3880,9 @@ public class TelephonyManager {
* To unregister a listener, pass the listener object and set the
* events argument to
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+ * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+ * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+ * {@link SecurityException} will be thrown otherwise.
*
* @param listener The {@link PhoneStateListener} object to register
* (or unregister)
@@ -4671,8 +4675,6 @@ public class TelephonyManager {
return;
}
- Rlog.d(TAG, "setTelephonyProperty: success phoneId=" + phoneId +
- " property=" + property + " value: " + value + " propVal=" + propVal);
SystemProperties.set(property, propVal);
}
@@ -5105,6 +5107,24 @@ public class TelephonyManager {
}
/**
+ * Determines if emergency calling is allowed for the MMTEL feature on the slot provided.
+ * @param slotIndex The SIM slot of the MMTEL feature
+ * @return true if emergency calling is allowed, false otherwise.
+ * @hide
+ */
+ public boolean isEmergencyMmTelAvailable(int slotIndex) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isEmergencyMmTelAvailable(slotIndex);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "isEmergencyMmTelAvailable, RemoteException: " + e.getMessage());
+ }
+ return false;
+ }
+
+ /**
* Set IMS registration state
*
* @param Registration state
@@ -6236,84 +6256,106 @@ public class TelephonyManager {
return false;
}
- /**
- * Returns the IMS Registration Status
- * @hide
- */
- public boolean isImsRegistered() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony == null)
- return false;
- return telephony.isImsRegistered();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
/**
- * Returns the IMS Registration Status for a particular Subscription ID
+ * Returns the IMS Registration Status for a particular Subscription ID.
*
* @param subId Subscription ID
* @return true if IMS status is registered, false if the IMS status is not registered or a
* RemoteException occurred.
- *
* @hide
*/
public boolean isImsRegistered(int subId) {
+ try {
+ return getITelephony().isImsRegistered(subId);
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the IMS Registration Status for a particular Subscription ID, which is determined
+ * when the TelephonyManager is created using {@link #createForSubscriptionId(int)}. If an
+ * invalid subscription ID is used during creation, will the default subscription ID will be
+ * used.
+ *
+ * @return true if IMS status is registered, false if the IMS status is not registered or a
+ * RemoteException occurred.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
+ * @hide
+ */
+ public boolean isImsRegistered() {
try {
- return getITelephony().isImsRegisteredForSubscriber(subId);
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isImsRegistered(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
/**
- * Returns the Status of Volte
+ * The current status of Voice over LTE for the subscription associated with this instance when
+ * it was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used.
+ * @return true if Voice over LTE is available or false if it is unavailable or unknown.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
* @hide
*/
public boolean isVolteAvailable() {
- try {
- return getITelephony().isVolteAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
+ try {
+ return getITelephony().isVolteAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
/**
- * Returns the Status of video telephony (VT)
+ * The availability of Video Telephony (VT) for the subscription ID specified when this instance
+ * was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used. To query the
+ * underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}.
+ * @return true if VT is available, or false if it is unavailable or unknown.
* @hide
*/
public boolean isVideoTelephonyAvailable() {
try {
- return getITelephony().isVideoTelephonyAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isVideoTelephonyAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified.
+ * @param subId the subscription ID.
+ * @return true if VoWiFi is available, or false if it is unavailable or unknown.
* @hide
*/
public boolean isWifiCallingAvailable() {
try {
- return getITelephony().isWifiCallingAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isWifiCallingAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
+ /**
+ * The technology that IMS is registered for for the MMTEL feature.
+ * @param subId subscription ID to get IMS registration technology for.
+ * @return The IMS registration technology that IMS is registered to for the MMTEL feature.
+ * Valid return results are:
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} for LTE registration,
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} for IWLAN registration, or
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the
+ * result is unavailable.
+ * @hide
+ */
+ public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() {
+ try {
+ return getITelephony().getImsRegTechnologyForMmTel(getSubId());
+ } catch (RemoteException ex) {
+ return ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+ }
+ }
+
/**
* Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
*
@@ -6944,18 +6986,16 @@ public class TelephonyManager {
*
* @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
* subscription is unavailable or the carrier cannot be identified.
- * @throws IllegalStateException if telephony service is unavailable.
*/
public int getAndroidCarrierIdForSubscription() {
try {
ITelephony service = getITelephony();
- return service.getSubscriptionCarrierId(getSubId());
+ if (service != null) {
+ return service.getSubscriptionCarrierId(getSubId());
+ }
} catch (RemoteException ex) {
// This could happen if binder process crashes.
ex.rethrowAsRuntimeException();
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing.
- throw new IllegalStateException("Telephony service unavailable");
}
return UNKNOWN_CARRIER_ID;
}
@@ -6971,18 +7011,16 @@ public class TelephonyManager {
*
* @return Carrier name of the current subscription. Return {@code null} if the subscription is
* unavailable or the carrier cannot be identified.
- * @throws IllegalStateException if telephony service is unavailable.
*/
public CharSequence getAndroidCarrierNameForSubscription() {
try {
ITelephony service = getITelephony();
- return service.getSubscriptionCarrierName(getSubId());
+ if (service != null) {
+ return service.getSubscriptionCarrierName(getSubId());
+ }
} catch (RemoteException ex) {
// This could happen if binder process crashes.
ex.rethrowAsRuntimeException();
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing.
- throw new IllegalStateException("Telephony service unavailable");
}
return null;
}
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index c3f8a1930409..21bc9d022d4c 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -221,6 +221,15 @@ public final class UiccAccessRule implements Parcelable {
}
@Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 * result + Arrays.hashCode(mCertificateHash);
+ result = 31 * result + Objects.hashCode(mPackageName);
+ result = 31 * result + Objects.hashCode(mAccessType);
+ return result;
+ }
+
+ @Override
public String toString() {
return "cert: " + IccUtils.bytesToHexString(mCertificateHash) + " pkg: " +
mPackageName + " access: " + mAccessType;
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 41c1430e386f..e8597b221391 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -17,6 +17,7 @@
package android.telephony.data;
import android.annotation.SystemApi;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -230,8 +231,10 @@ public final class DataProfile implements Parcelable {
@Override
public String toString() {
- return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType
- + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime
+ return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+ + "/" + (Build.IS_USER ? "***/***/***" :
+ (mApn + "/" + mUserName + "/" + mPassword))
+ + "/" + mType + "/" + mMaxConnsTime
+ "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
+ mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
+ mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 7b7749102590..7d654305015e 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -393,6 +393,12 @@ public final class ImsReasonInfo implements Parcelable {
*/
public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514;
+ /**
+ * Call failed because of unobtainable number
+ * @hide
+ */
+ public static final int CODE_UNOBTAINABLE_NUMBER = 1515;
+
/* OEM specific error codes. To be used by OEMs when they don't want to
reveal error code which would be replaced by ERROR_UNSPECIFIED */
public static final int CODE_OEM_CAUSE_1 = 0xf001;
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index bfdd4533275b..d53769907342 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -80,14 +80,16 @@ public abstract class ImsFeature {
public static final String EXTRA_PHONE_ID = "android:phone_id";
/**
- * Invalid feature value\
+ * Invalid feature value
* @hide
*/
public static final int FEATURE_INVALID = -1;
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
// defined values in ImsServiceClass for compatibility purposes.
/**
- * This feature supports emergency calling over MMTEL.
+ * This feature supports emergency calling over MMTEL. If defined, the framework will try to
+ * place an emergency call over IMS first. If it is not defined, the framework will only use
+ * CSFB for emergency calling.
*/
public static final int FEATURE_EMERGENCY_MMTEL = 0;
/**
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 09267fc2554c..2fffd36a1a4f 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -332,20 +332,14 @@ public class MmTelFeature extends ImsFeature {
public static final int PROCESS_CALL_IMS = 0;
/**
* To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
- * not process the outgoing NON_EMERGENCY call as IMS and should instead use circuit switch.
+ * not process the outgoing call as IMS and should instead use circuit switch.
*/
public static final int PROCESS_CALL_CSFB = 1;
- /**
- * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
- * not process the outgoing EMERGENCY call as IMS and should instead use circuit switch.
- */
- public static final int PROCESS_CALL_EMERGENCY_CSFB = 2;
@IntDef(flag = true,
value = {
PROCESS_CALL_IMS,
- PROCESS_CALL_CSFB,
- PROCESS_CALL_EMERGENCY_CSFB
+ PROCESS_CALL_CSFB
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessCallResult {}
@@ -536,12 +530,15 @@ public class MmTelFeature extends ImsFeature {
/**
* Called by the framework to determine if the outgoing call, designated by the outgoing
- * {@link Uri}s, should be processed as an IMS call or CSFB call.
+ * {@link String}s, should be processed as an IMS call or CSFB call. If this method's
+ * functionality is not overridden, the platform will process every call as IMS as long as the
+ * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is
+ * available.
* @param numbers An array of {@link String}s that will be used for placing the call. There can
* be multiple {@link String}s listed in the case when we want to place an outgoing
* call as a conference.
* @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
- * call wil lbe placed over IMS or via CSFB.
+ * call will be placed over IMS or via CSFB.
*/
public @ProcessCallResult int shouldProcessCall(String[] numbers) {
return PROCESS_CALL_IMS;
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index bf8953386e49..92d62da8d00c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -74,7 +74,9 @@ public class ImsSmsImplBase {
/** @hide */
@IntDef({
DELIVER_STATUS_OK,
- DELIVER_STATUS_ERROR
+ DELIVER_STATUS_ERROR_GENERIC,
+ DELIVER_STATUS_ERROR_NO_MEMORY,
+ DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeliverStatusResult {}
@@ -86,7 +88,17 @@ public class ImsSmsImplBase {
/**
* Message was not delivered.
*/
- public static final int DELIVER_STATUS_ERROR = 2;
+ public static final int DELIVER_STATUS_ERROR_GENERIC = 2;
+
+ /**
+ * Message was not delivered due to lack of memory.
+ */
+ public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3;
+
+ /**
+ * Message was not delivered as the request is not supported.
+ */
+ public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4;
/** @hide */
@IntDef({
@@ -106,7 +118,6 @@ public class ImsSmsImplBase {
*/
public static final int STATUS_REPORT_STATUS_ERROR = 2;
-
// Lock for feature synchronization
private final Object mLock = new Object();
private IImsSmsListener mListener;
@@ -157,7 +168,9 @@ public class ImsSmsImplBase {
* @param token token provided in {@link #onSmsReceived(int, String, byte[])}
* @param result result of delivering the message. Valid values are:
* {@link #DELIVER_STATUS_OK},
- * {@link #DELIVER_STATUS_ERROR}
+ * {@link #DELIVER_STATUS_ERROR_GENERIC},
+ * {@link #DELIVER_STATUS_ERROR_NO_MEMORY},
+ * {@link #DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED}
* @param messageRef the message reference
*/
public void acknowledgeSms(int token, @DeliverStatusResult int messageRef, int result) {
@@ -202,7 +215,7 @@ public class ImsSmsImplBase {
mListener.onSmsReceived(token, format, pdu);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
- acknowledgeSms(token, 0, DELIVER_STATUS_ERROR);
+ acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC);
}
}
}
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
index f0d60b68eb94..602c796aa188 100644
--- a/telephony/java/android/telephony/mbms/DownloadRequest.java
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -27,10 +27,13 @@ import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.File;
import java.io.IOException;
+import java.io.ObjectInput;
import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
-import java.io.Serializable;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -54,34 +57,116 @@ public final class DownloadRequest implements Parcelable {
public static final int MAX_DESTINATION_URI_SIZE = 50000;
/** @hide */
- private static class OpaqueDataContainer implements Serializable {
- private final String appIntent;
- private final int version;
+ private static class SerializationDataContainer implements Externalizable {
+ private String fileServiceId;
+ private Uri source;
+ private Uri destination;
+ private int subscriptionId;
+ private String appIntent;
+ private int version;
- public OpaqueDataContainer(String appIntent, int version) {
- this.appIntent = appIntent;
- this.version = version;
+ public SerializationDataContainer() {}
+
+ SerializationDataContainer(DownloadRequest request) {
+ fileServiceId = request.fileServiceId;
+ source = request.sourceUri;
+ destination = request.destinationUri;
+ subscriptionId = request.subscriptionId;
+ appIntent = request.serializedResultIntentForApp;
+ version = request.version;
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput objectOutput) throws IOException {
+ objectOutput.write(version);
+ objectOutput.writeUTF(fileServiceId);
+ objectOutput.writeUTF(source.toString());
+ objectOutput.writeUTF(destination.toString());
+ objectOutput.write(subscriptionId);
+ objectOutput.writeUTF(appIntent);
+ }
+
+ @Override
+ public void readExternal(ObjectInput objectInput) throws IOException {
+ version = objectInput.read();
+ fileServiceId = objectInput.readUTF();
+ source = Uri.parse(objectInput.readUTF());
+ destination = Uri.parse(objectInput.readUTF());
+ subscriptionId = objectInput.read();
+ appIntent = objectInput.readUTF();
+ // Do version checks here -- future versions may have other fields.
}
}
public static class Builder {
private String fileServiceId;
private Uri source;
+ private Uri destination;
private int subscriptionId;
private String appIntent;
private int version = CURRENT_VERSION;
+ /**
+ * Constructs a {@link Builder} from a {@link DownloadRequest}
+ * @param other The {@link DownloadRequest} from which the data for the {@link Builder}
+ * should come.
+ * @return An instance of {@link Builder} pre-populated with data from the provided
+ * {@link DownloadRequest}.
+ */
+ public static Builder fromDownloadRequest(DownloadRequest other) {
+ Builder result = new Builder(other.sourceUri, other.destinationUri)
+ .setServiceId(other.fileServiceId)
+ .setSubscriptionId(other.subscriptionId);
+ result.appIntent = other.serializedResultIntentForApp;
+ // Version of the result is going to be the current version -- as this class gets
+ // updated, new fields will be set to default values in here.
+ return result;
+ }
+
+ /**
+ * This method constructs a new instance of {@link Builder} based on the serialized data
+ * passed in.
+ * @param data A byte array, the contents of which should have been originally obtained
+ * from {@link DownloadRequest#toByteArray()}.
+ */
+ public static Builder fromSerializedRequest(byte[] data) {
+ Builder builder;
+ try {
+ ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(data));
+ SerializationDataContainer dataContainer =
+ (SerializationDataContainer) stream.readObject();
+ builder = new Builder(dataContainer.source, dataContainer.destination);
+ builder.version = dataContainer.version;
+ builder.appIntent = dataContainer.appIntent;
+ builder.fileServiceId = dataContainer.fileServiceId;
+ builder.subscriptionId = dataContainer.subscriptionId;
+ } catch (IOException e) {
+ // Really should never happen
+ Log.e(LOG_TAG, "Got IOException trying to parse opaque data");
+ throw new IllegalArgumentException(e);
+ } catch (ClassNotFoundException e) {
+ Log.e(LOG_TAG, "Got ClassNotFoundException trying to parse opaque data");
+ throw new IllegalArgumentException(e);
+ }
+ return builder;
+ }
/**
* Builds a new DownloadRequest.
* @param sourceUri the source URI for the DownloadRequest to be built. This URI should
* never be null.
+ * @param destinationUri The final location for the file(s) that are to be downloaded. It
+ * must be on the same filesystem as the temp file directory set via
+ * {@link android.telephony.MbmsDownloadSession#setTempFileRootDirectory(File)}.
+ * The provided path must be a directory that exists. An
+ * {@link IllegalArgumentException} will be thrown otherwise.
*/
- public Builder(@NonNull Uri sourceUri) {
- if (sourceUri == null) {
- throw new IllegalArgumentException("Source URI must be non-null.");
+ public Builder(@NonNull Uri sourceUri, @NonNull Uri destinationUri) {
+ if (sourceUri == null || destinationUri == null) {
+ throw new IllegalArgumentException("Source and destination URIs must be non-null.");
}
source = sourceUri;
+ destination = destinationUri;
}
/**
@@ -130,68 +215,34 @@ public final class DownloadRequest implements Parcelable {
return this;
}
- /**
- * For use by the middleware to set the byte array of opaque data. The opaque data
- * includes information about the download request that is used by the client app and the
- * manager code, but is irrelevant to the middleware.
- * @param data A byte array, the contents of which should have been originally obtained
- * from {@link DownloadRequest#getOpaqueData()}.
- * @hide
- */
- @SystemApi
- public Builder setOpaqueData(byte[] data) {
- try {
- ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(data));
- OpaqueDataContainer dataContainer = (OpaqueDataContainer) stream.readObject();
- version = dataContainer.version;
- appIntent = dataContainer.appIntent;
- } catch (IOException e) {
- // Really should never happen
- Log.e(LOG_TAG, "Got IOException trying to parse opaque data");
- throw new IllegalArgumentException(e);
- } catch (ClassNotFoundException e) {
- Log.e(LOG_TAG, "Got ClassNotFoundException trying to parse opaque data");
- throw new IllegalArgumentException(e);
- }
- return this;
- }
-
public DownloadRequest build() {
- return new DownloadRequest(fileServiceId, source, subscriptionId, appIntent, version);
+ return new DownloadRequest(fileServiceId, source, destination,
+ subscriptionId, appIntent, version);
}
}
private final String fileServiceId;
private final Uri sourceUri;
+ private final Uri destinationUri;
private final int subscriptionId;
private final String serializedResultIntentForApp;
private final int version;
private DownloadRequest(String fileServiceId,
- Uri source, int sub,
+ Uri source, Uri destination, int sub,
String appIntent, int version) {
this.fileServiceId = fileServiceId;
sourceUri = source;
subscriptionId = sub;
+ destinationUri = destination;
serializedResultIntentForApp = appIntent;
this.version = version;
}
- public static DownloadRequest copy(DownloadRequest other) {
- return new DownloadRequest(other);
- }
-
- private DownloadRequest(DownloadRequest dr) {
- fileServiceId = dr.fileServiceId;
- sourceUri = dr.sourceUri;
- subscriptionId = dr.subscriptionId;
- serializedResultIntentForApp = dr.serializedResultIntentForApp;
- version = dr.version;
- }
-
private DownloadRequest(Parcel in) {
fileServiceId = in.readString();
sourceUri = in.readParcelable(getClass().getClassLoader());
+ destinationUri = in.readParcelable(getClass().getClassLoader());
subscriptionId = in.readInt();
serializedResultIntentForApp = in.readString();
version = in.readInt();
@@ -204,6 +255,7 @@ public final class DownloadRequest implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(fileServiceId);
out.writeParcelable(sourceUri, flags);
+ out.writeParcelable(destinationUri, flags);
out.writeInt(subscriptionId);
out.writeString(serializedResultIntentForApp);
out.writeInt(version);
@@ -224,6 +276,13 @@ public final class DownloadRequest implements Parcelable {
}
/**
+ * @return The destination {@link Uri} of the downloaded file.
+ */
+ public Uri getDestinationUri() {
+ return destinationUri;
+ }
+
+ /**
* @return The subscription ID on which to perform MBMS operations.
*/
public int getSubscriptionId() {
@@ -244,19 +303,16 @@ public final class DownloadRequest implements Parcelable {
}
/**
- * For use by the middleware only. The byte array returned from this method should be
- * persisted and sent back to the app upon download completion or failure by passing it into
- * {@link Builder#setOpaqueData(byte[])}.
- * @return A byte array of opaque data to persist.
- * @hide
+ * This method returns a byte array that may be persisted to disk and restored to a
+ * {@link DownloadRequest}. The instance of {@link DownloadRequest} persisted by this method
+ * may be recovered via {@link Builder#fromSerializedRequest(byte[])}.
+ * @return A byte array of data to persist.
*/
- @SystemApi
- public byte[] getOpaqueData() {
+ public byte[] toByteArray() {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(byteArrayOutputStream);
- OpaqueDataContainer container = new OpaqueDataContainer(
- serializedResultIntentForApp, version);
+ SerializationDataContainer container = new SerializationDataContainer(this);
stream.writeObject(container);
stream.flush();
return byteArrayOutputStream.toByteArray();
@@ -299,15 +355,6 @@ public final class DownloadRequest implements Parcelable {
}
/**
- * @hide
- */
- public boolean isMultipartDownload() {
- // TODO: figure out what qualifies a request as a multipart download request.
- return getSourceUri().getLastPathSegment() != null &&
- getSourceUri().getLastPathSegment().contains("*");
- }
-
- /**
* Retrieves the hash string that should be used as the filename when storing a token for
* this DownloadRequest.
* @hide
@@ -320,8 +367,9 @@ public final class DownloadRequest implements Parcelable {
throw new RuntimeException("Could not get sha256 hash object");
}
if (version >= 1) {
- // Hash the source URI and the app intent
+ // Hash the source, destination, and the app intent
digest.update(sourceUri.toString().getBytes(StandardCharsets.UTF_8));
+ digest.update(destinationUri.toString().getBytes(StandardCharsets.UTF_8));
if (serializedResultIntentForApp != null) {
digest.update(serializedResultIntentForApp.getBytes(StandardCharsets.UTF_8));
}
@@ -344,12 +392,13 @@ public final class DownloadRequest implements Parcelable {
version == request.version &&
Objects.equals(fileServiceId, request.fileServiceId) &&
Objects.equals(sourceUri, request.sourceUri) &&
+ Objects.equals(destinationUri, request.destinationUri) &&
Objects.equals(serializedResultIntentForApp, request.serializedResultIntentForApp);
}
@Override
public int hashCode() {
- return Objects.hash(fileServiceId, sourceUri,
+ return Objects.hash(fileServiceId, sourceUri, destinationUri,
subscriptionId, serializedResultIntentForApp, version);
}
}
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
index a7a5958fff56..c2a79d82f8b6 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
@@ -16,22 +16,23 @@
package android.telephony.mbms;
-import android.os.Handler;
+import android.os.Binder;
import android.os.RemoteException;
import java.util.List;
+import java.util.concurrent.Executor;
/** @hide */
public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallback.Stub {
- private final Handler mHandler;
+ private final Executor mExecutor;
private final MbmsDownloadSessionCallback mAppCallback;
private volatile boolean mIsStopped = false;
public InternalDownloadSessionCallback(MbmsDownloadSessionCallback appCallback,
- Handler handler) {
+ Executor executor) {
mAppCallback = appCallback;
- mHandler = handler;
+ mExecutor = executor;
}
@Override
@@ -40,10 +41,15 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onError(errorCode, message);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onError(errorCode, message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -54,10 +60,15 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onFileServicesUpdated(services);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onFileServicesUpdated(services);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -68,18 +79,19 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onMiddlewareReady();
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onMiddlewareReady();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
- public Handler getHandler() {
- return mHandler;
- }
-
public void stop() {
mIsStopped = true;
}
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java
index 8702952cf06b..f30ae27b19b1 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java
@@ -16,20 +16,22 @@
package android.telephony.mbms;
-import android.os.Handler;
+import android.os.Binder;
import android.os.RemoteException;
+import java.util.concurrent.Executor;
+
/**
* @hide
*/
public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub {
- private final Handler mHandler;
+ private final Executor mExecutor;
private final DownloadStateCallback mAppCallback;
private volatile boolean mIsStopped = false;
- public InternalDownloadStateCallback(DownloadStateCallback appCallback, Handler handler) {
+ public InternalDownloadStateCallback(DownloadStateCallback appCallback, Executor executor) {
mAppCallback = appCallback;
- mHandler = handler;
+ mExecutor = executor;
}
@Override
@@ -40,11 +42,16 @@ public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub {
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onProgressUpdated(request, fileInfo, currentDownloadSize,
- fullDownloadSize, currentDecodedSize, fullDecodedSize);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onProgressUpdated(request, fileInfo, currentDownloadSize,
+ fullDownloadSize, currentDecodedSize, fullDecodedSize);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -56,10 +63,15 @@ public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub {
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onStateUpdated(request, fileInfo, state);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onStateUpdated(request, fileInfo, state);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
index eb6579cec471..e9f39ff959cc 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
@@ -16,18 +16,21 @@
package android.telephony.mbms;
-import android.os.Handler;
+import android.os.Binder;
import android.os.RemoteException;
+import java.util.concurrent.Executor;
+
/** @hide */
public class InternalStreamingServiceCallback extends IStreamingServiceCallback.Stub {
private final StreamingServiceCallback mAppCallback;
- private final Handler mHandler;
+ private final Executor mExecutor;
private volatile boolean mIsStopped = false;
- public InternalStreamingServiceCallback(StreamingServiceCallback appCallback, Handler handler) {
+ public InternalStreamingServiceCallback(StreamingServiceCallback appCallback,
+ Executor executor) {
mAppCallback = appCallback;
- mHandler = handler;
+ mExecutor = executor;
}
@Override
@@ -36,10 +39,15 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onError(errorCode, message);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onError(errorCode, message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -50,10 +58,15 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onStreamStateUpdated(state, reason);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onStreamStateUpdated(state, reason);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -64,10 +77,15 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onMediaDescriptionUpdated();
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onMediaDescriptionUpdated();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -78,10 +96,15 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -92,10 +115,15 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onStreamMethodUpdated(methodType);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onStreamMethodUpdated(methodType);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
index d782d12c00d6..d47f5adbaf91 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
@@ -16,21 +16,22 @@
package android.telephony.mbms;
-import android.os.Handler;
+import android.os.Binder;
import android.os.RemoteException;
import java.util.List;
+import java.util.concurrent.Executor;
/** @hide */
public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallback.Stub {
- private final Handler mHandler;
+ private final Executor mExecutor;
private final MbmsStreamingSessionCallback mAppCallback;
private volatile boolean mIsStopped = false;
public InternalStreamingSessionCallback(MbmsStreamingSessionCallback appCallback,
- Handler handler) {
+ Executor executor) {
mAppCallback = appCallback;
- mHandler = handler;
+ mExecutor = executor;
}
@Override
@@ -39,10 +40,15 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onError(errorCode, message);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onError(errorCode, message);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -54,10 +60,15 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onStreamingServicesUpdated(services);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onStreamingServicesUpdated(services);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
@@ -68,18 +79,19 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- mHandler.post(new Runnable() {
+ mExecutor.execute(new Runnable() {
@Override
public void run() {
- mAppCallback.onMiddlewareReady();
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppCallback.onMiddlewareReady();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
});
}
- public Handler getHandler() {
- return mHandler;
- }
-
public void stop() {
mIsStopped = true;
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 9ef188cfd2b3..b0c00c6284a6 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -21,8 +21,10 @@ import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.MbmsDownloadSession;
@@ -31,14 +33,11 @@ import android.util.Log;
import java.io.File;
import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -62,6 +61,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
/** @hide */
public static final String MBMS_FILE_PROVIDER_META_DATA_KEY = "mbms-file-provider-authority";
+ private static final String EMBMS_INTENT_PERMISSION = "android.permission.SEND_EMBMS_INTENTS";
+
/**
* Indicates that the requested operation completed without error.
* @hide
@@ -137,6 +138,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
/** @hide */
@Override
public void onReceive(Context context, Intent intent) {
+ verifyPermissionIntegrity(context);
+
if (!verifyIntentContents(context, intent)) {
setResultCode(RESULT_MALFORMED_INTENT);
return;
@@ -260,20 +263,18 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
FileInfo completedFileInfo =
(FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO);
- Path stagingDirectory = FileSystems.getDefault().getPath(
- MbmsTempFileProvider.getEmbmsTempFileDir(context).getPath(),
- TEMP_FILE_STAGING_LOCATION);
+ Path appSpecifiedDestination = FileSystems.getDefault().getPath(
+ request.getDestinationUri().getPath());
- Uri stagedFileLocation;
+ Uri finalLocation;
try {
- stagedFileLocation = stageTempFile(finalTempFile, stagingDirectory);
+ finalLocation = moveToFinalLocation(finalTempFile, appSpecifiedDestination);
} catch (IOException e) {
Log.w(LOG_TAG, "Failed to move temp file to final destination");
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
return;
}
- intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_COMPLETED_FILE_URI,
- stagedFileLocation);
+ intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_COMPLETED_FILE_URI, finalLocation);
intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, completedFileInfo);
context.sendBroadcast(intentForApp);
@@ -437,19 +438,22 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
/*
- * Moves a tempfile located at fromPath to a new location in the staging directory.
+ * Moves a tempfile located at fromPath to its final home where the app wants it
*/
- private static Uri stageTempFile(Uri fromPath, Path stagingDirectory) throws IOException {
+ private static Uri moveToFinalLocation(Uri fromPath, Path appSpecifiedPath) throws IOException {
if (!ContentResolver.SCHEME_FILE.equals(fromPath.getScheme())) {
- Log.w(LOG_TAG, "Moving source uri " + fromPath+ " does not have a file scheme");
+ Log.w(LOG_TAG, "Downloaded file location uri " + fromPath +
+ " does not have a file scheme");
return null;
}
Path fromFile = FileSystems.getDefault().getPath(fromPath.getPath());
- if (!Files.isDirectory(stagingDirectory)) {
- Files.createDirectory(stagingDirectory);
+ if (!Files.isDirectory(appSpecifiedPath)) {
+ Files.createDirectory(appSpecifiedPath);
}
- Path result = Files.move(fromFile, stagingDirectory.resolve(fromFile.getFileName()));
+ // TODO: do we want to support directory trees within the download directory?
+ Path result = Files.move(fromFile, appSpecifiedPath.resolve(fromFile.getFileName()),
+ StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
return Uri.fromFile(result.toFile());
}
@@ -513,39 +517,29 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
return mMiddlewarePackageNameCache;
}
- private static boolean manualMove(File src, File dst) {
- InputStream in = null;
- OutputStream out = null;
- try {
- if (!dst.exists()) {
- dst.createNewFile();
- }
- in = new FileInputStream(src);
- out = new FileOutputStream(dst);
- byte[] buffer = new byte[2048];
- int len;
- do {
- len = in.read(buffer);
- out.write(buffer, 0, len);
- } while (len > 0);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Manual file move failed due to exception " + e);
- if (dst.exists()) {
- dst.delete();
- }
- return false;
- } finally {
- try {
- if (in != null) {
- in.close();
- }
- if (out != null) {
- out.close();
- }
- } catch (IOException e) {
- Log.w(LOG_TAG, "Error closing streams: " + e);
+ private void verifyPermissionIntegrity(Context context) {
+ PackageManager pm = context.getPackageManager();
+ Intent queryIntent = new Intent(context, MbmsDownloadReceiver.class);
+ List<ResolveInfo> infos = pm.queryBroadcastReceivers(queryIntent, 0);
+ if (infos.size() != 1) {
+ throw new IllegalStateException("Non-unique download receiver in your app");
+ }
+ ActivityInfo selfInfo = infos.get(0).activityInfo;
+ if (selfInfo == null) {
+ throw new IllegalStateException("Queried ResolveInfo does not contain a receiver");
+ }
+ if (MbmsUtils.getOverrideServiceName(context,
+ MbmsDownloadSession.MBMS_DOWNLOAD_SERVICE_ACTION) != null) {
+ // If an override was specified, just make sure that the permission isn't null.
+ if (selfInfo.permission == null) {
+ throw new IllegalStateException(
+ "MbmsDownloadReceiver must require some permission");
}
+ return;
+ }
+ if (!Objects.equals(EMBMS_INTENT_PERMISSION, selfInfo.permission)) {
+ throw new IllegalStateException("MbmsDownloadReceiver must require the " +
+ "SEND_EMBMS_INTENTS permission.");
}
- return true;
}
}
diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java
index 75ca35e2342f..b5fec445d853 100644
--- a/telephony/java/android/telephony/mbms/MbmsErrors.java
+++ b/telephony/java/android/telephony/mbms/MbmsErrors.java
@@ -108,8 +108,8 @@ public class MbmsErrors {
/**
* Indicates that the app called
- * {@link MbmsStreamingSession#startStreaming(
- * StreamingServiceInfo, StreamingServiceCallback, android.os.Handler)}
+ * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo,
+ * java.util.concurrent.Executor, StreamingServiceCallback)}
* more than once for the same {@link StreamingServiceInfo}.
*/
public static final int ERROR_DUPLICATE_START_STREAM = 303;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
index 5c130a09773e..6e0395730aba 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
@@ -22,11 +22,12 @@ import android.os.Handler;
import android.telephony.MbmsStreamingSession;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* A callback class that is used to receive information from the middleware on MBMS streaming
* services. An instance of this object should be passed into
- * {@link MbmsStreamingSession#create(Context, MbmsStreamingSessionCallback, int, Handler)}.
+ * {@link MbmsStreamingSession#create(Context, Executor, int, MbmsStreamingSessionCallback)}.
*/
public class MbmsStreamingSessionCallback {
/**
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index b4ad1d77760a..ef317eefb3e3 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -50,7 +50,7 @@ public class MbmsUtils {
return new ComponentName(ci.packageName, ci.name);
}
- private static ComponentName getOverrideServiceName(Context context, String serviceAction) {
+ public static ComponentName getOverrideServiceName(Context context, String serviceAction) {
String metaDataKey = null;
switch (serviceAction) {
case MbmsDownloadSession.MBMS_DOWNLOAD_SERVICE_ACTION:
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index ec9134a4b855..b6239fe98a99 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -29,11 +29,11 @@ import java.lang.annotation.RetentionPolicy;
/**
* Class used to represent a single MBMS stream. After a stream has been started with
- * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo,
- * StreamingServiceCallback, android.os.Handler)},
+ * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo, java.util.concurrent.Executor,
+ * StreamingServiceCallback)},
* this class is used to hold information about the stream and control it.
*/
-public class StreamingService {
+public class StreamingService implements AutoCloseable {
private static final String LOG_TAG = "MbmsStreamingService";
/**
@@ -41,7 +41,7 @@ public class StreamingService {
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({STATE_STOPPED, STATE_STARTED, STATE_STALLED})
+ @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED})
public @interface StreamingState {}
public final static int STATE_STOPPED = 1;
public final static int STATE_STARTED = 2;
@@ -53,7 +53,8 @@ public class StreamingService {
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({REASON_BY_USER_REQUEST, REASON_END_OF_SESSION, REASON_FREQUENCY_CONFLICT,
+ @IntDef(prefix = { "REASON_" },
+ value = {REASON_BY_USER_REQUEST, REASON_END_OF_SESSION, REASON_FREQUENCY_CONFLICT,
REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE})
public @interface StreamingStateChangeReason {}
@@ -64,9 +65,9 @@ public class StreamingService {
public static final int REASON_NONE = 0;
/**
- * State changed due to a call to {@link #stopStreaming()} or
+ * State changed due to a call to {@link #close()} or
* {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo,
- * StreamingServiceCallback, android.os.Handler)}
+ * java.util.concurrent.Executor, StreamingServiceCallback)}
*/
public static final int REASON_BY_USER_REQUEST = 1;
@@ -161,7 +162,8 @@ public class StreamingService {
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*/
- public void stopStreaming() {
+ @Override
+ public void close() {
if (mService == null) {
throw new IllegalStateException("No streaming service attached");
}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index fe37531c0611..a4eb424ab66e 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -187,6 +187,57 @@ interface ISms {
in PendingIntent deliveryIntent, in boolean persistMessage);
/**
+ * Send an SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destAddr the address to send the message to
+ * @param scAddr the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param persistMessageForNonDefaultSmsApp whether the sent message should
+ * be automatically persisted in the SMS db. It only affects messages sent
+ * by a non-default SMS app. Currently only the carrier app can set this
+ * parameter to false to skip auto message persistence.
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendTextForSubscriberWithOptions(in int subId, String callingPkg, in String destAddr,
+ in String scAddr, in String text, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent, in boolean persistMessageForNonDefaultSmsApp,
+ in int priority, in boolean expectMore, in int validityPeriod);
+
+ /**
* Inject an SMS PDU into the android platform.
*
* @param subId the subId on which the SMS has to be injected.
@@ -234,6 +285,56 @@ interface ISms {
in List<PendingIntent> deliveryIntents, in boolean persistMessageForNonDefaultSmsApp);
/**
+ * Send a multi-part text based SMS with options using Subscription Id.
+ *
+ * @param subId the subId on which the SMS has to be sent.
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param persistMessageForNonDefaultSmsApp whether the sent message should
+ * be automatically persisted in the SMS db. It only affects messages sent
+ * by a non-default SMS app. Currently only the carrier app can set this
+ * parameter to false to skip auto message persistence.
+ * @param priority Priority level of the message
+ * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+ * ---------------------------------
+ * PRIORITY | Level of Priority
+ * ---------------------------------
+ * '00' | Normal
+ * '01' | Interactive
+ * '10' | Urgent
+ * '11' | Emergency
+ * ----------------------------------
+ * Any Other values included Negative considered as Invalid Priority Indicator of the message.
+ * @param expectMore is a boolean to indicate the sending message is multi segmented or not.
+ * @param validityPeriod Validity Period of the message in mins.
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * Validity Period(Minimum) -> 5 mins
+ * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+ * Any Other values included Negative considered as Invalid Validity Period of the message.
+ */
+ void sendMultipartTextForSubscriberWithOptions(in int subId, String callingPkg,
+ in String destinationAddress, in String scAddress, in List<String> parts,
+ in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents,
+ in boolean persistMessageForNonDefaultSmsApp, in int priority, in boolean expectMore,
+ in int validityPeriod);
+
+ /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier and RAN type. The RAN type specify this message ID
* belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2b4c059cf69f..d96f9260053f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -823,6 +823,12 @@ interface ITelephony {
IImsConfig getImsConfig(int slotId, int feature);
/**
+ * Returns true if emergency calling is available for the MMTEL feature associated with the
+ * slot specified.
+ */
+ boolean isEmergencyMmTelAvailable(int slotId);
+
+ /**
* Set the network selection mode to automatic.
*
* @param subId the id of the subscription to update.
@@ -952,6 +958,11 @@ interface ITelephony {
int getCarrierPrivilegeStatus(int subId);
/**
+ * Similar to above, but check for the given uid.
+ */
+ int getCarrierPrivilegeStatusForUid(int subId, int uid);
+
+ /**
* Similar to above, but check for the package whose name is pkgName.
*/
int checkCarrierPrivilegesForPackage(String pkgName);
@@ -1123,33 +1134,33 @@ interface ITelephony {
boolean isHearingAidCompatibilitySupported();
/**
- * Get IMS Registration Status
- */
- boolean isImsRegistered();
-
- /**
* Get IMS Registration Status on a particular subid.
*
* @param subId user preferred subId.
*
* @return {@code true} if the IMS status is registered.
*/
- boolean isImsRegisteredForSubscriber(int subId);
+ boolean isImsRegistered(int subId);
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the Status of Wi-Fi Calling for the subscription id specified.
*/
- boolean isWifiCallingAvailable();
+ boolean isWifiCallingAvailable(int subId);
/**
- * Returns the Status of Volte
+ * Returns the Status of VoLTE for the subscription ID specified.
*/
- boolean isVolteAvailable();
+ boolean isVolteAvailable(int subId);
/**
- * Returns the Status of VT (video telephony)
+ * Returns the Status of VT (video telephony) for the subscription ID specified.
*/
- boolean isVideoTelephonyAvailable();
+ boolean isVideoTelephonyAvailable(int subId);
+
+ /**
+ * Returns the MMTEL IMS registration technology for the subsciption ID specified.
+ */
+ int getImsRegTechnologyForMmTel(int subId);
/**
* Returns the unique device ID of phone, for example, the IMEI for
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
new file mode 100644
index 000000000000..da8471fa19ed
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -0,0 +1,209 @@
+/*
+ * 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.internal.telephony;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ITelephony;
+
+/** Utility class for Telephony permission enforcement. */
+public final class TelephonyPermissions {
+ private static final String LOG_TAG = "TelephonyPermissions";
+
+ private static final boolean DBG = false;
+
+ private TelephonyPermissions() {}
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) can read phone state.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
+ * READ_PHONE_STATE runtime permission.
+ * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
+ * apps which support runtime permissions, if the caller does not currently have any of
+ * these permissions.
+ * <li>return false: if the caller lacks all of these permissions and doesn't support runtime
+ * permissions. This implies that the user revoked the ability to read phone state
+ * manually (via AppOps). In this case we can't throw as it would break app compatibility,
+ * so we return false to indicate that the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadPhoneState(
+ Context context, String callingPackage, String message) {
+ return checkReadPhoneState(context, Binder.getCallingPid(), Binder.getCallingUid(),
+ callingPackage, message);
+ }
+
+ /**
+ * Check whether the app with the given pid/uid can read phone state.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has either the READ_PRIVILEGED_PHONE_STATE permission or the
+ * READ_PHONE_STATE runtime permission.
+ * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
+ * apps which support runtime permissions, if the caller does not currently have any of
+ * these permissions.
+ * <li>return false: if the caller lacks all of these permissions and doesn't support runtime
+ * permissions. This implies that the user revoked the ability to read phone state
+ * manually (via AppOps). In this case we can't throw as it would break app compatibility,
+ * so we return false to indicate that the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkReadPhoneState(
+ Context context, int pid, int uid, String callingPackage, String message) {
+ try {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+
+ // SKIP checking for run-time permission since caller has PRIVILEGED permission
+ return true;
+ } catch (SecurityException privilegedPhoneStateException) {
+ context.enforcePermission(
+ android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+ }
+
+ // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
+ // revoked.
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, uid, callingPackage) ==
+ AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
+ * Returns whether the caller can read phone numbers.
+ *
+ * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
+ * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
+ */
+ public static boolean checkCallingOrSelfReadPhoneNumber(
+ Context context, String callingPackage, String message) {
+ return checkReadPhoneNumber(
+ context, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+ }
+
+ @VisibleForTesting
+ public static boolean checkReadPhoneNumber(
+ Context context, int pid, int uid, String callingPackage, String message) {
+ // Default SMS app can always read it.
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ if (appOps.noteOp(AppOpsManager.OP_WRITE_SMS, uid, callingPackage) ==
+ AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+
+ // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
+ // will be denied access, even if they have another permission and AppOps bit if needed.
+
+ // First, check if we can read the phone state.
+ try {
+ return checkReadPhoneState(context, pid, uid, callingPackage, message);
+ } catch (SecurityException readPhoneStateSecurityException) {
+ }
+ // Can be read with READ_SMS too.
+ try {
+ context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
+ int opCode = AppOpsManager.permissionToOpCode(android.Manifest.permission.READ_SMS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readSmsSecurityException) {
+ }
+ // Can be read with READ_PHONE_NUMBERS too.
+ try {
+ context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid,
+ message);
+ int opCode = AppOpsManager.permissionToOpCode(
+ android.Manifest.permission.READ_PHONE_NUMBERS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return appOps.noteOp(opCode, uid, callingPackage) == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readPhoneNumberSecurityException) {
+ }
+
+ throw new SecurityException(message + ": Neither user " + uid +
+ " nor current process has " + android.Manifest.permission.READ_PHONE_STATE +
+ ", " + android.Manifest.permission.READ_SMS + ", or " +
+ android.Manifest.permission.READ_PHONE_NUMBERS);
+ }
+
+ /**
+ * Ensure the caller (or self, if not processing an IPC) has MODIFY_PHONE_STATE (and is thus a
+ * privileged app) or carrier privileges.
+ *
+ * @throws SecurityException if the caller does not have the required permission/privileges
+ */
+ public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ Context context, int subId, String message) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) ==
+ PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
+ enforceCallingOrSelfCarrierPrivilege(subId, message);
+ }
+
+ /**
+ * Make sure the caller (or self, if not processing an IPC) has carrier privileges.
+ *
+ * @throws SecurityException if the caller does not have the required privileges
+ */
+ public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
+ // NOTE: It's critical that we explicitly pass the calling UID here rather than call
+ // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
+ // the phone process. When called from another process, it will check whether that process
+ // has carrier privileges instead.
+ enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
+ }
+
+ private static void enforceCarrierPrivilege(int subId, int uid, String message) {
+ if (getCarrierPrivilegeStatus(subId, uid) !=
+ TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
+ throw new SecurityException(message);
+ }
+ }
+
+ private static int getCarrierPrivilegeStatus(int subId, int uid) {
+ ITelephony telephony =
+ ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ try {
+ if (telephony != null) {
+ return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
+ }
+ } catch (RemoteException e) {
+ // Fallback below.
+ }
+ Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 7a53ef63e2a8..14c5f4bebebb 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -99,6 +99,15 @@ public class SmsMessage extends SmsMessageBase {
private static final int RETURN_NO_ACK = 0;
private static final int RETURN_ACK = 1;
+ /**
+ * Supported priority modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
+ */
+ private static final int PRIORITY_NORMAL = 0x0;
+ private static final int PRIORITY_INTERACTIVE = 0x1;
+ private static final int PRIORITY_URGENT = 0x2;
+ private static final int PRIORITY_EMERGENCY = 0x3;
+
private SmsEnvelope mEnvelope;
private BearerData mBearerData;
@@ -211,6 +220,26 @@ public class SmsMessage extends SmsMessageBase {
*/
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
boolean statusReportRequested, SmsHeader smsHeader) {
+ return getSubmitPdu(scAddr, destAddr, message, statusReportRequested, smsHeader, -1);
+ }
+
+ /**
+ * Get an SMS-SUBMIT PDU for a destination address and a message
+ *
+ * @param scAddr Service Centre address. Null means use default.
+ * @param destAddr Address of the recipient.
+ * @param message String representation of the message payload.
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @param smsHeader Array containing the data for the User Data Header, preceded
+ * by the Element Identifiers.
+ * @param priority Priority level of the message
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
+ boolean statusReportRequested, SmsHeader smsHeader, int priority) {
/**
* TODO(cleanup): Do we really want silent failure like this?
@@ -224,7 +253,7 @@ public class SmsMessage extends SmsMessageBase {
UserData uData = new UserData();
uData.payloadStr = message;
uData.userDataHeader = smsHeader;
- return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
+ return privateGetSubmitPdu(destAddr, statusReportRequested, uData, priority);
}
/**
@@ -282,6 +311,22 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
+ *
+ * @param destAddr the address of the destination for the message
+ * @param userData the data for the message
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @param priority Priority level of the message
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
+ boolean statusReportRequested, int priority) {
+ return privateGetSubmitPdu(destAddr, statusReportRequested, userData, priority);
+ }
+
+ /**
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
*/
@Override
@@ -764,6 +809,15 @@ public class SmsMessage extends SmsMessageBase {
*/
private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
UserData userData) {
+ return privateGetSubmitPdu(destAddrStr, statusReportRequested, userData, -1);
+ }
+
+ /**
+ * Creates BearerData and Envelope from parameters for a Submit SMS.
+ * @return byte stream for SubmitPdu.
+ */
+ private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
+ UserData userData, int priority) {
/**
* TODO(cleanup): give this function a more meaningful name.
@@ -792,6 +846,10 @@ public class SmsMessage extends SmsMessageBase {
bearerData.userAckReq = false;
bearerData.readAckReq = false;
bearerData.reportReq = false;
+ if (priority >= PRIORITY_NORMAL && priority <= PRIORITY_EMERGENCY) {
+ bearerData.priorityIndicatorSet = true;
+ bearerData.priority = priority;
+ }
bearerData.userData = userData;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 1ca19e01d6c8..4f5bfa919135 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -89,6 +89,18 @@ public class SmsMessage extends SmsMessageBase {
private int mVoiceMailCount = 0;
+ private static final int VALIDITY_PERIOD_FORMAT_NONE = 0x00;
+ private static final int VALIDITY_PERIOD_FORMAT_ENHANCED = 0x01;
+ private static final int VALIDITY_PERIOD_FORMAT_RELATIVE = 0x02;
+ private static final int VALIDITY_PERIOD_FORMAT_ABSOLUTE = 0x03;
+
+ //Validity Period min - 5 mins
+ private static final int VALIDITY_PERIOD_MIN = 5;
+ //Validity Period max - 63 weeks
+ private static final int VALIDITY_PERIOD_MAX = 635040;
+
+ private static final int INVALID_VALIDITY_PERIOD = -1;
+
public static class SubmitPdu extends SubmitPduBase {
}
@@ -202,6 +214,45 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Get Encoded Relative Validty Period Value from Validity period in mins.
+ *
+ * @param validityPeriod Validity period in mins.
+ *
+ * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+ * ||relValidityPeriod (TP-VP) || || validityPeriod ||
+ *
+ * 0 to 143 ---> (TP-VP + 1) x 5 minutes
+ *
+ * 144 to 167 ---> 12 hours + ((TP-VP -143) x 30 minutes)
+ *
+ * 168 to 196 ---> (TP-VP - 166) x 1 day
+ *
+ * 197 to 255 ---> (TP-VP - 192) x 1 week
+ *
+ * @return relValidityPeriod Encoded Relative Validity Period Value.
+ * @hide
+ */
+ public static int getRelativeValidityPeriod(int validityPeriod) {
+ int relValidityPeriod = INVALID_VALIDITY_PERIOD;
+
+ if (validityPeriod < VALIDITY_PERIOD_MIN || validityPeriod > VALIDITY_PERIOD_MAX) {
+ Rlog.e(LOG_TAG,"Invalid Validity Period" + validityPeriod);
+ return relValidityPeriod;
+ }
+
+ if (validityPeriod <= 720) {
+ relValidityPeriod = (validityPeriod / 5) - 1;
+ } else if (validityPeriod <= 1440) {
+ relValidityPeriod = ((validityPeriod - 720) / 30) + 143;
+ } else if (validityPeriod <= 43200) {
+ relValidityPeriod = (validityPeriod / 1440) + 166;
+ } else if (validityPeriod <= 635040) {
+ relValidityPeriod = (validityPeriod / 10080) + 192;
+ }
+ return relValidityPeriod;
+ }
+
+ /**
* Get an SMS-SUBMIT PDU for a destination address and a message
*
* @param scAddress Service Centre address. Null means use default.
@@ -236,6 +287,29 @@ public class SmsMessage extends SmsMessageBase {
String destinationAddress, String message,
boolean statusReportRequested, byte[] header, int encoding,
int languageTable, int languageShiftTable) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+ header, encoding, languageTable, languageShiftTable, -1);
+ }
+
+ /**
+ * Get an SMS-SUBMIT PDU for a destination address and a message using the
+ * specified encoding.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param encoding Encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param languageTable
+ * @param languageShiftTable
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, byte[] header, int encoding,
+ int languageTable, int languageShiftTable, int validityPeriod) {
// Perform null parameter checks.
if (message == null || destinationAddress == null) {
@@ -272,8 +346,19 @@ public class SmsMessage extends SmsMessageBase {
}
SubmitPdu ret = new SubmitPdu();
- // MTI = SMS-SUBMIT, UDHI = header != null
- byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
+
+ int validityPeriodFormat = VALIDITY_PERIOD_FORMAT_NONE;
+ int relativeValidityPeriod = INVALID_VALIDITY_PERIOD;
+
+ // TP-Validity-Period-Format (TP-VPF) in 3GPP TS 23.040 V6.8.1 section 9.2.3.3
+ //bit 4:3 = 10 - TP-VP field present - relative format
+ if((relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod)) >= 0) {
+ validityPeriodFormat = VALIDITY_PERIOD_FORMAT_RELATIVE;
+ }
+
+ byte mtiByte = (byte)(0x01 | (validityPeriodFormat << 0x03) |
+ (header != null ? 0x40 : 0x00));
+
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
statusReportRequested, ret);
@@ -338,7 +423,11 @@ public class SmsMessage extends SmsMessageBase {
bo.write(0x08);
}
- // (no TP-Validity-Period)
+ if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) {
+ // ( TP-Validity-Period - relative format)
+ bo.write(relativeValidityPeriod);
+ }
+
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
return ret;
@@ -388,6 +477,24 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Get an SMS-SUBMIT PDU for a destination address and a message
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message
+ * @param statusReportRequested staus report of the message Requested
+ * @param validityPeriod Validity Period of the message in Minutes.
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested, int validityPeriod) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+ null, ENCODING_UNKNOWN, 0, 0, validityPeriod);
+ }
+
+ /**
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
*
* @param scAddress Service Centre address. null == use default
diff --git a/test-base/Android.bp b/test-base/Android.bp
index b65cda9302a7..4d149f7c8919 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -24,15 +24,15 @@ java_library {
srcs: ["src/**/*.java"],
+ errorprone: {
+ javacflags: ["-Xep:DepAnn:ERROR"],
+ },
+
// Needs to be consistent with the repackaged version of this make target.
java_version: "1.8",
- no_framework_libs: true,
+ sdk_version: "current",
hostdex: true,
- libs: [
- "framework",
- ],
-
}
// Build the legacy-test library
@@ -42,12 +42,9 @@ java_library {
// Also contains the com.android.internal.util.Predicate[s] classes.
java_library {
name: "legacy-test",
- static_libs: ["android.test.base"],
- no_framework_libs: true,
- libs: [
- "framework",
- ],
+ sdk_version: "current",
+ static_libs: ["android.test.base"],
}
// Build the repackaged.android.test.base library
@@ -57,11 +54,8 @@ java_library {
java_library_static {
name: "repackaged.android.test.base",
+ sdk_version: "current",
static_libs: ["android.test.base"],
- no_framework_libs: true,
- libs: [
- "framework",
- ],
jarjar_rules: "jarjar-rules.txt",
// Pin java_version until jarjar is certified to support later versions. http://b/72703434
diff --git a/test-base/Android.mk b/test-base/Android.mk
index 861385467a0f..ebb33deb42d3 100644
--- a/test-base/Android.mk
+++ b/test-base/Android.mk
@@ -26,10 +26,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := \
- core-oj \
- core-libart \
- framework \
+LOCAL_SDK_VERSION := current
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
diff --git a/test-base/src/android/test/PerformanceTestCase.java b/test-base/src/android/test/PerformanceTestCase.java
index 65bd4a48f7f5..2584da20e9be 100644
--- a/test-base/src/android/test/PerformanceTestCase.java
+++ b/test-base/src/android/test/PerformanceTestCase.java
@@ -21,6 +21,11 @@ package android.test;
*
* If you want your test to be used as a performance test, you must
* implement this interface.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
@Deprecated
public interface PerformanceTestCase
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index b8c53266b9f8..da47de0a3d35 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -21,16 +21,38 @@ ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
# Build the android.test.legacy library
# =====================================
+# Built against the SDK so that it can be statically included in APKs
+# without breaking link type checks.
+#
+# This builds directly from the source rather than simply statically
+# including the android.test.base-minus-junit and
+# android.test.runner-minus-junit libraries because the latter library
+# cannot itself be built against the SDK. That is because it uses on
+# an internal method (setTestContext) on the AndroidTestCase class.
+# That class is provided by both the android.test.base-minus-junit and
+# the current SDK and as the latter is first on the classpath its
+# version is used. Unfortunately, it does not provide the internal
+# method and so compilation fails.
+#
+# Building from source avoids that because the compiler will use the
+# source version of AndroidTestCase instead of the one from the current
+# SDK.
+#
+# The use of the internal method does not prevent this from being
+# statically included because the class that provides the method is
+# also included in this library.
include $(CLEAR_VARS)
LOCAL_MODULE := android.test.legacy
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, ../test-base/src/android) \
+ $(call all-java-files-under, ../test-base/src/com) \
+ $(call all-java-files-under, ../test-runner/src/android) \
+
LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES := junit
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android.test.base-minus-junit \
- android.test.runner-minus-junit \
+LOCAL_JAVA_LIBRARIES := junit android.test.mock.stubs
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
index d81ca013ec7a..15fa12d1298e 100644
--- a/test-mock/Android.mk
+++ b/test-mock/Android.mk
@@ -16,14 +16,19 @@
LOCAL_PATH:= $(call my-dir)
-android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
+# Includes the main framework source to ensure that doclava has access to the
+# visibility information for the base classes of the mock classes. Without it
+# otherwise hidden methods could be visible.
+android_test_mock_source_files := \
+ $(call all-java-files-under, src/android/test/mock) \
+ $(call all-java-files-under, ../core/java/android)
# Generate the stub source files for android.test.mock.stubs
# ==========================================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(android_test_mock_source_files)
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework conscrypt okhttp bouncycastle
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
@@ -34,6 +39,7 @@ ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
LOCAL_DROIDDOC_OPTIONS:= \
+ -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
-stubpackages android.test.mock \
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
-nodocs \
@@ -62,6 +68,9 @@ LOCAL_SOURCE_FILES_ALL_GENERATED := true
# Make sure to run droiddoc first to generate the stub source files.
LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
+android_test_mock_gen_stamp :=
+
+LOCAL_SDK_VERSION := current
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/test-mock/api/android-test-mock-current.txt b/test-mock/api/android-test-mock-current.txt
index 10286c297152..07acfef7ce6c 100644
--- a/test-mock/api/android-test-mock-current.txt
+++ b/test-mock/api/android-test-mock-current.txt
@@ -15,7 +15,6 @@ package android.test.mock {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>);
method public static deprecated void attachInfoForTesting(android.content.ContentProvider, android.content.Context, android.content.pm.ProviderInfo);
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
- method public final android.content.IContentProvider getIContentProvider();
method public java.lang.String getType(android.net.Uri);
method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public boolean onCreate();
@@ -27,37 +26,26 @@ package android.test.mock {
public class MockContentResolver extends android.content.ContentResolver {
ctor public MockContentResolver();
ctor public MockContentResolver(android.content.Context);
- method protected android.content.IContentProvider acquireProvider(android.content.Context, java.lang.String);
- method protected android.content.IContentProvider acquireUnstableProvider(android.content.Context, java.lang.String);
method public void addProvider(java.lang.String, android.content.ContentProvider);
- method public boolean releaseProvider(android.content.IContentProvider);
- method public boolean releaseUnstableProvider(android.content.IContentProvider);
- method public void unstableProviderDied(android.content.IContentProvider);
}
public class MockContext extends android.content.Context {
ctor public MockContext();
method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
- method public boolean canLoadUnsafeResources();
method public int checkCallingOrSelfPermission(java.lang.String);
method public int checkCallingOrSelfUriPermission(android.net.Uri, int);
method public int checkCallingPermission(java.lang.String);
method public int checkCallingUriPermission(android.net.Uri, int);
method public int checkPermission(java.lang.String, int, int);
- method public int checkPermission(java.lang.String, int, int, android.os.IBinder);
method public int checkSelfPermission(java.lang.String);
method public int checkUriPermission(android.net.Uri, int, int, int);
- method public int checkUriPermission(android.net.Uri, int, int, int, android.os.IBinder);
method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public void clearWallpaper();
- method public android.content.Context createApplicationContext(android.content.pm.ApplicationInfo, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Context createConfigurationContext(android.content.res.Configuration);
method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.Context createCredentialProtectedStorageContext();
method public android.content.Context createDeviceProtectedStorageContext();
method public android.content.Context createDisplayContext(android.view.Display);
method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.String[] databaseList();
method public boolean deleteDatabase(java.lang.String);
method public boolean deleteFile(java.lang.String);
@@ -73,7 +61,6 @@ package android.test.mock {
method public android.content.Context getApplicationContext();
method public android.content.pm.ApplicationInfo getApplicationInfo();
method public android.content.res.AssetManager getAssets();
- method public java.lang.String getBasePackageName();
method public java.io.File getCacheDir();
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
@@ -81,8 +68,6 @@ package android.test.mock {
method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
- method public android.view.Display getDisplay();
- method public android.view.DisplayAdjustments getDisplayAdjustments(int);
method public java.io.File getExternalCacheDir();
method public java.io.File[] getExternalCacheDirs();
method public java.io.File getExternalFilesDir(java.lang.String);
@@ -94,25 +79,19 @@ package android.test.mock {
method public java.io.File getNoBackupFilesDir();
method public java.io.File getObbDir();
method public java.io.File[] getObbDirs();
- method public java.lang.String getOpPackageName();
method public java.lang.String getPackageCodePath();
method public android.content.pm.PackageManager getPackageManager();
method public java.lang.String getPackageName();
method public java.lang.String getPackageResourcePath();
- method public java.io.File getPreloadsFileCache();
method public android.content.res.Resources getResources();
method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public java.io.File getSharedPreferencesPath(java.lang.String);
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
- method public int getUserId();
method public android.graphics.drawable.Drawable getWallpaper();
method public int getWallpaperDesiredMinimumHeight();
method public int getWallpaperDesiredMinimumWidth();
method public void grantUriPermission(java.lang.String, android.net.Uri, int);
- method public boolean isCredentialProtectedStorage();
method public boolean isDeviceProtectedStorage();
method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
@@ -125,31 +104,19 @@ package android.test.mock {
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
- method public android.content.Intent registerReceiverAsUser(android.content.BroadcastReceiver, android.os.UserHandle, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public void reloadSharedPreferences();
method public void removeStickyBroadcast(android.content.Intent);
method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
method public void revokeUriPermission(java.lang.String, android.net.Uri, int);
method public void sendBroadcast(android.content.Intent);
method public void sendBroadcast(android.content.Intent, java.lang.String);
- method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
- method public void sendBroadcast(android.content.Intent, java.lang.String, int);
method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
- method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
- method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int);
- method public void sendBroadcastMultiplePermissions(android.content.Intent, java.lang.String[]);
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
- method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void sendStickyBroadcast(android.content.Intent);
method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
- method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.os.Bundle);
method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
method public void setTheme(int);
@@ -160,17 +127,13 @@ package android.test.mock {
method public void startActivity(android.content.Intent);
method public void startActivity(android.content.Intent, android.os.Bundle);
method public android.content.ComponentName startForegroundService(android.content.Intent);
- method public android.content.ComponentName startForegroundServiceAsUser(android.content.Intent, android.os.UserHandle);
method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public android.content.ComponentName startService(android.content.Intent);
- method public android.content.ComponentName startServiceAsUser(android.content.Intent, android.os.UserHandle);
method public boolean stopService(android.content.Intent);
- method public boolean stopServiceAsUser(android.content.Intent, android.os.UserHandle);
method public void unbindService(android.content.ServiceConnection);
method public void unregisterReceiver(android.content.BroadcastReceiver);
- method public void updateDisplay(int);
}
public deprecated class MockCursor implements android.database.Cursor {
@@ -226,8 +189,6 @@ package android.test.mock {
public deprecated class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
- method public void addCrossProfileIntentFilter(android.content.IntentFilter, int, int, int);
- method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void addPackageToPreferred(java.lang.String);
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
@@ -237,19 +198,10 @@ package android.test.mock {
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
method public int checkSignatures(int, int);
- method public void clearApplicationUserData(java.lang.String, android.content.pm.IPackageDataObserver);
- method public void clearCrossProfileIntentFilters(int);
method public void clearInstantAppCookie();
method public void clearPackagePreferredActivities(java.lang.String);
method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
- method public void deleteApplicationCacheFiles(java.lang.String, android.content.pm.IPackageDataObserver);
- method public void deleteApplicationCacheFilesAsUser(java.lang.String, int, android.content.pm.IPackageDataObserver);
- method public void deletePackage(java.lang.String, android.content.pm.IPackageDeleteObserver, int);
- method public void deletePackageAsUser(java.lang.String, android.content.pm.IPackageDeleteObserver, int, int);
method public void extendVerificationTimeout(int, int, long);
- method public void flushPackageRestrictionsAsUser(int);
- method public void freeStorage(java.lang.String, long, android.content.IntentSender);
- method public void freeStorageAndNotify(java.lang.String, long, android.content.pm.IPackageDataObserver);
method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -262,149 +214,75 @@ package android.test.mock {
method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getApplicationEnabledSetting(java.lang.String);
- method public boolean getApplicationHiddenSettingAsUser(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.pm.ApplicationInfo getApplicationInfoAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
method public android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.ChangedPackages getChangedPackages(int);
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
- method public android.content.ComponentName getHomeActivities(java.util.List<android.content.pm.ResolveInfo>);
- method public int getInstallReason(java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
- method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
- method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public java.lang.String getInstallerPackageName(java.lang.String);
- method public java.lang.String getInstantAppAndroidId(java.lang.String, android.os.UserHandle);
method public byte[] getInstantAppCookie();
method public int getInstantAppCookieMaxBytes();
- method public int getInstantAppCookieMaxSize();
- method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
- method public android.content.ComponentName getInstantAppInstallerComponent();
- method public android.content.ComponentName getInstantAppResolverSettingsComponent();
- method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
- method public int getIntentVerificationStatusAsUser(java.lang.String, int);
- method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
- method public int getMoveStatus(int);
method public java.lang.String getNameForUid(int);
- method public java.lang.String[] getNamesForUids(int[]);
- method public java.util.List<android.os.storage.VolumeInfo> getPackageCandidateVolumes(android.content.pm.ApplicationInfo);
- method public android.os.storage.VolumeInfo getPackageCurrentVolume(android.content.pm.ApplicationInfo);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.pm.PackageInfo getPackageInfoAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInstaller getPackageInstaller();
- method public void getPackageSizeInfoAsUser(java.lang.String, int, android.content.pm.IPackageStatsObserver);
method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public int getPackageUidAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public int getPackageUidAsUser(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.String[] getPackagesForUid(int);
method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
- method public java.lang.String getPermissionControllerPackageName();
- method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
method public java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
- method public java.util.List<android.os.storage.VolumeInfo> getPrimaryStorageCandidateVolumes();
- method public android.os.storage.VolumeInfo getPrimaryStorageCurrentVolume();
method public android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public android.content.res.Resources getResourcesForApplicationAsUser(java.lang.String, int);
method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public java.lang.String getServicesSystemSharedLibraryPackageName();
method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
- method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibrariesAsUser(int, int);
- method public java.lang.String getSharedSystemSharedLibraryPackageName();
- method public android.content.pm.KeySet getSigningKeySet(java.lang.String);
method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
method public java.lang.String[] getSystemSharedLibraryNames();
method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
- method public int getUidForSharedUser(java.lang.String);
- method public android.graphics.drawable.Drawable getUserBadgeForDensity(android.os.UserHandle, int);
- method public android.graphics.drawable.Drawable getUserBadgeForDensityNoBackground(android.os.UserHandle, int);
method public android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
method public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
- method public android.content.pm.VerifierDeviceIdentity getVerifierDeviceIdentity();
method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
- method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
- method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public int installExistingPackageAsUser(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public void installPackage(android.net.Uri, android.content.pm.IPackageInstallObserver, int, java.lang.String);
- method public void installPackage(android.net.Uri, android.app.PackageInstallObserver, int, java.lang.String);
method public boolean isInstantApp();
method public boolean isInstantApp(java.lang.String);
- method public boolean isPackageAvailable(java.lang.String);
- method public boolean isPackageSuspendedForUser(java.lang.String, int);
- method public boolean isPermissionReviewModeEnabled();
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
method public boolean isSafeMode();
- method public boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
- method public boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
- method public boolean isUpgrade();
- method public android.graphics.drawable.Drawable loadItemIcon(android.content.pm.PackageItemInfo, android.content.pm.ApplicationInfo);
- method public android.graphics.drawable.Drawable loadUnbadgedItemIcon(android.content.pm.PackageItemInfo, android.content.pm.ApplicationInfo);
- method public int movePackage(java.lang.String, android.os.storage.VolumeInfo);
- method public int movePrimaryStorage(android.os.storage.VolumeInfo);
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
- method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, int);
method public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
- method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(android.content.Intent, int, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
- method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(android.content.Intent, int, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
- method public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(android.content.Intent, int, int);
method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method public void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
- method public void registerMoveCallback(android.content.pm.PackageManager.MoveCallback, android.os.Handler);
- method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void removePackageFromPreferred(java.lang.String);
method public void removePermission(java.lang.String);
- method public void replacePreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
- method public android.content.pm.ResolveInfo resolveActivityAsUser(android.content.Intent, int, int);
method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
- method public android.content.pm.ProviderInfo resolveContentProviderAsUser(java.lang.String, int, int);
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
- method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setApplicationCategoryHint(java.lang.String, int);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
- method public boolean setApplicationHiddenSettingAsUser(java.lang.String, boolean, android.os.UserHandle);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
- method public boolean setInstantAppCookie(byte[]);
- method public java.lang.String[] setPackagesSuspendedAsUser(java.lang.String[], boolean, int);
- method public void setUpdateAvailable(java.lang.String, boolean);
- method public boolean shouldShowRequestPermissionRationale(java.lang.String);
- method public void unregisterMoveCallback(android.content.pm.PackageManager.MoveCallback);
method public void updateInstantAppCookie(byte[]);
- method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
- method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
- method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
method public void verifyPendingInstall(int, int);
}
diff --git a/test-mock/api/android-test-mock-removed.txt b/test-mock/api/android-test-mock-removed.txt
index 5b358cfdbf59..bd109a887933 100644
--- a/test-mock/api/android-test-mock-removed.txt
+++ b/test-mock/api/android-test-mock-removed.txt
@@ -8,6 +8,7 @@ package android.test.mock {
public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public deprecated java.lang.String getDefaultBrowserPackageName(int);
method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ method public boolean setInstantAppCookie(byte[]);
}
}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 66b95271ee06..a2edb047d9de 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -23,6 +23,10 @@ java_library {
java_version: "1.8",
srcs: ["src/**/*.java"],
+ errorprone: {
+ javacflags: ["-Xep:DepAnn:ERROR"],
+ },
+
no_framework_libs: true,
libs: [
"framework",
@@ -33,8 +37,8 @@ java_library {
// Build the android.test.runner-minus-junit library
// =================================================
-// This is only intended for inclusion in the android.test.legacy and
-// legacy-android-test static libraries and must not be used elsewhere.
+// This is only intended for inclusion in the legacy-android-test static
+// library and must not be used elsewhere.
java_library {
name: "android.test.runner-minus-junit",
diff --git a/test-runner/src/android/test/ComparisonFailure.java b/test-runner/src/android/test/ComparisonFailure.java
index 3fa76f5b166c..d86b7007a733 100644
--- a/test-runner/src/android/test/ComparisonFailure.java
+++ b/test-runner/src/android/test/ComparisonFailure.java
@@ -19,8 +19,9 @@ package android.test;
/**
* Thrown when an assert equals for Strings failed.
*
- * @deprecated use junit.framework.ComparisonFailure
+ * @deprecated use org.junit.ComparisonFailure
*/
+@Deprecated
public class ComparisonFailure extends AssertionFailedError {
private junit.framework.ComparisonFailure mComparison;
diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java
index c74651cea01f..12cfcb76e10b 100644
--- a/test-runner/src/android/test/TestSuiteProvider.java
+++ b/test-runner/src/android/test/TestSuiteProvider.java
@@ -20,6 +20,11 @@ import junit.framework.TestSuite;
/**
* Implementors will know how to get a test suite.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
@Deprecated
public interface TestSuiteProvider {
diff --git a/test-runner/src/junit/runner/BaseTestRunner.java b/test-runner/src/junit/runner/BaseTestRunner.java
index e7e043133c95..b2fa16c91da2 100644
--- a/test-runner/src/junit/runner/BaseTestRunner.java
+++ b/test-runner/src/junit/runner/BaseTestRunner.java
@@ -207,6 +207,7 @@ public abstract class BaseTestRunner implements TestListener {
*
* @deprecated not present in JUnit4.10
*/
+ @Deprecated
public TestSuiteLoader getLoader() {
return new StandardTestSuiteLoader();
}
@@ -279,6 +280,7 @@ public abstract class BaseTestRunner implements TestListener {
// BEGIN android-changed - add back this method for API compatibility
/** @deprecated not present in JUnit4.10 */
+ @Deprecated
public static boolean inVAJava() {
return false;
}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
index 388f91a2c3fb..261ea2ec866d 100644
--- a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
@@ -66,9 +66,6 @@ public class SurfaceCompositionTest extends
super(SurfaceCompositionMeasuringActivity.class);
}
- private void testRestoreContexts() {
- }
-
@SmallTest
public void testSurfaceCompositionPerformance() {
Bundle status = new Bundle();
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
index b4342df58549..ffd1f063e48b 100644
--- a/tests/net/java/android/net/IpSecTransformTest.java
+++ b/tests/net/java/android/net/IpSecTransformTest.java
@@ -17,6 +17,7 @@
package android.net;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.support.test.filters.SmallTest;
@@ -56,6 +57,6 @@ public class IpSecTransformTest {
IpSecTransform config1 = new IpSecTransform(null, config);
IpSecTransform config2 = new IpSecTransform(null, config);
- assertFalse(IpSecTransform.equals(config1, config2));
+ assertTrue(IpSecTransform.equals(config1, config2));
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 24639e9e3f76..28f81220027c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -50,6 +50,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
+import static com.android.internal.util.TestUtils.waitForIdleLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -85,6 +86,7 @@ import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
+import android.net.ConnectivityThread;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.IpPrefix;
@@ -279,6 +281,7 @@ public class ConnectivityServiceTest {
waitForIdle(mWiFiNetworkAgent, timeoutMs);
waitForIdle(mEthernetNetworkAgent, timeoutMs);
waitForIdleHandler(mService.mHandlerThread, timeoutMs);
+ waitForIdleLooper(ConnectivityThread.getInstanceLooper(), timeoutMs);
}
public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
@@ -1438,9 +1441,9 @@ public class ConnectivityServiceTest {
expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
}
if (expectValidated) {
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+ expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
} else {
- expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent);
+ expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
}
expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
}
@@ -1479,14 +1482,24 @@ public class ConnectivityServiceTest {
}
NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ return expectCapabilitiesWith(capability, agent, TIMEOUT_MS);
+ }
+
+ NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
+ int timeoutMs) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
assertTrue(nc.hasCapability(capability));
return nc;
}
NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ return expectCapabilitiesWithout(capability, agent, TIMEOUT_MS);
+ }
+
+ NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
+ int timeoutMs) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
assertFalse(nc.hasCapability(capability));
return nc;
@@ -1831,6 +1844,51 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testNetworkGoesIntoBackgroundAfterLinger() {
+ setMobileDataAlwaysOn(true);
+ NetworkRequest request = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .build();
+ TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+
+ mCellNetworkAgent.connect(true);
+ callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+
+ // Wifi comes up and cell lingers.
+ mWiFiNetworkAgent.connect(true);
+ defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+
+ // File a request for cellular, then release it.
+ NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ NetworkCallback noopCallback = new NetworkCallback();
+ mCm.requestNetwork(cellRequest, noopCallback);
+ mCm.unregisterNetworkCallback(noopCallback);
+ callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+
+ // Let linger run its course.
+ callback.assertNoCallback();
+ final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent,
+ lingerTimeoutMs);
+
+ // Clean up.
+ mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(callback);
+ }
+
+ @Test
public void testExplicitlySelected() {
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -3125,6 +3183,9 @@ public class ConnectivityServiceTest {
InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
+ final int validKaInterval = 15;
+ final int invalidKaInterval = 9;
+
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("wlan12");
lp.addLinkAddress(new LinkAddress(myIPv6, 64));
@@ -3139,36 +3200,37 @@ public class ConnectivityServiceTest {
PacketKeepalive ka;
// Attempt to start keepalives with invalid parameters and check for errors.
- ka = mCm.startNattKeepalive(notMyNet, 25, callback, myIPv4, 1234, dstIPv4);
+ ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
- ka = mCm.startNattKeepalive(myNet, 19, callback, notMyIPv4, 1234, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 1234, dstIPv6);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6);
callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS); // NAT-T is IPv4-only.
+ // NAT-T is only supported for IPv4.
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6);
+ callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
// Check that a started keepalive can be stopped.
mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
ka.stop();
@@ -3176,7 +3238,7 @@ public class ConnectivityServiceTest {
// Check that deleting the IP address stops the keepalive.
LinkProperties bogusLp = new LinkProperties(lp);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
@@ -3185,7 +3247,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.sendLinkProperties(lp);
// Check that a started keepalive is stopped correctly when the network disconnects.
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
mWiFiNetworkAgent.disconnect();
waitFor(mWiFiNetworkAgent.getDisconnectedCV());
@@ -3202,7 +3264,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
// Check things work as expected when the keepalive is stopped and the network disconnects.
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
ka.stop();
mWiFiNetworkAgent.disconnect();
@@ -3216,13 +3278,14 @@ public class ConnectivityServiceTest {
// Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
+ ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
// The second one gets slot 2.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
- PacketKeepalive ka2 = mCm.startNattKeepalive(myNet, 25, callback2, myIPv4, 6789, dstIPv4);
+ PacketKeepalive ka2 = mCm.startNattKeepalive(
+ myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4);
callback2.expectStarted();
// Now stop the first one and create a third. This also gets slot 1.
@@ -3231,7 +3294,8 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
- PacketKeepalive ka3 = mCm.startNattKeepalive(myNet, 25, callback3, myIPv4, 9876, dstIPv4);
+ PacketKeepalive ka3 = mCm.startNattKeepalive(
+ myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4);
callback3.expectStarted();
ka2.stop();
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 66e0955b04c3..3e1ff6dd5f32 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -281,6 +281,7 @@ public class IpSecServiceParameterizedTest {
anyInt());
}
+ @Test
public void testCreateTwoTransformsWithSameSpis() throws Exception {
IpSecConfig ipSecConfig = new IpSecConfig();
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 9bfc0105fcc9..71e6859f2049 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -263,6 +263,7 @@ public class CredentialTest {
*
* @throws Exception
*/
+ @Test
public void validateCertCredentialWithoutCaCert() throws Exception {
Credential cred = createCredentialWithCertificateCredential();
cred.setCaCertificate(null);