diff options
26 files changed, 651 insertions, 91 deletions
diff --git a/Android.bp b/Android.bp index 7e659247c734..90dca0350a0c 100644 --- a/Android.bp +++ b/Android.bp @@ -914,6 +914,7 @@ framework_docs_only_libs = [ ] metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + + "--ignore-classes-on-classpath " + "--hide-package com.android.okhttp " + "--hide-package com.android.org.conscrypt --hide-package com.android.server " + "--error UnhiddenSystemApi " + @@ -1417,29 +1418,6 @@ droidstubs { " --show-annotation android.annotation.TestApi ", } -filegroup { - name: "apache-http-stubs-sources", - srcs: [ - "core/java/org/apache/http/conn/ConnectTimeoutException.java", - "core/java/org/apache/http/conn/scheme/HostNameResolver.java", - "core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java", - "core/java/org/apache/http/conn/scheme/SocketFactory.java", - "core/java/org/apache/http/conn/ssl/AbstractVerifier.java", - "core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java", - "core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java", - "core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java", - "core/java/org/apache/http/conn/ssl/SSLSocketFactory.java", - "core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java", - "core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java", - "core/java/org/apache/http/params/CoreConnectionPNames.java", - "core/java/org/apache/http/params/HttpConnectionParams.java", - "core/java/org/apache/http/params/HttpParams.java", - "core/java/android/net/http/SslCertificate.java", - "core/java/android/net/http/SslError.java", - "core/java/com/android/internal/util/HexDump.java", - ], -} - droidstubs { name: "api-stubs-docs", defaults: ["metalava-api-stubs-default"], diff --git a/api/current.txt b/api/current.txt index 0c60fc16c5c4..8b06719dfad5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -44161,6 +44161,7 @@ package android.telephony { field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool"; + field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool"; field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array"; field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; @@ -44970,6 +44971,7 @@ package android.telephony { method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot(); + method public int getActiveModemCount(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); method public int getCardIdForDefaultEuicc(); @@ -45002,7 +45004,7 @@ package android.telephony { method public String getNetworkOperatorName(); method public String getNetworkSpecifier(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType(); - method public int getPhoneCount(); + method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); @@ -45018,6 +45020,7 @@ package android.telephony { method public int getSimState(); method public int getSimState(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId(); + method public int getSupportedModemCount(); method @Nullable public String getTypeAllocationCode(); method @Nullable public String getTypeAllocationCode(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo(); @@ -45070,6 +45073,7 @@ package android.telephony { method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE"; field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL"; + field public static final String ACTION_MULTI_SIM_CONFIG_CHANGED = "android.telephony.action.MULTI_SIM_CONFIG_CHANGED"; field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED"; field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; @@ -45110,6 +45114,7 @@ package android.telephony { field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY"; field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; + field public static final String EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED = "android.telephony.extra.NUM_OF_ACTIVE_SIM_SUPPORTED"; field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE"; field public static final String EXTRA_SPECIFIC_CARRIER_ID = "android.telephony.extra.SPECIFIC_CARRIER_ID"; field public static final String EXTRA_SPECIFIC_CARRIER_NAME = "android.telephony.extra.SPECIFIC_CARRIER_NAME"; @@ -45120,6 +45125,10 @@ package android.telephony { field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID"; field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU"; + field public static final int MODEM_COUNT_DUAL_MODEM = 2; // 0x2 + field public static final int MODEM_COUNT_NO_MODEM = 0; // 0x0 + field public static final int MODEM_COUNT_SINGLE_MODEM = 1; // 0x1 + field public static final int MODEM_COUNT_TRI_MODEM = 3; // 0x3 field public static final int MULTISIM_ALLOWED = 0; // 0x0 field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2 field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1 diff --git a/api/system-current.txt b/api/system-current.txt index a9d228971d22..2321e3e78b18 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8149,6 +8149,9 @@ package android.telephony { public class TelephonyManager { method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionReportDefaultNetworkStatus(int, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionResetAll(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionSetRadioEnabled(int, boolean); method public int checkCarrierPrivilegesForPackage(String); method public int checkCarrierPrivilegesForPackageAnyPhone(String); method public void dial(String); diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java index f641731fa08f..124b6c6f7377 100644 --- a/core/java/android/os/ServiceManagerNative.java +++ b/core/java/android/os/ServiceManagerNative.java @@ -86,6 +86,10 @@ class ServiceManagerProxy implements IServiceManager { throw new RemoteException(); } + public boolean isDeclared(String name) throws RemoteException { + throw new RemoteException(); + } + /** * Same as mServiceManager but used by apps. * diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java index a3dc9471a1d0..9e495dd775dc 100644 --- a/core/java/android/provider/SettingsStringUtil.java +++ b/core/java/android/provider/SettingsStringUtil.java @@ -126,7 +126,7 @@ public class SettingsStringUtil { @Override protected String itemToString(ComponentName item) { - return item.flattenToString(); + return item != null ? item.flattenToString() : "null"; } public static String add(String delimitedElements, ComponentName element) { diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index bb5780558bdf..3704ccdfb8ea 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -59,6 +59,10 @@ FileDescriptorWhitelist* FileDescriptorWhitelist::Get() { return instance_; } +static bool IsArtMemfd(const std::string& path) { + return android::base::StartsWith(path, "/memfd:/boot-image-methods.art"); +} + bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { // Check the static whitelist path. for (const auto& whitelist_path : kPathWhitelist) { @@ -87,6 +91,11 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { return true; } + // the in-memory file created by ART through memfd_create is allowed. + if (IsArtMemfd(path)) { + return true; + } + // Whitelist files needed for Runtime Resource Overlay, like these: // /system/vendor/overlay/framework-res.apk // /system/vendor/overlay-subdir/pg/framework-res.apk @@ -312,6 +321,11 @@ void FileDescriptorInfo::ReopenOrDetach(fail_fn_t fail_fn) const { return DetachSocket(fail_fn); } + // Children can directly use the in-memory file created by ART through memfd_create. + if (IsArtMemfd(file_path)) { + return; + } + // NOTE: This might happen if the file was unlinked after being opened. // It's a common pattern in the case of temporary files and the like but // we should not allow such usage from the zygote. @@ -531,6 +545,10 @@ FileDescriptorTable::FileDescriptorTable( } void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) { + // ART creates a file through memfd for optimization purposes. We make sure + // there is at most one being created. + bool art_memfd_seen = false; + // Iterate through the list of file descriptors we've already recorded // and check whether : // @@ -563,6 +581,14 @@ void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail // FD. } + if (IsArtMemfd(it->second->file_path)) { + if (art_memfd_seen) { + fail_fn("ART fd already seen: " + it->second->file_path); + } else { + art_memfd_seen = true; + } + } + ++it; // Finally, remove the FD from the set of open_fds. We do this last because diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 6ab0fc91d744..74ced8921799 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -3,8 +3,10 @@ # Metrics joeo@google.com singhtejinder@google.com +yanmin@google.com yaochen@google.com yro@google.com +zhouwenjie@google.com # Settings UI per-file settings_enums.proto=tmfang@google.com diff --git a/location/lib/Android.bp b/location/lib/Android.bp index fe0f669508eb..cd45e8e6ffa6 100644 --- a/location/lib/Android.bp +++ b/location/lib/Android.bp @@ -17,10 +17,8 @@ java_sdk_library { name: "com.android.location.provider", srcs: ["java/**/*.java"], - api_srcs: [":framework-all-sources"], libs: [ "androidx.annotation_annotation", - "framework-all", ], api_packages: ["com.android.location.provider"], } diff --git a/media/java/android/media/tv/OWNER b/media/java/android/media/tv/OWNER new file mode 100644 index 000000000000..64c0bb53e894 --- /dev/null +++ b/media/java/android/media/tv/OWNER @@ -0,0 +1,5 @@ +amyjojo@google.com +nchalko@google.com +shubang@google.com +quxiangfang@google.com + diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h index 8078e369ee82..d4672a95c6d8 100644 --- a/media/jni/audioeffect/Visualizer.h +++ b/media/jni/audioeffect/Visualizer.h @@ -73,7 +73,8 @@ public: ~Visualizer(); - virtual status_t setEnabled(bool enabled); + // Declared 'final' because we call this in ~Visualizer(). + status_t setEnabled(bool enabled) final; // maximum capture size in samples static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; } diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp index 6b03e4de57d7..3b2578754087 100644 --- a/media/lib/signer/Android.bp +++ b/media/lib/signer/Android.bp @@ -17,7 +17,5 @@ java_sdk_library { name: "com.android.mediadrm.signer", srcs: ["java/**/*.java"], - api_srcs: [":framework-all-sources"], - libs: ["framework-all"], api_packages: ["com.android.mediadrm.signer"], } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 11b0487a64b2..047ac5984fe3 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -173,6 +173,8 @@ <uses-permission android:name="android.permission.MANAGE_WIFI_WHEN_WIRELESS_CONSENT_REQUIRED" /> <!-- Permission needed to invoke DynamicSystem (AOT) --> <uses-permission android:name="android.permission.INSTALL_DYNAMIC_SYSTEM" /> + <!-- Used to clean up heap dumps on boot. --> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.CONTROL_KEYGUARD" /> @@ -201,7 +203,7 @@ <!-- Permission required to test ExplicitHealthCheckServiceImpl. --> <uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" /> - + <!-- Permission required for CTS test - CrossProfileAppsHostSideTest --> <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/> @@ -231,12 +233,25 @@ </intent-filter> </provider> + <provider android:name=".HeapDumpProvider" + android:authorities="com.android.shell.heapdump" + android:grantUriPermissions="true" + android:exported="true" /> + <activity android:name=".BugreportWarningActivity" android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" android:exported="false" /> + <activity android:name=".HeapDumpActivity" + android:theme="@*android:style/Theme.Translucent.NoTitleBar" + android:label="@*android:string/dump_heap_title" + android:finishOnCloseSystemDialogs="true" + android:noHistory="true" + android:excludeFromRecents="true" + android:exported="false" /> + <receiver android:name=".BugreportReceiver" android:permission="android.permission.DUMP"> @@ -254,6 +269,16 @@ </intent-filter> </receiver> + <receiver + android:name=".HeapDumpReceiver" + android:permission="android.permission.DUMP"> + <intent-filter> + <action android:name="android.intent.action.BOOT_COMPLETED" /> + <action android:name="com.android.internal.intent.action.HEAP_DUMP_FINISHED" /> + <action android:name="com.android.shell.action.DELETE_HEAP_DUMP" /> + </intent-filter> + </receiver> + <service android:name=".BugreportProgressService" android:exported="false"/> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 857cb2af41f6..29c61ee70f7d 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -1410,7 +1410,7 @@ public class BugreportProgressService extends Service { return false; } - private static boolean isTv(Context context) { + static boolean isTv(Context context) { return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); } diff --git a/packages/Shell/src/com/android/shell/HeapDumpActivity.java b/packages/Shell/src/com/android/shell/HeapDumpActivity.java new file mode 100644 index 000000000000..0ff0d3353041 --- /dev/null +++ b/packages/Shell/src/com/android/shell/HeapDumpActivity.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2019 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.shell; + +import static com.android.shell.HeapDumpProvider.makeUri; +import static com.android.shell.HeapDumpReceiver.ACTION_DELETE_HEAP_DUMP; +import static com.android.shell.HeapDumpReceiver.EXTRA_IS_USER_INITIATED; +import static com.android.shell.HeapDumpReceiver.EXTRA_PROCESS_NAME; +import static com.android.shell.HeapDumpReceiver.EXTRA_REPORT_PACKAGE; +import static com.android.shell.HeapDumpReceiver.EXTRA_SIZE_BYTES; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AlertDialog; +import android.content.ActivityNotFoundException; +import android.content.ClipData; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Process; +import android.util.DebugUtils; +import android.util.Log; + +import com.android.internal.R; + +/** + * This activity is displayed when the system has collected a heap dump. + */ +public class HeapDumpActivity extends Activity { + private static final String TAG = "HeapDumpActivity"; + + static final String KEY_URI = "uri"; + + private AlertDialog mDialog; + private Uri mDumpUri; + private boolean mHandled = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String process = getIntent().getStringExtra(EXTRA_PROCESS_NAME); + long size = getIntent().getLongExtra(EXTRA_SIZE_BYTES, 0); + final boolean isUserInitiated = getIntent().getBooleanExtra(EXTRA_IS_USER_INITIATED, false); + final int uid = getIntent().getIntExtra(Intent.EXTRA_UID, 0); + final boolean isSystemProcess = uid == Process.SYSTEM_UID; + mDumpUri = makeUri(process); + final String procDisplayName = isSystemProcess + ? getString(com.android.internal.R.string.android_system_label) + : process; + + final Intent sendIntent = new Intent(); + ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", mDumpUri); + sendIntent.setClipData(clip); + sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + sendIntent.setType(clip.getDescription().getMimeType(0)); + sendIntent.putExtra(Intent.EXTRA_STREAM, mDumpUri); + + String directLaunchPackage = getIntent().getStringExtra(EXTRA_REPORT_PACKAGE); + if (directLaunchPackage != null) { + sendIntent.setAction(ActivityManager.ACTION_REPORT_HEAP_LIMIT); + sendIntent.setPackage(directLaunchPackage); + try { + startActivity(sendIntent); + mHandled = true; + finish(); + return; + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Unable to direct launch to " + directLaunchPackage, e); + } + } + + final int messageId; + if (isUserInitiated) { + messageId = com.android.internal.R.string.dump_heap_ready_text; + } else if (isSystemProcess) { + messageId = com.android.internal.R.string.dump_heap_system_text; + } else { + messageId = com.android.internal.R.string.dump_heap_text; + } + mDialog = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert) + .setTitle(com.android.internal.R.string.dump_heap_title) + .setMessage(getString(messageId, procDisplayName, + DebugUtils.sizeValueToString(size, null))) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> { + mHandled = true; + finish(); + }) + .setNeutralButton(R.string.delete, (dialog, which) -> { + mHandled = true; + Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP); + deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class); + deleteIntent.putExtra(KEY_URI, mDumpUri.toString()); + sendBroadcast(deleteIntent); + finish(); + }) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + mHandled = true; + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.setPackage(null); + startActivity(Intent.createChooser(sendIntent, + getText(com.android.internal.R.string.dump_heap_title))); + finish(); + }) + .show(); + } + + @Override + protected void onStop() { + super.onStop(); + if (!isChangingConfigurations()) { + if (!mHandled) { + Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP); + deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class); + deleteIntent.putExtra(KEY_URI, mDumpUri.toString()); + sendBroadcast(deleteIntent); + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDialog != null) { + mDialog.dismiss(); + } + } +} diff --git a/packages/Shell/src/com/android/shell/HeapDumpProvider.java b/packages/Shell/src/com/android/shell/HeapDumpProvider.java new file mode 100644 index 000000000000..3eceb9118b12 --- /dev/null +++ b/packages/Shell/src/com/android/shell/HeapDumpProvider.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 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.shell; + +import android.annotation.NonNull; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.os.Process; + +import java.io.File; +import java.io.FileNotFoundException; + +/** ContentProvider to write and access heap dumps. */ +public class HeapDumpProvider extends ContentProvider { + private static final String FILENAME_SUFFIX = "_javaheap.bin"; + private static final Object sLock = new Object(); + + private File mRoot; + + @Override + public boolean onCreate() { + synchronized (sLock) { + mRoot = new File(getContext().createCredentialProtectedStorageContext().getFilesDir(), + "heapdumps"); + return mRoot.mkdir(); + } + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return "application/octet-stream"; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("Insert not allowed."); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + String path = sanitizePath(uri.getEncodedPath()); + String tag = Uri.decode(path); + return (new File(mRoot, tag)).delete() ? 1 : 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("Update not allowed."); + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + String path = sanitizePath(uri.getEncodedPath()); + String tag = Uri.decode(path); + final int pMode; + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + pMode = ParcelFileDescriptor.MODE_CREATE + | ParcelFileDescriptor.MODE_TRUNCATE + | ParcelFileDescriptor.MODE_WRITE_ONLY; + } else { + pMode = ParcelFileDescriptor.MODE_READ_ONLY; + } + + synchronized (sLock) { + return ParcelFileDescriptor.open(new File(mRoot, tag), pMode); + } + } + + @NonNull + static Uri makeUri(@NonNull String procName) { + return Uri.parse("content://com.android.shell.heapdump/" + procName + FILENAME_SUFFIX); + } + + private String sanitizePath(String path) { + return path.replaceAll("[^a-zA-Z0-9_.]", ""); + } +} diff --git a/packages/Shell/src/com/android/shell/HeapDumpReceiver.java b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java new file mode 100644 index 000000000000..858c521eaed5 --- /dev/null +++ b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 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.shell; + +import static com.android.shell.BugreportProgressService.isTv; + +import android.annotation.Nullable; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.FileUtils; +import android.os.Process; +import android.text.format.DateUtils; +import android.util.Log; + +import java.io.File; + +/** + * Receiver that handles finished heap dumps. + */ +public class HeapDumpReceiver extends BroadcastReceiver { + private static final String TAG = "HeapDumpReceiver"; + + /** + * Broadcast action to determine when to delete a specific dump heap. Must include a {@link + * HeapDumpActivity#KEY_URI} String extra. + */ + static final String ACTION_DELETE_HEAP_DUMP = "com.android.shell.action.DELETE_HEAP_DUMP"; + + /** Broadcast sent when heap dump collection has been completed. */ + private static final String ACTION_HEAP_DUMP_FINISHED = + "com.android.internal.intent.action.HEAP_DUMP_FINISHED"; + + /** The process we are reporting */ + static final String EXTRA_PROCESS_NAME = "com.android.internal.extra.heap_dump.PROCESS_NAME"; + + /** The size limit the process reached. */ + static final String EXTRA_SIZE_BYTES = "com.android.internal.extra.heap_dump.SIZE_BYTES"; + + /** Whether the user initiated the dump or not. */ + static final String EXTRA_IS_USER_INITIATED = + "com.android.internal.extra.heap_dump.IS_USER_INITIATED"; + + /** Optional name of package to directly launch. */ + static final String EXTRA_REPORT_PACKAGE = + "com.android.internal.extra.heap_dump.REPORT_PACKAGE"; + + private static final String NOTIFICATION_CHANNEL_ID = "heapdumps"; + private static final int NOTIFICATION_ID = 2019; + + /** + * Always keep heap dumps taken in the last week. + */ + private static final long MIN_KEEP_AGE_MS = DateUtils.WEEK_IN_MILLIS; + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive(): " + intent); + final String action = intent.getAction(); + if (action == null) { + Log.e(TAG, "null action received"); + return; + } + switch (action) { + case Intent.ACTION_BOOT_COMPLETED: + cleanupOldFiles(context); + break; + case ACTION_DELETE_HEAP_DUMP: + deleteHeapDump(context, intent.getStringExtra(HeapDumpActivity.KEY_URI)); + break; + case ACTION_HEAP_DUMP_FINISHED: + showDumpNotification(context, intent); + break; + } + } + + private void cleanupOldFiles(Context context) { + final PendingResult result = goAsync(); + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + try { + Log.d(TAG, "Deleting from " + new File(context.getFilesDir(), "heapdumps")); + FileUtils.deleteOlderFiles(new File(context.getFilesDir(), "heapdumps"), 0, + MIN_KEEP_AGE_MS); + } catch (RuntimeException e) { + Log.e(TAG, "Couldn't delete old files", e); + } + result.finish(); + return null; + } + }.execute(); + } + + private void deleteHeapDump(Context context, @Nullable final String uri) { + if (uri == null) { + Log.e(TAG, "null URI for delete heap dump intent"); + return; + } + final PendingResult result = goAsync(); + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + context.getContentResolver().delete(Uri.parse(uri), null, null); + result.finish(); + return null; + } + }.execute(); + } + + private void showDumpNotification(Context context, Intent intent) { + final boolean isUserInitiated = intent.getBooleanExtra( + EXTRA_IS_USER_INITIATED, false); + final String procName = intent.getStringExtra(EXTRA_PROCESS_NAME); + final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); + + final String reportPackage = intent.getStringExtra( + EXTRA_REPORT_PACKAGE); + final long size = intent.getLongExtra(EXTRA_SIZE_BYTES, 0); + + if (procName == null) { + Log.e(TAG, "No process name sent over"); + return; + } + + NotificationManager nm = NotificationManager.from(context); + nm.createNotificationChannel( + new NotificationChannel(NOTIFICATION_CHANNEL_ID, + "Heap dumps", + NotificationManager.IMPORTANCE_DEFAULT)); + + final int titleId = isUserInitiated + ? com.android.internal.R.string.dump_heap_ready_notification + : com.android.internal.R.string.dump_heap_notification; + final String procDisplayName = uid == Process.SYSTEM_UID + ? context.getString(com.android.internal.R.string.android_system_label) + : procName; + String text = context.getString(titleId, procDisplayName); + + Intent shareIntent = new Intent(); + shareIntent.setClassName(context, HeapDumpActivity.class.getName()); + shareIntent.putExtra(EXTRA_PROCESS_NAME, procName); + shareIntent.putExtra(EXTRA_SIZE_BYTES, size); + shareIntent.putExtra(EXTRA_IS_USER_INITIATED, isUserInitiated); + shareIntent.putExtra(Intent.EXTRA_UID, uid); + if (reportPackage != null) { + shareIntent.putExtra(EXTRA_REPORT_PACKAGE, reportPackage); + } + final Notification.Builder builder = new Notification.Builder(context, + NOTIFICATION_CHANNEL_ID) + .setSmallIcon( + isTv(context) ? R.drawable.ic_bug_report_black_24dp + : com.android.internal.R.drawable.stat_sys_adb) + .setLocalOnly(true) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setContentTitle(text) + .setTicker(text) + .setAutoCancel(true) + .setContentText(context.getText( + com.android.internal.R.string.dump_heap_notification_detail)) + .setContentIntent(PendingIntent.getActivity(context, 2, shareIntent, + PendingIntent.FLAG_UPDATE_CURRENT)); + + Log.v(TAG, "Creating share heap dump notification"); + NotificationManager.from(context).notify(NOTIFICATION_ID, builder.build()); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index a15c035fdd3a..0efc5bf411f3 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -172,7 +172,7 @@ public class CarrierTextController { mSeparator = separator; mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); mSimSlotsNumber = ((TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE)).getMaxPhoneCount(); + Context.TELEPHONY_SERVICE)).getSupportedModemCount(); mSimErrorState = new boolean[mSimSlotsNumber]; updateDisplayOpportunisticSubscriptionCarrierText(SystemProperties.getBoolean( TelephonyProperties.DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index e74e955cd7a0..528625ee4dc8 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -119,7 +119,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); - when(mTelephonyManager.getMaxPhoneCount()).thenReturn(3); + when(mTelephonyManager.getSupportedModemCount()).thenReturn(3); mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true, mKeyguardUpdateMonitor); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 05b937a34626..d4fb9acdad5e 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -82,8 +82,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.provider.Settings; -import android.provider.SettingsStringUtil; -import android.provider.SettingsStringUtil.ComponentNameSet; import android.provider.SettingsStringUtil.SettingStringHelper; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; @@ -2436,12 +2434,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Enables accessibility service specified by {@param componentName} for the {@param userId}. */ private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) { - final SettingStringHelper setting = - new SettingStringHelper( - mContext.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - userId); - setting.write(ComponentNameSet.add(setting.read(), componentName)); + mTempComponentNameSet.clear(); + readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + userId, mTempComponentNameSet); + mTempComponentNameSet.add(componentName); + persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + mTempComponentNameSet, userId); UserState userState = getUserStateLocked(userId); if (userState.mEnabledServices.add(componentName)) { @@ -2453,12 +2451,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * Disables accessibility service specified by {@param componentName} for the {@param userId}. */ private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) { - final SettingsStringUtil.SettingStringHelper setting = - new SettingStringHelper( - mContext.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - userId); - setting.write(ComponentNameSet.remove(setting.read(), componentName)); + mTempComponentNameSet.clear(); + readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + userId, mTempComponentNameSet); + mTempComponentNameSet.remove(componentName); + persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + mTempComponentNameSet, userId); UserState userState = getUserStateLocked(userId); if (userState.mEnabledServices.remove(componentName)) { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 0269579e3e07..14678884e8e2 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -382,7 +382,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext = context; mBatteryStats = BatteryStatsService.getService(); - int numPhones = TelephonyManager.getDefault().getMaxPhoneCount(); + int numPhones = TelephonyManager.getDefault().getSupportedModemCount(); if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones); mNumPhones = numPhones; mCallState = new int[numPhones]; diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index c5c53d8ba4ca..a18a53dfea92 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4112,9 +4112,13 @@ class ActivityStack extends ConfigurationContainer { final ActivityDisplay display = getDisplay(); final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */); final boolean isFloating = r.getConfiguration().windowConfiguration.tasksAreFloating(); - - if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) - && next != null && !next.nowVisible && !isFloating) { + // isNextNotYetVisible is to check if the next activity is invisible, or it has been + // requested to be invisible but its windows haven't reported as invisible. If so, it + // implied that the current finishing activity should be added into stopping list rather + // than destroying it immediately. + final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible); + if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) && isNextNotYetVisible + && !isFloating) { if (!mStackSupervisor.mStoppingActivities.contains(r)) { addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */, "finishCurrentActivityLocked"); diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index d5fbd2b316e7..c59e6056b72e 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -151,7 +151,7 @@ static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) { } } -static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) { +static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jlong strength) { Status status; uint32_t lengthMs; auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index fc0c2e84243e..e458ae6b1d3d 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1831,6 +1831,13 @@ public class CarrierConfigManager { "support_direct_fdn_dialing_bool"; /** + * Int indicating the max number length for FDN + * @hide + */ + public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT = + "fdn_number_length_limit_int"; + + /** * Report IMEI as device id even if it's a CDMA/LTE phone. * * @hide @@ -3170,6 +3177,14 @@ public class CarrierConfigManager { public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array"; + /** + * Flag specifying whether to prevent sending CLIR activation("*31#") and deactivation("#31#") + * code only without dialing number. + * When {@code true}, these are prevented, {@code false} otherwise. + */ + public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = + "prevent_clir_activation_and_deactivation_code_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -3371,6 +3386,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL, false); sDefaults.putString(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING, ""); sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false); + sDefaults.putInt(KEY_FDN_NUMBER_LENGTH_LIMIT_INT, 20); sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, true); @@ -3596,6 +3612,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null); sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY, new int[] {4 /* BUSY */}); + sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false); } /** diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 97c46e33a472..4e93efde54f1 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2095,13 +2095,13 @@ public class SubscriptionManager { /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static boolean isValidSlotIndex(int slotIndex) { - return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getMaxPhoneCount(); + return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSupportedModemCount(); } /** @hide */ @UnsupportedAppUsage public static boolean isValidPhoneId(int phoneId) { - return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getMaxPhoneCount(); + return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getSupportedModemCount(); } /** @hide */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 311d260ee209..bec0a975108a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -289,6 +289,21 @@ public class TelephonyManager { }; /** @hide */ + @IntDef(prefix = {"MODEM_COUNT_"}, + value = { + MODEM_COUNT_NO_MODEM, + MODEM_COUNT_SINGLE_MODEM, + MODEM_COUNT_DUAL_MODEM, + MODEM_COUNT_TRI_MODEM + }) + public @interface ModemCount {} + + public static final int MODEM_COUNT_NO_MODEM = 0; + public static final int MODEM_COUNT_SINGLE_MODEM = 1; + public static final int MODEM_COUNT_DUAL_MODEM = 2; + public static final int MODEM_COUNT_TRI_MODEM = 3; + + /** @hide */ @UnsupportedAppUsage public TelephonyManager(Context context) { this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); @@ -365,12 +380,26 @@ public class TelephonyManager { /** * Returns the number of phones available. * Returns 0 if none of voice, sms, data is not supported - * Returns 1 for Single standby mode (Single SIM functionality) - * Returns 2 for Dual standby mode.(Dual SIM functionality) - * Returns 3 for Tri standby mode.(Tri SIM functionality) + * Returns 1 for Single standby mode (Single SIM functionality). + * Returns 2 for Dual standby mode (Dual SIM functionality). + * Returns 3 for Tri standby mode (Tri SIM functionality). + * @deprecated Use {@link #getActiveModemCount} instead. */ + @Deprecated public int getPhoneCount() { - int phoneCount = 1; + return getActiveModemCount(); + } + + /** + * Returns the number of logical modems currently configured to be activated. + * + * Returns 0 if none of voice, sms, data is not supported + * Returns 1 for Single standby mode (Single SIM functionality). + * Returns 2 for Dual standby mode (Dual SIM functionality). + * Returns 3 for Tri standby mode (Tri SIM functionality). + */ + public @ModemCount int getActiveModemCount() { + int modemCount = 1; switch (getMultiSimConfiguration()) { case UNKNOWN: ConnectivityManager cm = mContext == null ? null : (ConnectivityManager) mContext @@ -378,45 +407,32 @@ public class TelephonyManager { // check for voice and data support, 0 if not supported if (!isVoiceCapable() && !isSmsCapable() && cm != null && !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { - phoneCount = 0; + modemCount = MODEM_COUNT_NO_MODEM; } else { - phoneCount = 1; + modemCount = MODEM_COUNT_SINGLE_MODEM; } break; case DSDS: case DSDA: - phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; + modemCount = MODEM_COUNT_DUAL_MODEM; break; case TSTS: - phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM; + modemCount = MODEM_COUNT_TRI_MODEM; break; } - return phoneCount; + return modemCount; } /** - * - * Return how many phone / logical modem can be active simultaneously, in terms of device + * Return how many logical modem can be potentially active simultaneously, in terms of hardware * capability. - * For example, for a dual-SIM capable device, it always returns 2, even if only one logical - * modem / SIM is active (aka in single SIM mode). - * - * TODO: b/139642279 publicize and rename. - * @hide - */ - public int getMaxPhoneCount() { - // TODO: b/139642279 when turning on this feature, remove dependency of - // PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE and always return result based on - // PROPERTY_MAX_ACTIVE_MODEMS. - String rebootRequired = SystemProperties.get( - TelephonyProperties.PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE); - if (rebootRequired.equals("false")) { - // If no reboot is required, return max possible active modems. - return SystemProperties.getInt( - TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getPhoneCount()); - } else { - return getPhoneCount(); - } + * It might return different value from {@link #getActiveModemCount}. For example, for a + * dual-SIM capable device operating in single SIM mode (only one logical modem is turned on), + * {@link #getActiveModemCount} returns 1 while this API returns 2. + */ + public @ModemCount int getSupportedModemCount() { + return SystemProperties.getInt(TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, + getActiveModemCount()); } /** {@hide} */ @@ -1177,6 +1193,35 @@ public class TelephonyManager { "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; /** + * Broadcast intent that indicates multi-SIM configuration is changed. For example, it changed + * from single SIM capable to dual-SIM capable (DSDS or DSDA) or triple-SIM mode. + * + * It doesn't indicate how many subscriptions are actually active, or which states SIMs are, + * or that all steps during multi-SIM change are done. To know those information you still need + * to listen to SIM_STATE changes or active subscription changes. + * + * See extra of {@link #EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED} for updated value. + */ + public static final String ACTION_MULTI_SIM_CONFIG_CHANGED = + "android.telephony.action.MULTI_SIM_CONFIG_CHANGED"; + + + /** + * The number of active SIM supported by current multi-SIM config. It's not related to how many + * SIM/subscriptions are currently active. + * + * For single SIM mode, it's 1. + * For DSDS or DSDA mode, it's 2. + * For triple-SIM mode, it's 3. + * + * Extra of {@link #ACTION_MULTI_SIM_CONFIG_CHANGED}. + * + * type: integer + */ + public static final String EXTRA_NUM_OF_ACTIVE_SIM_SUPPORTED = + "android.telephony.extra.NUM_OF_ACTIVE_SIM_SUPPORTED"; + + /** * @hide */ public static final String USSD_RESPONSE = "USSD_RESPONSE"; @@ -1832,7 +1877,12 @@ public class TelephonyManager { if (telephony == null) return null; try { - return telephony.getMeidForSlot(slotIndex, getOpPackageName()); + String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName()); + if (TextUtils.isEmpty(meid)) { + Log.d(TAG, "getMeid: return null because MEID is not available"); + return null; + } + return meid; } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -10132,11 +10182,13 @@ public class TelephonyManager { /** * Action set from carrier signalling broadcast receivers to enable/disable radio - * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required + * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required. * @param subId the subscription ID that this action applies to. * @param enabled control enable or disable radio. * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionSetRadioEnabled(int subId, boolean enabled) { try { ITelephony service = getITelephony(); @@ -10151,11 +10203,13 @@ public class TelephonyManager { /** * Action set from carrier signalling broadcast receivers to start/stop reporting default * network available events - * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required + * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required. * @param subId the subscription ID that this action applies to. * @param report control start/stop reporting network status. * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionReportDefaultNetworkStatus(int subId, boolean report) { try { ITelephony service = getITelephony(); @@ -10169,10 +10223,12 @@ public class TelephonyManager { /** * Action set from carrier signalling broadcast receivers to reset all carrier actions - * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required + * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required. * @param subId the subscription ID that this action applies to. * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionResetAll(int subId) { try { ITelephony service = getITelephony(); diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 116c05129a96..e65e032c0cd4 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1206,7 +1206,7 @@ public class ApnSetting implements Parcelable { && !other.canHandleType(TYPE_DUN) && Objects.equals(this.mApnName, other.mApnName) && !typeSameAny(this, other) - && xorEquals(this.mProxyAddress, other.mProxyAddress) + && xorEqualsString(this.mProxyAddress, other.mProxyAddress) && xorEqualsInt(this.mProxyPort, other.mProxyPort) && xorEquals(this.mProtocol, other.mProtocol) && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol) @@ -1215,7 +1215,7 @@ public class ApnSetting implements Parcelable { && Objects.equals(this.mMvnoType, other.mMvnoType) && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData) && xorEquals(this.mMmsc, other.mMmsc) - && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress) + && xorEqualsString(this.mMmsProxyAddress, other.mMmsProxyAddress) && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort)) && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask) && Objects.equals(mApnSetId, other.mApnSetId) @@ -1228,6 +1228,11 @@ public class ApnSetting implements Parcelable { return first == null || second == null || first.equals(second); } + // Equal or one is null. + private boolean xorEqualsString(String first, String second) { + return TextUtils.isEmpty(first) || TextUtils.isEmpty(second) || first.equals(second); + } + // Equal or one is not specified. private boolean xorEqualsInt(int first, int second) { return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT |