diff options
21 files changed, 271 insertions, 80 deletions
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index 82d4443ea724..aa283a2d019b 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -226,9 +226,10 @@ public class SystemProperties { */ @UnsupportedAppUsage public static void set(@NonNull String key, @Nullable String val) { - if (val != null && !key.startsWith("ro.") && val.length() > PROP_VALUE_MAX) { + if (val != null && !key.startsWith("ro.") && val.getBytes(StandardCharsets.UTF_8).length + > PROP_VALUE_MAX) { throw new IllegalArgumentException("value of system property '" + key - + "' is longer than " + PROP_VALUE_MAX + " characters: " + val); + + "' is longer than " + PROP_VALUE_MAX + " bytes: " + val); } if (TRACK_KEY_ACCESS) onKeyAccess(key); native_set(key, val); diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java index e8e47857ecba..9610b16a312c 100644 --- a/core/java/android/os/image/DynamicSystemManager.java +++ b/core/java/android/os/image/DynamicSystemManager.java @@ -16,13 +16,16 @@ package android.os.image; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; import android.gsi.AvbPublicKey; import android.gsi.GsiProgress; +import android.gsi.IGsiService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.Pair; /** * The DynamicSystemManager offers a mechanism to use a new system image temporarily. After the @@ -138,17 +141,18 @@ public class DynamicSystemManager { * @param name The DSU partition name * @param size Size of the DSU image in bytes * @param readOnly True if the partition is read only, e.g. system. - * @return {@code true} if the call succeeds. {@code false} either the device does not contain - * enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be - * true. + * @return {@code Integer} an IGsiService.INSTALL_* status code. {@link Session} an installation + * session object if successful, otherwise {@code null}. */ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - public Session createPartition(String name, long size, boolean readOnly) { + public @NonNull Pair<Integer, Session> createPartition( + String name, long size, boolean readOnly) { try { - if (mService.createPartition(name, size, readOnly)) { - return new Session(); + int status = mService.createPartition(name, size, readOnly); + if (status == IGsiService.INSTALL_OK) { + return new Pair<>(status, new Session()); } else { - return null; + return new Pair<>(status, null); } } catch (RemoteException e) { throw new RuntimeException(e.toString()); diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index 4e69952fac2f..755368a85c40 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -35,10 +35,10 @@ interface IDynamicSystemService * @param name The DSU partition name * @param size Size of the DSU image in bytes * @param readOnly True if this partition is readOnly - * @return true if the call succeeds + * @return IGsiService.INSTALL_* status code */ @EnforcePermission("MANAGE_DYNAMIC_SYSTEM") - boolean createPartition(@utf8InCpp String name, long size, boolean readOnly); + int createPartition(@utf8InCpp String name, long size, boolean readOnly); /** * Complete the current partition installation. diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 93c1c20f8252..1777f56691a7 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -867,8 +867,8 @@ public final class DeviceConfig { /** * Delete a property with the provided name and value in the provided namespace * - * @param namespace The namespace containing the property to create or update. - * @param name The name of the property to create or update. + * @param namespace The namespace containing the property to delete. + * @param name The name of the property to delete. * @return True if the property was deleted or it did not exist in the first place. * False if the storage implementation throws errors. * @hide diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index d0fd2b393633..509f4d996ae9 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -350,6 +350,53 @@ public class TextUtils { return ret; } + + /** + * Returns the longest prefix of a string for which the UTF-8 encoding fits into the given + * number of bytes, with the additional guarantee that the string is not truncated in the middle + * of a valid surrogate pair. + * + * <p>Unpaired surrogates are counted as taking 3 bytes of storage. However, a subsequent + * attempt to actually encode a string containing unpaired surrogates is likely to be rejected + * by the UTF-8 implementation. + * + * (copied from google/thirdparty) + * + * @param str a string + * @param maxbytes the maximum number of UTF-8 encoded bytes + * @return the beginning of the string, so that it uses at most maxbytes bytes in UTF-8 + * @throws IndexOutOfBoundsException if maxbytes is negative + * + * @hide + */ + public static String truncateStringForUtf8Storage(String str, int maxbytes) { + if (maxbytes < 0) { + throw new IndexOutOfBoundsException(); + } + + int bytes = 0; + for (int i = 0, len = str.length(); i < len; i++) { + char c = str.charAt(i); + if (c < 0x80) { + bytes += 1; + } else if (c < 0x800) { + bytes += 2; + } else if (c < Character.MIN_SURROGATE + || c > Character.MAX_SURROGATE + || str.codePointAt(i) < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + bytes += 3; + } else { + bytes += 4; + i += (bytes > maxbytes) ? 0 : 1; + } + if (bytes > maxbytes) { + return str.substring(0, i); + } + } + return str; + } + + /** * Returns a string containing the tokens joined by delimiters. * diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java index 4a20ad0f33f5..fc2c8cca9796 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java @@ -33,7 +33,6 @@ import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.os.Build; -import android.os.storage.StorageManager; import android.provider.Settings; import android.text.BidiFormatter; import android.view.LayoutInflater; @@ -282,19 +281,7 @@ public final class AccessibilityTargetHelper { Context.LAYOUT_INFLATER_SERVICE); final View content = inflater.inflate( - R.layout.accessibility_enable_service_encryption_warning, /* root= */ null); - - final TextView encryptionWarningView = (TextView) content.findViewById( - R.id.accessibility_encryption_warning); - if (StorageManager.isNonDefaultBlockEncrypted()) { - final String text = context.getString( - R.string.accessibility_enable_service_encryption_warning, - getServiceName(context, target.getLabel())); - encryptionWarningView.setText(text); - encryptionWarningView.setVisibility(View.VISIBLE); - } else { - encryptionWarningView.setVisibility(View.GONE); - } + R.layout.accessibility_enable_service_warning, /* root= */ null); final ImageView dialogIcon = content.findViewById( R.id.accessibility_permissionDialog_icon); diff --git a/core/res/res/layout/accessibility_enable_service_encryption_warning.xml b/core/res/res/layout/accessibility_enable_service_warning.xml index 400051660592..01ef10177c5a 100644 --- a/core/res/res/layout/accessibility_enable_service_encryption_warning.xml +++ b/core/res/res/layout/accessibility_enable_service_warning.xml @@ -54,14 +54,6 @@ android:fontFamily="google-sans-medium"/> <TextView - android:id="@+id/accessibility_encryption_warning" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="10dip" - android:textAlignment="viewStart" - android:textAppearance="?android:attr/textAppearanceMedium"/> - - <TextView android:id="@+id/accessibility_permissionDialog_description" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 76631926a52a..db0cc277c3af 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4687,13 +4687,6 @@ <xliff:g id="service" example="TalkBack">%1$s</xliff:g> to have full control of your device?</string> - <!-- Warning that the device data will not be encrypted with password or PIN if - enabling an accessibility service and there is a secure lock setup. [CHAR LIMIT=NONE] --> - <string name="accessibility_enable_service_encryption_warning">If you turn on - <xliff:g id="service" example="TalkBack">%1$s</xliff:g>, your device won’t use your screen - lock to enhance data encryption. - </string> - <!-- Warning description that explains that it's appropriate for accessibility services to have full control to help users with accessibility needs. [CHAR LIMIT=NONE] --> <string name="accessibility_service_warning_description">Full control is appropriate for apps diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bacd25d026d4..a296aa5fbae5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3414,14 +3414,12 @@ <java-symbol type="string" name="accessibility_edit_shortcut_menu_volume_title" /> <java-symbol type="string" name="accessibility_uncheck_legacy_item_warning" /> - <java-symbol type="layout" name="accessibility_enable_service_encryption_warning" /> + <java-symbol type="layout" name="accessibility_enable_service_warning" /> <java-symbol type="id" name="accessibility_permissionDialog_icon" /> <java-symbol type="id" name="accessibility_permissionDialog_title" /> - <java-symbol type="id" name="accessibility_encryption_warning" /> <java-symbol type="id" name="accessibility_permission_enable_allow_button" /> <java-symbol type="id" name="accessibility_permission_enable_deny_button" /> <java-symbol type="string" name="accessibility_enable_service_title" /> - <java-symbol type="string" name="accessibility_enable_service_encryption_warning" /> <java-symbol type="layout" name="accessibility_shortcut_chooser_item" /> <java-symbol type="id" name="accessibility_shortcut_target_checkbox" /> diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java index a0fc34923a4d..c4bcfd4cf117 100644 --- a/core/tests/coretests/src/android/text/TextUtilsTest.java +++ b/core/tests/coretests/src/android/text/TextUtilsTest.java @@ -43,6 +43,7 @@ import com.google.android.collect.Lists; import org.junit.Test; import org.junit.runner.RunWith; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -782,6 +783,81 @@ public class TextUtilsTest { } @Test + public void truncateStringForUtf8Storage() { + assertEquals("", TextUtils.truncateStringForUtf8Storage("abc", 0)); + + //================ long normal case ================ + StringBuilder builder = new StringBuilder(); + + int n = 50; + for (int i = 0; i < 2 * n; i++) { + builder.append("哈"); + } + String initial = builder.toString(); + String result = TextUtils.truncateStringForUtf8Storage(initial, n); + + // Result should be the beginning of initial + assertTrue(initial.startsWith(result)); + + // Result should take less than n bytes in UTF-8 + assertTrue(result.getBytes(StandardCharsets.UTF_8).length <= n); + + // result + the next codePoint should take strictly more than + // n bytes in UTF-8 + assertTrue(initial.substring(0, initial.offsetByCodePoints(result.length(), 1)) + .getBytes(StandardCharsets.UTF_8).length > n); + + // =================== short normal case ===================== + String s = "sf\u20ACgk\u00E9ls\u00E9fg"; + result = TextUtils.truncateStringForUtf8Storage(s, 100); + assertEquals(s, result); + } + + @Test + public void testTruncateInMiddleOfSurrogate() { + StringBuilder builder = new StringBuilder(); + String beginning = "a"; + builder.append(beginning); + builder.append(Character.toChars(0x1D11E)); + + String result = TextUtils.truncateStringForUtf8Storage(builder.toString(), 3); + + // \u1D11E is a surrogate and needs 4 bytes in UTF-8. beginning == "a" uses + // only 1 bytes in UTF8 + // As we allow only 3 bytes for the whole string, so just 2 for this + // codePoint, there is not enough place and the string will be truncated + // just before it + assertEquals(beginning, result); + } + + @Test + public void testTruncateInMiddleOfChar() { + StringBuilder builder = new StringBuilder(); + String beginning = "a"; + builder.append(beginning); + builder.append(Character.toChars(0x20AC)); + + String result = TextUtils.truncateStringForUtf8Storage(builder.toString(), 3); + + // Like above, \u20AC uses 3 bytes in UTF-8, with "beginning", that makes + // 4 bytes so it is too big and should be truncated + assertEquals(beginning, result); + } + + @Test + public void testTruncateSubString() { + String test = "sdgkl;hjsl;gjhdgkljdfhglkdj"; + String sub = test.substring(10, 20); + String res = TextUtils.truncateStringForUtf8Storage(sub, 255); + assertEquals(sub, res); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void truncateStringForUtf8StorageThrowsExceptionForNegativeSize() { + TextUtils.truncateStringForUtf8Storage("abc", -1); + } + + @Test public void length() { assertEquals(0, TextUtils.length(null)); assertEquals(0, TextUtils.length("")); diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 3a3565941489..55626844594d 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -110,6 +110,7 @@ public class DynamicSystemInstallationService extends Service private static final int EVENT_DSU_PROGRESS_UPDATE = 120000; private static final int EVENT_DSU_INSTALL_COMPLETE = 120001; private static final int EVENT_DSU_INSTALL_FAILED = 120002; + private static final int EVENT_DSU_INSTALL_INSUFFICIENT_SPACE = 120003; protected static void logEventProgressUpdate( String partitionName, @@ -136,6 +137,10 @@ public class DynamicSystemInstallationService extends Service EventLog.writeEvent(EVENT_DSU_INSTALL_FAILED, cause); } + protected static void logEventInsufficientSpace() { + EventLog.writeEvent(EVENT_DSU_INSTALL_INSUFFICIENT_SPACE); + } + /* * IPC */ @@ -258,6 +263,8 @@ public class DynamicSystemInstallationService extends Service if (result == RESULT_CANCELLED) { logEventFailed("Dynamic System installation task is canceled by the user."); + } else if (detail instanceof InstallationAsyncTask.InsufficientSpaceException) { + logEventInsufficientSpace(); } else { logEventFailed("error: " + detail); } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags index 407314384be8..8d8be1030b8e 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/EventLogTags.logtags @@ -5,3 +5,4 @@ option java_package com.android.dynsystem 120000 dsu_progress_update (partition_name|3),(installed_bytes|2|5),(total_bytes|2|5),(partition_number|1|5),(total_partition_number|1|5),(total_progress_percentage|1|5) 120001 dsu_install_complete 120002 dsu_install_failed (cause|3) +120003 dsu_install_insufficient_space diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 38d851eb76aa..62e53d62fd2a 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -18,6 +18,7 @@ package com.android.dynsystem; import android.content.Context; import android.gsi.AvbPublicKey; +import android.gsi.IGsiService; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -27,6 +28,7 @@ import android.os.SystemProperties; import android.os.image.DynamicSystemManager; import android.service.persistentdata.PersistentDataBlockManager; import android.util.Log; +import android.util.Pair; import android.util.Range; import android.webkit.URLUtil; @@ -106,8 +108,15 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } } + static class InsufficientSpaceException extends IOException { + InsufficientSpaceException(String message) { + super(message); + } + } + /** UNSET means the installation is not completed */ static final int RESULT_UNSET = 0; + static final int RESULT_OK = 1; static final int RESULT_CANCELLED = 2; static final int RESULT_ERROR_IO = 3; @@ -157,6 +166,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { private final boolean mIsNetworkUrl; private final boolean mIsDeviceBootloaderUnlocked; private final boolean mWantScratchPartition; + private int mCreatePartitionStatus; private DynamicSystemManager.Session mInstallationSession; private KeyRevocationList mKeyRevocationList; @@ -364,7 +374,7 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { mIsZip = true; } else { throw new UnsupportedFormatException( - String.format(Locale.US, "Unsupported file format: %s", mUrl)); + String.format(Locale.US, "Unsupported file format: %s", mUrl)); } if (mIsNetworkUrl) { @@ -435,14 +445,19 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { throws IOException { Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize); - Thread thread = new Thread() { - @Override - public void run() { - mInstallationSession = - mDynSystem.createPartition( - partitionName, partitionSize, /* readOnly= */ false); - } - }; + mCreatePartitionStatus = 0; + mInstallationSession = null; + Thread thread = + new Thread() { + @Override + public void run() { + Pair<Integer, DynamicSystemManager.Session> result = + mDynSystem.createPartition( + partitionName, partitionSize, /* readOnly = */ false); + mCreatePartitionStatus = result.first; + mInstallationSession = result.second; + } + }; initPartitionProgress(partitionName, partitionSize, /* readonly = */ false); publishProgress(/* installedSize = */ 0L); @@ -468,13 +483,17 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } } - if (prevInstalledSize != partitionSize) { - publishProgress(partitionSize); - } - if (mInstallationSession == null) { - throw new IOException( - "Failed to start installation with requested size: " + partitionSize); + if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE + || mCreatePartitionStatus == IGsiService.INSTALL_ERROR_FILE_SYSTEM_CLUTTERED) { + throw new InsufficientSpaceException( + "Failed to create " + + partitionName + + " partition: storage media has insufficient free space"); + } else { + throw new IOException( + "Failed to start installation with requested size: " + partitionSize); + } } // Reset installation session and verify that installation completes successfully. @@ -482,6 +501,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { if (!mDynSystem.closePartition()) { throw new IOException("Failed to complete partition installation: " + partitionName); } + + // Ensure a 100% mark is published. + if (prevInstalledSize != partitionSize) { + publishProgress(partitionSize); + } } private void installScratch() throws IOException { @@ -606,10 +630,19 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { throw new IOException("Cannot get raw size for " + partitionName); } - Thread thread = new Thread(() -> { - mInstallationSession = - mDynSystem.createPartition(partitionName, partitionSize, true); - }); + mCreatePartitionStatus = 0; + mInstallationSession = null; + Thread thread = + new Thread() { + @Override + public void run() { + Pair<Integer, DynamicSystemManager.Session> result = + mDynSystem.createPartition( + partitionName, partitionSize, /* readOnly = */ true); + mCreatePartitionStatus = result.first; + mInstallationSession = result.second; + } + }; Log.d(TAG, "Start creating partition: " + partitionName); thread.start(); @@ -627,8 +660,16 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { } if (mInstallationSession == null) { - throw new IOException( - "Failed to start installation with requested size: " + partitionSize); + if (mCreatePartitionStatus == IGsiService.INSTALL_ERROR_NO_SPACE + || mCreatePartitionStatus == IGsiService.INSTALL_ERROR_FILE_SYSTEM_CLUTTERED) { + throw new InsufficientSpaceException( + "Failed to create " + + partitionName + + " partition: storage media has insufficient free space"); + } else { + throw new IOException( + "Failed to start installation with requested size: " + partitionSize); + } } Log.d(TAG, "Start installing: " + partitionName); @@ -688,11 +729,6 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { installedSize += numBytesRead; } - // Ensure a 100% mark is published. - if (prevInstalledSize != partitionSize) { - publishProgress(partitionSize); - } - AvbPublicKey avbPublicKey = new AvbPublicKey(); if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) { imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed")); @@ -708,6 +744,11 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { if (!mDynSystem.closePartition()) { throw new IOException("Failed to complete partition installation: " + partitionName); } + + // Ensure a 100% mark is published. + if (prevInstalledSize != partitionSize) { + publishProgress(partitionSize); + } } private static String toHexString(byte[] bytes) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index e9dea65c2078..d558336a1285 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -237,7 +237,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); Intent sharingIntent = new Intent(Intent.ACTION_SEND); - sharingIntent.setType("image/png"); + sharingIntent.setDataAndType(uri, "image/png"); sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); // Include URI in ClipData also, so that grantPermission picks it up. // We don't use setData here because some apps interpret this as "to:". diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index e924012c8892..99e12a8f9f55 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -119,14 +119,13 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { @Override @EnforcePermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - public boolean createPartition(String name, long size, boolean readOnly) - throws RemoteException { + public int createPartition(String name, long size, boolean readOnly) throws RemoteException { IGsiService service = getGsiService(); - if (service.createPartition(name, size, readOnly) != 0) { - Slog.i(TAG, "Failed to install " + name); - return false; + int status = service.createPartition(name, size, readOnly); + if (status != IGsiService.INSTALL_OK) { + Slog.i(TAG, "Failed to create partition: " + name); } - return true; + return status; } @Override diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 597f7f284730..be38005abb63 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -544,6 +544,7 @@ public class VcnGatewayConnection extends StateMachine { private final boolean mIsMobileDataEnabled; @NonNull private final IpSecManager mIpSecManager; + @NonNull private final ConnectivityManager mConnectivityManager; @Nullable private IpSecTunnelInterface mTunnelIface = null; @@ -701,6 +702,7 @@ public class VcnGatewayConnection extends StateMachine { mLastSnapshot, mUnderlyingNetworkControllerCallback); mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class); + mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); addState(mDisconnectedState); addState(mDisconnectingState); @@ -1683,6 +1685,14 @@ public class VcnGatewayConnection extends StateMachine { clearFailedAttemptCounterAndSafeModeAlarm(); break; case NetworkAgent.VALIDATION_STATUS_NOT_VALID: + // Trigger re-validation of underlying networks; if it + // fails, the VCN will attempt to migrate away. + if (mUnderlying != null) { + mConnectivityManager.reportNetworkConnectivity( + mUnderlying.network, + false /* hasConnectivity */); + } + // Will only set a new alarm if no safe mode alarm is // currently scheduled. setSafeModeAlarm(); @@ -1869,6 +1879,10 @@ public class VcnGatewayConnection extends StateMachine { IpSecManager.DIRECTION_OUT); updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig); + + // Trigger re-validation after migration events. + mConnectivityManager.reportNetworkConnectivity( + mNetworkAgent.getNetwork(), false /* hasConnectivity */); } private void handleUnderlyingNetworkChanged(@NonNull Message msg) { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index a5adf52051b9..b4825153bf0a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -11487,7 +11487,25 @@ public class TelephonyManager { if (SubscriptionManager.isValidPhoneId(phoneId)) { List<String> newList = updateTelephonyProperty( TelephonyProperties.operator_alpha(), phoneId, name); - TelephonyProperties.operator_alpha(newList); + try { + TelephonyProperties.operator_alpha(newList); + } catch (IllegalArgumentException e) { //property value is longer than the byte limit + Log.e(TAG, "setNetworkOperatorNameForPhone: ", e); + + int numberOfEntries = newList.size(); + int maxOperatorLength = //save 1 byte for joiner " , " + (SystemProperties.PROP_VALUE_MAX - numberOfEntries) / numberOfEntries; + + //examine and truncate every operator and retry + for (int i = 0; i < newList.size(); i++) { + if (newList.get(i) != null) { + newList.set(i, TextUtils + .truncateStringForUtf8Storage(newList.get(i), maxOperatorLength)); + } + } + TelephonyProperties.operator_alpha(newList); + Log.e(TAG, "successfully truncated operator_alpha: " + newList); + } } } diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 281b018b3395..b0ddf2c28dff 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -369,6 +369,10 @@ public class ApnSetting implements Parcelable { public @interface AuthType {} // Possible values for protocol which is defined in TS 27.007 section 10.1.1. + /** Unknown protocol. + * @hide + */ + public static final int PROTOCOL_UNKNOWN = -1; /** Internet protocol. */ public static final int PROTOCOL_IP = 0; /** Internet protocol, version 6. */ diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 883e2ad9b76e..7799113c5bf1 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2556,4 +2556,7 @@ interface ITelephony { * for the slot, or {@code null} if none is resolved */ String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex); + + /** Check if telephony new data stack is enabled. */ + boolean isUsingNewDataStack(); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 4cfa93b4ecf9..841b81c2a282 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -252,6 +252,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes()))); verify(mNetworkAgent) .setUnderlyingNetworks(eq(singletonList(TEST_UNDERLYING_NETWORK_RECORD_2.network))); + + // Verify revalidation is triggered on VCN network + verify(mConnMgr).reportNetworkConnectivity(eq(mNetworkAgent.getNetwork()), eq(false)); } private void triggerChildOpened() { @@ -425,6 +428,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); mTestLooper.dispatchAll(); + verify(mConnMgr) + .reportNetworkConnectivity(eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), eq(false)); + final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); verify(mDeps, times(2)) .newWakeupMessage( diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index be09545abb45..383be56bb227 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -349,7 +349,7 @@ Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDia const std::string root_dir = path.to_string(); std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir); if (!d) { - diag->Error(DiagMessage() << SystemErrorCodeToString(errno)); + diag->Error(DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir); return {}; } |