diff options
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 *#*#<code>#*#*}. The intent will have the data URI: - * {@code android_secret_code://<code>}. + * 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 *#*#<code>#*#*}. The intent will have the data + * URI: {@code android_secret_code://<code>}. 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 & 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 & 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); |