diff options
242 files changed, 4834 insertions, 2693 deletions
diff --git a/Android.bp b/Android.bp index 477f0272efa0..efe530798041 100644 --- a/Android.bp +++ b/Android.bp @@ -651,6 +651,7 @@ filegroup { "core/java/com/android/internal/util/Preconditions.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", + "core/java/com/android/internal/util/TrafficStatsConstants.java", "core/java/android/net/shared/Inet4AddressUtils.java", ], } diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp index 98bbe8243183..ec074262fb13 100644 --- a/apex/jobscheduler/framework/Android.bp +++ b/apex/jobscheduler/framework/Android.bp @@ -25,5 +25,6 @@ java_library { }, libs: [ "framework-minus-apex", + "unsupportedappusage", ], } diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 8b3b3a28f2bc..0bb07caf0b00 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -29,7 +29,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ComponentName; import android.net.NetworkRequest; diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index 42cf17b1264e..ef1351e6d597 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -18,8 +18,7 @@ package android.app.job; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.app.job.IJobCallback; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.net.Network; import android.net.Uri; diff --git a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java index c6631fa76494..0c45cbf6dc11 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobWorkItem.java @@ -19,7 +19,7 @@ package android.app.job; import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN; import android.annotation.BytesLong; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Build; import android.os.Parcel; diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java index c3dd3fe4451c..d059c670ccb6 100644 --- a/apex/media/framework/java/android/media/MediaController2.java +++ b/apex/media/framework/java/android/media/MediaController2.java @@ -141,6 +141,9 @@ public class MediaController2 implements AutoCloseable { // Note: unbindService() throws IllegalArgumentException when it's called twice. return; } + if (DEBUG) { + Log.d(TAG, "closing " + this); + } mClosed = true; if (mServiceConnection != null) { // Note: This should be called even when the bindService() has returned false. diff --git a/api/current.txt b/api/current.txt index a441841ba815..b673df0b5c90 100644 --- a/api/current.txt +++ b/api/current.txt @@ -9504,6 +9504,7 @@ package android.content { method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]); method @Nullable public final String getCallingFeatureId(); method @Nullable public final String getCallingPackage(); + method @Nullable public final String getCallingPackageUnchecked(); method @Nullable public final android.content.Context getContext(); method @Nullable public final android.content.pm.PathPermission[] getPathPermissions(); method @Nullable public final String getReadPermission(); @@ -9513,6 +9514,7 @@ package android.content { method @Nullable public abstract android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues); method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable android.os.Bundle); method protected boolean isTemporary(); + method public void onCallingPackageChanged(); method public void onConfigurationChanged(android.content.res.Configuration); method public abstract boolean onCreate(); method public void onLowMemory(); @@ -9627,13 +9629,13 @@ package android.content { ctor public ContentProviderResult(@NonNull android.net.Uri); ctor public ContentProviderResult(int); ctor public ContentProviderResult(@NonNull android.os.Bundle); - ctor public ContentProviderResult(@NonNull Exception); + ctor public ContentProviderResult(@NonNull Throwable); ctor public ContentProviderResult(android.os.Parcel); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR; field @Nullable public final Integer count; - field @Nullable public final Exception exception; + field @Nullable public final Throwable exception; field @Nullable public final android.os.Bundle extras; field @Nullable public final android.net.Uri uri; } @@ -13324,6 +13326,7 @@ package android.database.sqlite { method @Deprecated public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String[], String, String); method public int delete(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable String, @Nullable String[]); method @Nullable public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); + method @Nullable public java.util.Collection<java.util.regex.Pattern> getProjectionGreylist(); method @Nullable public java.util.Map<java.lang.String,java.lang.String> getProjectionMap(); method @Nullable public String getTables(); method public long insert(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues); @@ -13336,6 +13339,7 @@ package android.database.sqlite { method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String, android.os.CancellationSignal); method public void setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory); method public void setDistinct(boolean); + method public void setProjectionGreylist(@Nullable java.util.Collection<java.util.regex.Pattern>); method public void setProjectionMap(@Nullable java.util.Map<java.lang.String,java.lang.String>); method public void setStrict(boolean); method public void setStrictColumns(boolean); @@ -28685,6 +28689,7 @@ package android.media.tv { method public boolean isAudioDescription(); method public boolean isEncrypted(); method public boolean isHardOfHearing(); + method public boolean isSpokenSubtitle(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR; field public static final int TYPE_AUDIO = 0; // 0x0 @@ -28703,6 +28708,7 @@ package android.media.tv { method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean); method public android.media.tv.TvTrackInfo.Builder setLanguage(String); + method @NonNull public android.media.tv.TvTrackInfo.Builder setSpokenSubtitle(boolean); method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte); method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int); @@ -36387,15 +36393,22 @@ package android.os.storage { method public boolean isObbMounted(String); method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener); method @NonNull public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException; + method public void registerStorageVolumeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.storage.StorageManager.StorageVolumeCallback); method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException; method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException; method public boolean unmountObb(String, boolean, android.os.storage.OnObbStateChangeListener); + method public void unregisterStorageVolumeCallback(@NonNull android.os.storage.StorageManager.StorageVolumeCallback); field public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; field public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES"; field public static final String EXTRA_UUID = "android.os.storage.extra.UUID"; field public static final java.util.UUID UUID_DEFAULT; } + public static class StorageManager.StorageVolumeCallback { + ctor public StorageManager.StorageVolumeCallback(); + method public void onStateChanged(@NonNull android.os.storage.StorageVolume); + } + public final class StorageVolume implements android.os.Parcelable { method @Deprecated @Nullable public android.content.Intent createAccessIntent(String); method @NonNull public android.content.Intent createOpenDocumentTreeIntent(); @@ -45703,6 +45716,7 @@ package android.telephony { method public String getOperatorNumeric(); method public boolean getRoaming(); method public int getState(); + method public boolean isSearching(); method public void setIsManualSelection(boolean); method public void setOperatorName(String, String, String); method public void setRoaming(boolean); @@ -45961,6 +45975,7 @@ package android.telephony { public class SubscriptionManager { method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); + method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); method public boolean canManageSubscription(android.telephony.SubscriptionInfo); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>); diff --git a/api/system-current.txt b/api/system-current.txt index 4f262618c48e..384dc13ff567 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -567,6 +567,7 @@ package android.app { } public class DownloadManager { + method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public void onMediaStoreDownloadsDeleted(@NonNull android.util.LongSparseArray<java.lang.String>); field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED"; } @@ -1654,11 +1655,17 @@ package android.content { method @NonNull public final android.os.UserHandle getSendingUser(); } + public abstract class ContentProvider implements android.content.ComponentCallbacks2 { + method public int checkUriPermission(@NonNull android.net.Uri, int, int); + } + public class ContentProviderClient implements java.lang.AutoCloseable { method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long); } public abstract class ContentResolver { + method @NonNull public static android.net.Uri decodeFromFile(@NonNull java.io.File); + method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri); method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri); method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle); } @@ -3581,9 +3588,17 @@ package android.hardware.usb { } public class UsbManager { + method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions(); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts(); method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String); + method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long); field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED"; + field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; + field public static final long FUNCTION_NONE = 0L; // 0x0L + field public static final long FUNCTION_RNDIS = 32L; // 0x20L + field public static final String USB_CONFIGURED = "configured"; + field public static final String USB_CONNECTED = "connected"; + field public static final String USB_FUNCTION_RNDIS = "rndis"; } public final class UsbPort { @@ -4680,6 +4695,7 @@ package android.net { method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl(); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi(); @@ -4687,6 +4703,7 @@ package android.net { method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; @@ -4857,6 +4874,17 @@ package android.net { field public final android.net.WifiKey wifiKey; } + public class NetworkProvider { + ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String); + method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest); + method @Nullable public android.os.Messenger getMessenger(); + method @NonNull public String getName(); + method public int getProviderId(); + method public void onNetworkRequested(@NonNull android.net.NetworkRequest, int, int); + method public void onRequestWithdrawn(@NonNull android.net.NetworkRequest); + field public static final int ID_NONE = -1; // 0xffffffff + } + public abstract class NetworkRecommendationProvider { ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor); method public final android.os.IBinder getBinder(); @@ -4900,6 +4928,33 @@ package android.net { field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK"; } + public final class NetworkStats implements android.os.Parcelable { + ctor public NetworkStats(long, int); + method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats); + method @NonNull public android.net.NetworkStats addValues(@NonNull android.net.NetworkStats.Entry); + method public int describeContents(); + method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR; + field public static final int DEFAULT_NETWORK_NO = 0; // 0x0 + field public static final int DEFAULT_NETWORK_YES = 1; // 0x1 + field @Nullable public static final String IFACE_ALL; + field public static final String IFACE_VT = "vt_data0"; + field public static final int METERED_NO = 0; // 0x0 + field public static final int METERED_YES = 1; // 0x1 + field public static final int ROAMING_NO = 0; // 0x0 + field public static final int ROAMING_YES = 1; // 0x1 + field public static final int SET_DEFAULT = 0; // 0x0 + field public static final int SET_FOREGROUND = 1; // 0x1 + field public static final int TAG_NONE = 0; // 0x0 + field public static final int UID_ALL = -1; // 0xffffffff + field public static final int UID_TETHERING = -5; // 0xfffffffb + } + + public static class NetworkStats.Entry { + ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long); + } + public final class RouteInfo implements android.os.Parcelable { ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int); method public int getType(); @@ -5491,6 +5546,25 @@ package android.net.metrics { } +package android.net.netstats.provider { + + public abstract class AbstractNetworkStatsProvider { + ctor public AbstractNetworkStatsProvider(); + method public abstract void requestStatsUpdate(int); + method public abstract void setAlert(long); + method public abstract void setLimit(@NonNull String, long); + field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff + } + + public class NetworkStatsProviderCallback { + method public void onAlertReached(); + method public void onLimitReached(); + method public void onStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); + method public void unregister(); + } + +} + package android.net.util { public final class SocketUtils { @@ -6966,6 +7040,10 @@ package android.os { method public boolean hasSingleFileDescriptor(); } + public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable { + method @NonNull public static android.os.ParcelFileDescriptor wrap(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.Handler, @NonNull android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException; + } + public final class PowerManager { method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long); method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend(); @@ -7369,6 +7447,10 @@ package android.os.storage { field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 } + public final class StorageVolume implements android.os.Parcelable { + method @NonNull public String getId(); + } + } package android.permission { @@ -7788,6 +7870,7 @@ package android.provider { field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS"; field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; + field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; } public static final class Settings.Global extends android.provider.Settings.NameValueTable { @@ -7807,6 +7890,7 @@ package android.provider { field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis"; field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt"; + field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; field public static final String TETHER_SUPPORTED = "tether_supported"; field public static final String THEATER_MODE_ON = "theater_mode_on"; field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; diff --git a/api/test-current.txt b/api/test-current.txt index e64cbdb6eb10..d017dd63bdd3 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2552,6 +2552,7 @@ package android.provider { field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION"; field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE"; + field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1 } @@ -2570,6 +2571,7 @@ package android.provider { field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky"; field public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; + field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package"; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index a4f6f57c097e..b82a67556fc0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3349,8 +3349,8 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStartActivity(ActivityClientRecord r, - PendingTransactionActions pendingActions) { + public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) { + final ActivityClientRecord r = mActivities.get(token); final Activity activity = r.activity; if (r.activity == null) { // TODO(lifecycler): What do we do in this case? @@ -3364,6 +3364,8 @@ public final class ActivityThread extends ClientTransactionHandler { return; } + unscheduleGcIdler(); + // Start activity.performStart("handleStartActivity"); r.setState(ON_START); @@ -3400,6 +3402,9 @@ public final class ActivityThread extends ClientTransactionHandler { + " did not call through to super.onPostCreate()"); } } + + updateVisibility(r, true /* show */); + mSomeActivitiesChanged = true; } /** @@ -4660,8 +4665,8 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage final void performStopActivity(IBinder token, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); - performStopActivityInner(r, null /* stopInfo */, false /* keepShown */, saveState, - false /* finalStateRequest */, reason); + performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */, + reason); } private static final class ProviderRefCount { @@ -4687,25 +4692,19 @@ public final class ActivityThread extends ClientTransactionHandler { } /** - * Core implementation of stopping an activity. Note this is a little - * tricky because the server's meaning of stop is slightly different - * than our client -- for the server, stop means to save state and give - * it the result when it is done, but the window may still be visible. - * For the client, we want to call onStop()/onStart() to indicate when - * the activity's UI visibility changes. + * Core implementation of stopping an activity. * @param r Target activity client record. * @param info Action that will report activity stop to server. - * @param keepShown Flag indicating whether the activity is still shown. * @param saveState Flag indicating whether the activity state should be saved. * @param finalStateRequest Flag indicating if this call is handling final lifecycle state * request for a transaction. * @param reason Reason for performing this operation. */ - private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, + private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean saveState, boolean finalStateRequest, String reason) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); if (r != null) { - if (!keepShown && r.stopped) { + if (r.stopped) { if (r.activity.mFinished) { // If we are finishing, we won't call onResume() in certain // cases. So here we likewise don't want to call onStop() @@ -4740,9 +4739,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } - if (!keepShown) { - callActivityOnStop(r, saveState, reason); - } + callActivityOnStop(r, saveState, reason); } } @@ -4810,20 +4807,19 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStopActivity(IBinder token, boolean show, int configChanges, + public void handleStopActivity(IBinder token, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) { final ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; final StopInfo stopInfo = new StopInfo(); - performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest, + performStopActivityInner(r, stopInfo, true /* saveState */, finalStateRequest, reason); if (localLOGV) Slog.v( - TAG, "Finishing stop of " + r + ": show=" + show - + " win=" + r.window); + TAG, "Finishing stop of " + r + ": win=" + r.window); - updateVisibility(r, show); + updateVisibility(r, false); // Make sure any pending writes are now committed. if (!r.isPreHoneycomb()) { @@ -4859,34 +4855,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - @Override - public void handleWindowVisibility(IBinder token, boolean show) { - ActivityClientRecord r = mActivities.get(token); - - if (r == null) { - Log.w(TAG, "handleWindowVisibility: no activity for token " + token); - return; - } - - if (!show && !r.stopped) { - performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */, - false /* finalStateRequest */, "handleWindowVisibility"); - } else if (show && r.getLifecycleState() == ON_STOP) { - // If we are getting ready to gc after going to the background, well - // we are back active so skip it. - unscheduleGcIdler(); - - r.activity.performRestart(true /* start */, "handleWindowVisibility"); - r.setState(ON_START); - } - if (r.activity.mDecor != null) { - if (false) Slog.v( - TAG, "Handle window " + r + " visibility: " + show); - updateVisibility(r, show); - } - mSomeActivitiesChanged = true; - } - // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to // stop operation on the activity to reduce code duplication and the chance of fixing a bug in // one place and missing the other. diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index f9a689a7e1de..d2235f10da99 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -119,7 +119,6 @@ public abstract class ClientTransactionHandler { /** * Stop the activity. * @param token Target activity token. - * @param show Flag indicating whether activity is still shown. * @param configChanges Activity configuration changes. * @param pendingActions Pending actions to be used on this or later stages of activity * transaction. @@ -127,7 +126,7 @@ public abstract class ClientTransactionHandler { * request for a transaction. * @param reason Reason for performing this operation. */ - public abstract void handleStopActivity(IBinder token, boolean show, int configChanges, + public abstract void handleStopActivity(IBinder token, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason); /** Report that activity was stopped to server. */ @@ -161,15 +160,12 @@ public abstract class ClientTransactionHandler { /** Request that an activity enter picture-in-picture. */ public abstract void handlePictureInPictureRequested(IBinder token); - /** Update window visibility. */ - public abstract void handleWindowVisibility(IBinder token, boolean show); - /** Perform activity launch. */ public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent); /** Perform activity start. */ - public abstract void handleStartActivity(ActivityThread.ActivityClientRecord r, + public abstract void handleStartActivity(IBinder token, PendingTransactionActions pendingActions); /** Get package info. */ diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 49c389a0c4a7..1278ff6817fd 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -16,7 +16,9 @@ package android.app; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -40,11 +42,13 @@ import android.os.Environment; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.provider.BaseColumns; import android.provider.Downloads; import android.provider.MediaStore; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; +import android.util.LongSparseArray; import android.util.Pair; import java.io.File; @@ -1069,6 +1073,37 @@ public class DownloadManager { } /** + * Notify {@link DownloadManager} that the given {@link MediaStore} items + * were just deleted so that {@link DownloadManager} internal data + * structures can be cleaned up. + * + * @param idToMime map from {@link BaseColumns#_ID} to + * {@link ContentResolver#getType(Uri)}. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) + public void onMediaStoreDownloadsDeleted(@NonNull LongSparseArray<String> idToMime) { + try (ContentProviderClient client = mResolver + .acquireUnstableContentProviderClient(mBaseUri)) { + final Bundle callExtras = new Bundle(); + final long[] ids = new long[idToMime.size()]; + final String[] mimeTypes = new String[idToMime.size()]; + for (int i = idToMime.size() - 1; i >= 0; --i) { + ids[i] = idToMime.keyAt(i); + mimeTypes[i] = idToMime.valueAt(i); + } + callExtras.putLongArray(android.provider.Downloads.EXTRA_IDS, ids); + callExtras.putStringArray(android.provider.Downloads.EXTRA_MIME_TYPES, + mimeTypes); + client.call(android.provider.Downloads.CALL_MEDIASTORE_DOWNLOADS_DELETED, + null, callExtras); + } catch (RemoteException e) { + // Should not happen + } + } + + /** * Enqueue a new download. The download will start automatically once the download manager is * ready to execute it and connectivity is available. * diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 4033aea32b55..7cdf85e0a6b8 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -177,7 +177,7 @@ public class LocalActivityManager { pendingActions = null; } - mActivityThread.handleStartActivity(clientRecord, pendingActions); + mActivityThread.handleStartActivity(r, pendingActions); r.curState = STARTED; if (desiredState == RESUMED) { diff --git a/core/java/android/app/servertransaction/WindowVisibilityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java index 115d1ececc0e..4fbe02b9cf76 100644 --- a/core/java/android/app/servertransaction/WindowVisibilityItem.java +++ b/core/java/android/app/servertransaction/StartActivityItem.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 The Android Open Source Project + * Copyright 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. @@ -24,41 +24,44 @@ import android.os.Parcel; import android.os.Trace; /** - * Window visibility change message. + * Request to move an activity to started and visible state. * @hide */ -public class WindowVisibilityItem extends ClientTransactionItem { +public class StartActivityItem extends ActivityLifecycleItem { - private boolean mShowWindow; + private static final String TAG = "StartActivityItem"; @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, - mShowWindow ? "activityShowWindow" : "activityHideWindow"); - client.handleWindowVisibility(token, mShowWindow); + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem"); + client.handleStartActivity(token, pendingActions); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } + @Override + public int getTargetState() { + return ON_START; + } + // ObjectPoolItem implementation - private WindowVisibilityItem() {} + private StartActivityItem() {} /** Obtain an instance initialized with provided params. */ - public static WindowVisibilityItem obtain(boolean showWindow) { - WindowVisibilityItem instance = ObjectPool.obtain(WindowVisibilityItem.class); + public static StartActivityItem obtain() { + StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class); if (instance == null) { - instance = new WindowVisibilityItem(); + instance = new StartActivityItem(); } - instance.mShowWindow = showWindow; return instance; } @Override public void recycle() { - mShowWindow = false; + super.recycle(); ObjectPool.recycle(this); } @@ -68,24 +71,24 @@ public class WindowVisibilityItem extends ClientTransactionItem { /** Write to Parcel. */ @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeBoolean(mShowWindow); + // Empty } /** Read from Parcel. */ - private WindowVisibilityItem(Parcel in) { - mShowWindow = in.readBoolean(); + private StartActivityItem(Parcel in) { + // Empty } - public static final @android.annotation.NonNull Creator<WindowVisibilityItem> CREATOR = - new Creator<WindowVisibilityItem>() { - public WindowVisibilityItem createFromParcel(Parcel in) { - return new WindowVisibilityItem(in); - } + public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR = + new Creator<StartActivityItem>() { + public StartActivityItem createFromParcel(Parcel in) { + return new StartActivityItem(in); + } - public WindowVisibilityItem[] newArray(int size) { - return new WindowVisibilityItem[size]; - } - }; + public StartActivityItem[] newArray(int size) { + return new StartActivityItem[size]; + } + }; @Override public boolean equals(Object o) { @@ -95,17 +98,17 @@ public class WindowVisibilityItem extends ClientTransactionItem { if (o == null || getClass() != o.getClass()) { return false; } - final WindowVisibilityItem other = (WindowVisibilityItem) o; - return mShowWindow == other.mShowWindow; + return true; } @Override public int hashCode() { - return 17 + 31 * (mShowWindow ? 1 : 0); + return 17; } @Override public String toString() { - return "WindowVisibilityItem{showWindow=" + mShowWindow + "}"; + return "StartActivityItem{}"; } } + diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java index 63efa6fe7c17..8668bd49c8f5 100644 --- a/core/java/android/app/servertransaction/StopActivityItem.java +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -31,14 +31,13 @@ public class StopActivityItem extends ActivityLifecycleItem { private static final String TAG = "StopActivityItem"; - private boolean mShowWindow; private int mConfigChanges; @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); - client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions, + client.handleStopActivity(token, mConfigChanges, pendingActions, true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -59,13 +58,15 @@ public class StopActivityItem extends ActivityLifecycleItem { private StopActivityItem() {} - /** Obtain an instance initialized with provided params. */ - public static StopActivityItem obtain(boolean showWindow, int configChanges) { + /** + * Obtain an instance initialized with provided params. + * @param configChanges Configuration pieces that changed. + */ + public static StopActivityItem obtain(int configChanges) { StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class); if (instance == null) { instance = new StopActivityItem(); } - instance.mShowWindow = showWindow; instance.mConfigChanges = configChanges; return instance; @@ -74,7 +75,6 @@ public class StopActivityItem extends ActivityLifecycleItem { @Override public void recycle() { super.recycle(); - mShowWindow = false; mConfigChanges = 0; ObjectPool.recycle(this); } @@ -85,13 +85,11 @@ public class StopActivityItem extends ActivityLifecycleItem { /** Write to Parcel. */ @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeBoolean(mShowWindow); dest.writeInt(mConfigChanges); } /** Read from Parcel. */ private StopActivityItem(Parcel in) { - mShowWindow = in.readBoolean(); mConfigChanges = in.readInt(); } @@ -115,20 +113,18 @@ public class StopActivityItem extends ActivityLifecycleItem { return false; } final StopActivityItem other = (StopActivityItem) o; - return mShowWindow == other.mShowWindow && mConfigChanges == other.mConfigChanges; + return mConfigChanges == other.mConfigChanges; } @Override public int hashCode() { int result = 17; - result = 31 * result + (mShowWindow ? 1 : 0); result = 31 * result + mConfigChanges; return result; } @Override public String toString() { - return "StopActivityItem{showWindow=" + mShowWindow + ",configChanges=" + mConfigChanges - + "}"; + return "StopActivityItem{configChanges=" + mConfigChanges + "}"; } } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 20e0da3ead8a..17fcda587322 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -218,7 +218,7 @@ public class TransactionExecutor { null /* customIntent */); break; case ON_START: - mTransactionHandler.handleStartActivity(r, mPendingActions); + mTransactionHandler.handleStartActivity(r.token, mPendingActions); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, @@ -230,8 +230,8 @@ public class TransactionExecutor { "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: - mTransactionHandler.handleStopActivity(r.token, false /* show */, - 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, + mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */, + mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index 0ea8c3c159fa..6df92a78cc9f 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -183,8 +183,7 @@ public class TransactionExecutorHelper { lifecycleItem = PauseActivityItem.obtain(); break; case ON_STOP: - lifecycleItem = StopActivityItem.obtain(r.isVisibleFromServer(), - 0 /* configChanges */); + lifecycleItem = StopActivityItem.obtain(0 /* configChanges */); break; default: lifecycleItem = ResumeActivityItem.obtain(false /* isForward */); diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 393d48891d64..85826fd4e669 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -27,6 +27,7 @@ import static android.os.Trace.TRACE_TAG_DATABASE; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.AppOpsManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageManager; @@ -942,7 +943,18 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return null; } - /** {@hide} */ + /** + * Return the package name of the caller that initiated the request being + * processed on the current thread. The returned package will have + * <em>not</em> been verified to belong to the calling UID. Returns + * {@code null} if not currently processing a request. + * <p> + * This will always return {@code null} when processing + * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests. + * + * @see Binder#getCallingUid() + * @see Context#grantUriPermission(String, Uri, int) + */ public final @Nullable String getCallingPackageUnchecked() { final Pair<String, String> pkg = mCallingPackage.get(); if (pkg != null) { @@ -952,7 +964,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return null; } - /** {@hide} */ + /** + * Called whenever the value of {@link #getCallingPackage()} changes, giving + * the provider an opportunity to invalidate any security related caching it + * may be performing. + * <p> + * This typically happens when a {@link ContentProvider} makes a nested call + * back into itself when already processing a call from a remote process. + */ public void onCallingPackageChanged() { } @@ -1390,8 +1409,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * @param uri The URI to query. This will be the full URI sent by the client. * @param projection The list of columns to put into the cursor. * If {@code null} provide a default set of columns. - * @param queryArgs A Bundle containing all additional information necessary for the query. - * Values in the Bundle may include SQL style arguments. + * @param queryArgs A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @param cancellationSignal A signal to cancel the operation in progress, * or {@code null}. * @return a Cursor or {@code null}. @@ -1525,8 +1547,24 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return false; } - /** {@hide} */ + /** + * Perform a detailed internal check on a {@link Uri} to determine if a UID + * is able to access it with specific mode flags. + * <p> + * This method is typically used when the provider implements more dynamic + * access controls that cannot be expressed with {@code <path-permission>} + * style static rules. + * + * @param uri the {@link Uri} to perform an access check on. + * @param uid the UID to check the permission for. + * @param modeFlags the access flags to use for the access check, such as + * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}. + * @return {@link PackageManager#PERMISSION_GRANTED} if access is allowed, + * otherwise {@link PackageManager#PERMISSION_DENIED}. + * @hide + */ @Override + @SystemApi public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) { return PackageManager.PERMISSION_DENIED; } @@ -1574,9 +1612,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * * @param uri The content:// URI of the insertion request. * @param values A set of column_name/value pairs to add to the database. - * @param extras A Bundle containing all additional information necessary - * for the insert. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @return The URI for the newly inserted item. + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. */ @Override public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values, @@ -1653,10 +1696,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * * @param uri The full URI to query, including a row ID (if a specific * record is requested). - * @param extras A Bundle containing all additional information necessary - * for the delete. Values in the Bundle may include SQL style - * arguments. - * @return The number of rows affected. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. * @throws SQLException */ @Override @@ -1699,10 +1745,14 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * @param uri The URI to query. This can potentially have a record ID if * this is an update request for a specific record. * @param values A set of column_name/value pairs to update in the database. - * @param extras A Bundle containing all additional information necessary - * for the update. Values in the Bundle may include SQL style - * arguments. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @return the number of rows affected. + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. */ @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 93f42879d946..494d2aeaf42a 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -18,7 +18,7 @@ package android.content; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index 11dda83a6e6c..4fb1ddb958d5 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -36,7 +36,7 @@ public class ContentProviderResult implements Parcelable { public final @Nullable Uri uri; public final @Nullable Integer count; public final @Nullable Bundle extras; - public final @Nullable Exception exception; + public final @Nullable Throwable exception; public ContentProviderResult(@NonNull Uri uri) { this(Objects.requireNonNull(uri), null, null, null); @@ -50,12 +50,12 @@ public class ContentProviderResult implements Parcelable { this(null, null, Objects.requireNonNull(extras), null); } - public ContentProviderResult(@NonNull Exception exception) { + public ContentProviderResult(@NonNull Throwable exception) { this(null, null, null, exception); } /** {@hide} */ - public ContentProviderResult(Uri uri, Integer count, Bundle extras, Exception exception) { + public ContentProviderResult(Uri uri, Integer count, Bundle extras, Throwable exception) { this.uri = uri; this.count = count; this.extras = extras; @@ -79,7 +79,7 @@ public class ContentProviderResult implements Parcelable { extras = null; } if (source.readInt() != 0) { - exception = (Exception) ParcelableException.readFromParcel(source); + exception = ParcelableException.readFromParcel(source); } else { exception = null; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 1d3c6505f677..6cd1cd3354c2 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -984,7 +984,11 @@ public abstract class ContentResolver implements ContentInterface { * retrieve. * @param projection A list of which columns to return. Passing null will * return all columns, which is inefficient. - * @param queryArgs A Bundle containing any arguments to the query. + * @param queryArgs A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @param cancellationSignal A signal to cancel the operation in progress, or null if none. * If the operation is canceled, then {@link OperationCanceledException} will be thrown * when the query is executed. @@ -1925,9 +1929,15 @@ public abstract class ContentResolver implements ContentInterface { * @param url The URL of the table to insert into. * @param values The initial values for the newly inserted row. The key is the column name for * the field. Passing an empty ContentValues will create an empty row. - * @param extras A Bundle containing all additional information necessary for the insert. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @return the URL of the newly created row. May return <code>null</code> if the underlying * content provider returns <code>null</code>, or if it crashes. + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. */ @Override public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, @@ -2061,9 +2071,14 @@ public abstract class ContentResolver implements ContentInterface { * If the content provider supports transactions, the deletion will be atomic. * * @param url The URL of the row to delete. - * @param extras A Bundle containing all additional information necessary for the delete. - * Values in the Bundle may include SQL style arguments. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @return The number of rows deleted. + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. */ @Override public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable Bundle extras) { @@ -2121,10 +2136,15 @@ public abstract class ContentResolver implements ContentInterface { * @param uri The URI to modify. * @param values The new field values. The key is the column name for the field. A null value will remove an existing field value. - * @param extras A Bundle containing all additional information necessary for the update. - * Values in the Bundle may include SQL style arguments. + * @param extras A Bundle containing additional information necessary for + * the operation. Arguments may include SQL style arguments, such + * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that + * the documentation for each individual provider will indicate + * which arguments they support. * @return the number of rows updated. * @throws NullPointerException if uri or values are null + * @throws IllegalArgumentException if the provider doesn't support one of + * the requested Bundle arguments. */ @Override public final int update(@RequiresPermission.Write @NonNull Uri uri, @@ -3851,15 +3871,47 @@ public abstract class ContentResolver implements ContentInterface { } } + /** + * Decode a path generated by {@link #encodeToFile(Uri)} back into + * the original {@link Uri}. + * <p> + * This is used to offer a way to intercept filesystem calls in + * {@link ContentProvider} unaware code and redirect them to a + * {@link ContentProvider} when they attempt to use {@code _DATA} columns + * that are otherwise deprecated. + * + * @hide + */ + @SystemApi + public static @NonNull Uri decodeFromFile(@NonNull File file) { + return translateDeprecatedDataPath(file.getAbsolutePath()); + } + + /** + * Encode a {@link Uri} into an opaque filesystem path which can then be + * resurrected by {@link #decodeFromFile(File)}. + * <p> + * This is used to offer a way to intercept filesystem calls in + * {@link ContentProvider} unaware code and redirect them to a + * {@link ContentProvider} when they attempt to use {@code _DATA} columns + * that are otherwise deprecated. + * + * @hide + */ + @SystemApi + public static @NonNull File encodeToFile(@NonNull Uri uri) { + return new File(translateDeprecatedDataPath(uri)); + } + /** {@hide} */ - public static Uri translateDeprecatedDataPath(String path) { + public static @NonNull Uri translateDeprecatedDataPath(@NonNull String path) { final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length()); return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT) .encodedOpaquePart(ssp).build().toString()); } /** {@hide} */ - public static String translateDeprecatedDataPath(Uri uri) { + public static @NonNull String translateDeprecatedDataPath(@NonNull Uri uri) { return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2); } } diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index ac2e373f000d..6639b3d5c0b5 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -18,7 +18,7 @@ package android.content.pm.parsing; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java index 595685729a0c..f04a30ce4239 100644 --- a/core/java/android/content/pm/parsing/ComponentParseUtils.java +++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java @@ -27,8 +27,8 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityTaskManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index bba14c39de72..36ec67ee1471 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -35,8 +35,8 @@ import com.android.internal.util.ArrayUtils; import libcore.util.EmptyArray; import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; @@ -56,7 +56,7 @@ public class SQLiteQueryBuilder { "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)"); private Map<String, String> mProjectionMap = null; - private List<Pattern> mProjectionGreylist = null; + private Collection<Pattern> mProjectionGreylist = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private String mTables = ""; @@ -196,20 +196,16 @@ public class SQLiteQueryBuilder { * Sets a projection greylist of columns that will be allowed through, even * when {@link #setStrict(boolean)} is enabled. This provides a way for * abusive custom columns like {@code COUNT(*)} to continue working. - * - * @hide */ - public void setProjectionGreylist(@Nullable List<Pattern> projectionGreylist) { + public void setProjectionGreylist(@Nullable Collection<Pattern> projectionGreylist) { mProjectionGreylist = projectionGreylist; } /** * Gets the projection greylist for the query, as last configured by - * {@link #setProjectionGreylist(List)}. - * - * @hide + * {@link #setProjectionGreylist}. */ - public @Nullable List<Pattern> getProjectionGreylist() { + public @Nullable Collection<Pattern> getProjectionGreylist() { return mProjectionGreylist; } @@ -244,25 +240,27 @@ public class SQLiteQueryBuilder { } /** - * When set, the selection is verified against malicious arguments. - * When using this class to create a statement using + * When set, the selection is verified against malicious arguments. When + * using this class to create a statement using * {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)}, - * non-numeric limits will raise an exception. If a projection map is specified, fields - * not in that map will be ignored. - * If this class is used to execute the statement directly using + * non-numeric limits will raise an exception. If a projection map is + * specified, fields not in that map will be ignored. If this class is used + * to execute the statement directly using * {@link #query(SQLiteDatabase, String[], String, String[], String, String, String)} * or * {@link #query(SQLiteDatabase, String[], String, String[], String, String, String, String)}, - * additionally also parenthesis escaping selection are caught. - * - * To summarize: To get maximum protection against malicious third party apps (for example - * content provider consumers), make sure to do the following: + * additionally also parenthesis escaping selection are caught. To + * summarize: To get maximum protection against malicious third party apps + * (for example content provider consumers), make sure to do the following: * <ul> * <li>Set this value to true</li> * <li>Use a projection map</li> - * <li>Use one of the query overloads instead of getting the statement as a sql string</li> + * <li>Use one of the query overloads instead of getting the statement as a + * sql string</li> * </ul> - * By default, this value is false. + * <p> + * This feature is disabled by default on each newly constructed + * {@link SQLiteQueryBuilder} and needs to be manually enabled. */ public void setStrict(boolean strict) { if (strict) { @@ -287,6 +285,9 @@ public class SQLiteQueryBuilder { * This enforcement applies to {@link #insert}, {@link #query}, and * {@link #update} operations. Any enforcement failures will throw an * {@link IllegalArgumentException}. + * <p> + * This feature is disabled by default on each newly constructed + * {@link SQLiteQueryBuilder} and needs to be manually enabled. */ public void setStrictColumns(boolean strictColumns) { if (strictColumns) { @@ -323,6 +324,9 @@ public class SQLiteQueryBuilder { * {@link #delete} operations. This enforcement does not apply to trusted * inputs, such as those provided by {@link #appendWhere}. Any enforcement * failures will throw an {@link IllegalArgumentException}. + * <p> + * This feature is disabled by default on each newly constructed + * {@link SQLiteQueryBuilder} and needs to be manually enabled. */ public void setStrictGrammar(boolean strictGrammar) { if (strictGrammar) { diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 638d81b2f635..6e1987c47d20 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -90,4 +90,11 @@ interface IInputManager { /** Create an input monitor for gestures. */ InputMonitor monitorGestureInput(String name, int displayId); + + // Add a runtime association between the input port and the display port. This overrides any + // static associations. + void addPortAssociation(in String inputPort, int displayPort); + // Remove the runtime association between the input port and the display port. Any existing + // static association for the cleared input port will be restored. + void removePortAssociation(in String inputPort); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 8d32db013fb3..83f01a5dca35 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -17,6 +17,7 @@ package android.hardware.input; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -963,6 +964,41 @@ public final class InputManager { } } + /** + * Add a runtime association between the input port and the display port. This overrides any + * static associations. + * @param inputPort The port of the input device. + * @param displayPort The physical port of the associated display. + * <p> + * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT}. + * </p> + * @hide + */ + public void addPortAssociation(@NonNull String inputPort, int displayPort) { + try { + mIm.addPortAssociation(inputPort, displayPort); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Remove the runtime association between the input port and the display port. Any existing + * static association for the cleared input port will be restored. + * @param inputPort The port of the input device to be cleared. + * <p> + * Requires {@link android.Manifest.permissions.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT}. + * </p> + * @hide + */ + public void removePortAssociation(@NonNull String inputPort) { + try { + mIm.removePortAssociation(inputPort); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + private void populateInputDevicesLocked() { if (mInputDevicesChangedListener == null) { final InputDevicesChangedListener listener = new InputDevicesChangedListener(); diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 73b9d1739061..67fdda37ed3b 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -91,7 +91,7 @@ public class UsbManager { * * {@hide} */ - @UnsupportedAppUsage + @SystemApi public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; @@ -164,7 +164,7 @@ public class UsbManager { * * {@hide} */ - @UnsupportedAppUsage + @SystemApi public static final String USB_CONNECTED = "connected"; /** @@ -181,6 +181,7 @@ public class UsbManager { * * {@hide} */ + @SystemApi public static final String USB_CONFIGURED = "configured"; /** @@ -217,6 +218,7 @@ public class UsbManager { * * {@hide} */ + @SystemApi public static final String USB_FUNCTION_RNDIS = "rndis"; /** @@ -319,6 +321,7 @@ public class UsbManager { * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_NONE = 0; /** @@ -337,6 +340,7 @@ public class UsbManager { * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)} * {@hide} */ + @SystemApi public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS; /** @@ -698,6 +702,8 @@ public class UsbManager { * * {@hide} */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long functions) { try { mService.setCurrentFunctions(functions); @@ -737,6 +743,8 @@ public class UsbManager { * * {@hide} */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_USB) public long getCurrentFunctions() { try { return mService.getCurrentFunctions(); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6da16a82c822..03d4200bd90f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -363,7 +363,7 @@ public class ConnectivityManager { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @UnsupportedAppUsage public static final String ACTION_TETHER_STATE_CHANGED = - "android.net.conn.TETHER_STATE_CHANGED"; + TetheringManager.ACTION_TETHER_STATE_CHANGED; /** * @hide @@ -371,14 +371,14 @@ public class ConnectivityManager { * tethering and currently available for tethering. */ @UnsupportedAppUsage - public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER; /** * @hide * gives a String[] listing all the interfaces currently in local-only * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) */ - public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; /** * @hide @@ -386,7 +386,7 @@ public class ConnectivityManager { * (ie, has DHCPv4 support and packets potentially forwarded/NATed) */ @UnsupportedAppUsage - public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER; /** * @hide @@ -395,7 +395,7 @@ public class ConnectivityManager { * for any interfaces listed here. */ @UnsupportedAppUsage - public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER; /** * Broadcast Action: The captive portal tracker has finished its test. @@ -445,7 +445,7 @@ public class ConnectivityManager { * @see #startTethering(int, boolean, OnStartTetheringCallback) * @hide */ - public static final int TETHERING_INVALID = -1; + public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID; /** * Wifi tethering type. @@ -453,7 +453,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_WIFI = 0; + public static final int TETHERING_WIFI = TetheringManager.TETHERING_WIFI; /** * USB tethering type. @@ -461,7 +461,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_USB = 1; + public static final int TETHERING_USB = TetheringManager.TETHERING_USB; /** * Bluetooth tethering type. @@ -469,7 +469,7 @@ public class ConnectivityManager { * @hide */ @SystemApi - public static final int TETHERING_BLUETOOTH = 2; + public static final int TETHERING_BLUETOOTH = TetheringManager.TETHERING_BLUETOOTH; /** * Wifi P2p tethering type. @@ -477,41 +477,41 @@ public class ConnectivityManager { * need to start from #startTethering(int, boolean, OnStartTetheringCallback). * @hide */ - public static final int TETHERING_WIFI_P2P = 3; + public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P; /** * Extra used for communicating with the TetherService. Includes the type of tethering to * enable if any. * @hide */ - public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE; /** * Extra used for communicating with the TetherService. Includes the type of tethering for * which to cancel provisioning. * @hide */ - public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE; /** * Extra used for communicating with the TetherService. True to schedule a recheck of tether * provisioning. * @hide */ - public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM; /** * Tells the TetherService to run a provision check now. * @hide */ - public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION; /** * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} * which will receive provisioning results. Can be left empty. * @hide */ - public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK; /** * The absence of a connection type. @@ -3107,6 +3107,63 @@ public class ConnectivityManager { } } + /** + * Registers the specified {@link NetworkProvider}. + * Each listener must only be registered once. The listener can be unregistered with + * {@link #unregisterNetworkProvider}. + * + * @param provider the provider to register + * @return the ID of the provider. This ID must be used by the provider when registering + * {@link android.net.NetworkAgent}s. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public int registerNetworkProvider(@NonNull NetworkProvider provider) { + if (provider.getProviderId() != NetworkProvider.ID_NONE) { + // TODO: Provide a better method for checking this by moving NetworkFactory.SerialNumber + // out of NetworkFactory. + throw new IllegalStateException("NetworkProviders can only be registered once"); + } + + try { + int providerId = mService.registerNetworkProvider(provider.getMessenger(), + provider.getName()); + provider.setProviderId(providerId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return provider.getProviderId(); + } + + /** + * Unregisters the specified NetworkProvider. + * + * @param provider the provider to unregister + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void unregisterNetworkProvider(@NonNull NetworkProvider provider) { + try { + mService.unregisterNetworkProvider(provider.getMessenger()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + provider.setProviderId(NetworkProvider.ID_NONE); + } + + + /** @hide exposed via the NetworkProvider class. */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + try { + mService.declareNetworkRequestUnfulfillable(request); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // TODO : remove this method. It is a stopgap measure to help sheperding a number // of dependent changes that would conflict throughout the automerger graph. Having this // temporarily helps with the process of going through with all these dependent changes across diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 09c02efbcfc4..e6a0379ff629 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -142,12 +142,16 @@ interface IConnectivityManager void setAirplaneMode(boolean enable); - int registerNetworkFactory(in Messenger messenger, in String name); - boolean requestBandwidthUpdate(in Network network); + int registerNetworkFactory(in Messenger messenger, in String name); void unregisterNetworkFactory(in Messenger messenger); + int registerNetworkProvider(in Messenger messenger, in String name); + void unregisterNetworkProvider(in Messenger messenger); + + void declareNetworkRequestUnfulfillable(in NetworkRequest request); + int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber); diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java new file mode 100644 index 000000000000..2c0e4aa700b1 --- /dev/null +++ b/core/java/android/net/NetworkProvider.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; + +/** + * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device + * to networks and makes them available to to the core network stack by creating + * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted + * with via networking APIs such as {@link ConnectivityManager}. + * + * Subclasses should implement {@link #onNetworkRequested} and {@link #onRequestWithdrawn} to + * receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the + * best (highest-scoring) network for any request is generally not used by the system, and torn + * down. + * + * @hide + */ +@SystemApi +public class NetworkProvider { + /** + * {@code providerId} value that indicates the absence of a provider. It is the providerId of + * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not + * currently being satisfied by a network. + */ + public static final int ID_NONE = -1; + + /** + * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any + * provider, so they use this constant for clarity instead of NONE. + * @hide only used by ConnectivityService. + */ + public static final int ID_VPN = -2; + + /** + * The first providerId value that will be allocated. + * @hide only used by ConnectivityService. + */ + public static final int FIRST_PROVIDER_ID = 1; + + /** @hide only used by ConnectivityService */ + public static final int CMD_REQUEST_NETWORK = 1; + /** @hide only used by ConnectivityService */ + public static final int CMD_CANCEL_REQUEST = 2; + + private final Messenger mMessenger; + private final String mName; + private final ConnectivityManager mCm; + + private int mProviderId = ID_NONE; + + /** + * Constructs a new NetworkProvider. + * + * @param looper the Looper on which to run {@link #onNetworkRequested} and + * {@link #onRequestWithdrawn}. + * @param name the name of the listener, used only for debugging. + * + * @hide + */ + @SystemApi + public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { + mCm = ConnectivityManager.from(context); + + Handler handler = new Handler(looper) { + @Override + public void handleMessage(Message m) { + switch (m.what) { + case CMD_REQUEST_NETWORK: + onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2); + break; + case CMD_CANCEL_REQUEST: + onRequestWithdrawn((NetworkRequest) m.obj); + break; + default: + Log.e(mName, "Unhandled message: " + m.what); + } + } + }; + mMessenger = new Messenger(handler); + mName = name; + } + + // TODO: consider adding a register() method so ConnectivityManager does not need to call this. + public @Nullable Messenger getMessenger() { + return mMessenger; + } + + public @NonNull String getName() { + return mName; + } + + /** + * Returns the ID of this provider. This is known only once the provider is registered via + * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}. + * This ID must be used when registering any {@link NetworkAgent}s. + */ + public int getProviderId() { + return mProviderId; + } + + /** @hide */ + public void setProviderId(int providerId) { + mProviderId = providerId; + } + + /** + * Called when a NetworkRequest is received. The request may be a new request or an existing + * request with a different score. + * + * @param request the NetworkRequest being received + * @param score the score of the network currently satisfying the request, or 0 if none. + * @param providerId the ID of the provider that created the network currently satisfying this + * request, or {@link #ID_NONE} if none. + * + * @hide + */ + @SystemApi + public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {} + + /** + * Called when a NetworkRequest is withdrawn. + * @hide + */ + @SystemApi + public void onRequestWithdrawn(@NonNull NetworkRequest request) {} + + /** + * Asserts that no provider will ever be able to satisfy the specified request. The provider + * must only call this method if it knows that it is the only provider on the system capable of + * satisfying this request, and that the request cannot be satisfied. The application filing the + * request will receive an {@link NetworkCallback#onUnavailable()} callback. + * + * @param request the request that cannot be fulfilled + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { + mCm.declareNetworkRequestUnfulfillable(request); + } +} diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 45bf4d2e1358..96d7a80886a5 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,6 +19,9 @@ package android.net; import static android.os.Process.CLAT_UID; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -48,59 +51,104 @@ import java.util.function.Predicate; * @hide */ // @NotThreadSafe -public class NetworkStats implements Parcelable { +@SystemApi +public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; + /** {@link #iface} value when interface details unavailable. */ - public static final String IFACE_ALL = null; + @SuppressLint("CompileTimeConstant") + @Nullable public static final String IFACE_ALL = null; + /** + * Virtual network interface for video telephony. This is for VT data usage counting + * purpose. + */ + public static final String IFACE_VT = "vt_data0"; + /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; - /** {@link #tag} value matching any tag. */ + /** Special UID value for data usage by tethering. */ + public static final int UID_TETHERING = -5; + + /** + * {@link #tag} value matching any tag. + * @hide + */ // TODO: Rename TAG_ALL to TAG_ANY. public static final int TAG_ALL = -1; - /** {@link #set} value for all sets combined, not including debug sets. */ + /** + * {@link #set} value for all sets combined, not including debug sets. + * @hide + */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; /** {@link #set} value where foreground data is accounted. */ public static final int SET_FOREGROUND = 1; - /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */ + /** + * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. + * @hide + */ public static final int SET_DEBUG_START = 1000; - /** Debug {@link #set} value when the VPN stats are moved in. */ + /** + * Debug {@link #set} value when the VPN stats are moved in. + * @hide + */ public static final int SET_DBG_VPN_IN = 1001; - /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ + /** + * Debug {@link #set} value when the VPN stats are moved out of a vpn UID. + * @hide + */ public static final int SET_DBG_VPN_OUT = 1002; - /** Include all interfaces when filtering */ - public static final String[] INTERFACES_ALL = null; + /** + * Include all interfaces when filtering + * @hide + */ + public @Nullable static final String[] INTERFACES_ALL = null; /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #metered} value to account for all metered states. */ + /** + * {@link #metered} value to account for all metered states. + * @hide + */ public static final int METERED_ALL = -1; /** {@link #metered} value where native, unmetered data is accounted. */ public static final int METERED_NO = 0; /** {@link #metered} value where metered data is accounted. */ public static final int METERED_YES = 1; - /** {@link #roaming} value to account for all roaming states. */ + /** + * {@link #roaming} value to account for all roaming states. + * @hide + */ public static final int ROAMING_ALL = -1; /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; - /** {@link #onDefaultNetwork} value to account for all default network states. */ + /** + * {@link #onDefaultNetwork} value to account for all default network states. + * @hide + */ public static final int DEFAULT_NETWORK_ALL = -1; /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ public static final int DEFAULT_NETWORK_NO = 0; /** {@link #onDefaultNetwork} value to account for usage while the default network. */ public static final int DEFAULT_NETWORK_YES = 1; - /** Denotes a request for stats at the interface level. */ + /** + * Denotes a request for stats at the interface level. + * @hide + */ public static final int STATS_PER_IFACE = 0; - /** Denotes a request for stats at the interface and UID level. */ + /** + * Denotes a request for stats at the interface and UID level. + * @hide + */ public static final int STATS_PER_UID = 1; private static final String CLATD_INTERFACE_PREFIX = "v4-"; @@ -144,60 +192,78 @@ public class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; + /** @hide */ + @SystemApi public static class Entry { + /** @hide */ @UnsupportedAppUsage public String iface; + /** @hide */ @UnsupportedAppUsage public int uid; + /** @hide */ @UnsupportedAppUsage public int set; + /** @hide */ @UnsupportedAppUsage public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int roaming; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of * getSummary(). + * @hide */ public int defaultNetwork; + /** @hide */ @UnsupportedAppUsage public long rxBytes; + /** @hide */ @UnsupportedAppUsage public long rxPackets; + /** @hide */ @UnsupportedAppUsage public long txBytes; + /** @hide */ @UnsupportedAppUsage public long txPackets; + /** @hide */ + @UnsupportedAppUsage public long operations; + /** @hide */ @UnsupportedAppUsage public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } + /** @hide */ public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations); } + /** @hide */ public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets, txBytes, txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; @@ -214,15 +280,18 @@ public class NetworkStats implements Parcelable { this.operations = operations; } + /** @hide */ public boolean isNegative() { return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0; } + /** @hide */ public boolean isEmpty() { return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0 && operations == 0; } + /** @hide */ public void add(Entry another) { this.rxBytes += another.rxBytes; this.rxPackets += another.rxPackets; @@ -249,6 +318,7 @@ public class NetworkStats implements Parcelable { return builder.toString(); } + /** @hide */ @Override public boolean equals(Object o) { if (o instanceof Entry) { @@ -262,13 +332,13 @@ public class NetworkStats implements Parcelable { return false; } + /** @hide */ @Override public int hashCode() { return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface); } } - @UnsupportedAppUsage public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; @@ -292,6 +362,7 @@ public class NetworkStats implements Parcelable { } } + /** @hide */ @UnsupportedAppUsage public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); @@ -312,7 +383,7 @@ public class NetworkStats implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(elapsedRealtime); dest.writeInt(size); dest.writeInt(capacity); @@ -330,19 +401,23 @@ public class NetworkStats implements Parcelable { dest.writeLongArray(operations); } + /** + * @hide + */ @Override public NetworkStats clone() { final NetworkStats clone = new NetworkStats(elapsedRealtime, size); NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addValues(entry); + clone.addEntry(entry); } return clone; } /** * Clear all data stored in this object. + * @hide */ public void clear() { this.capacity = 0; @@ -360,25 +435,28 @@ public class NetworkStats implements Parcelable { this.operations = EmptyArray.LONG; } + /** @hide */ @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addValues( + return addEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } + /** @hide */ @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addValues(new Entry( + return addEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } + /** @hide */ @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, + public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addValues(new Entry( + return addEntry(new Entry( iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -386,8 +464,9 @@ public class NetworkStats implements Parcelable { /** * Add new stats entry, copying from given {@link Entry}. The {@link Entry} * object can be recycled across multiple calls. + * @hide */ - public NetworkStats addValues(Entry entry) { + public NetworkStats addEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -428,6 +507,7 @@ public class NetworkStats implements Parcelable { /** * Return specific stats entry. + * @hide */ @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { @@ -467,10 +547,12 @@ public class NetworkStats implements Parcelable { operations[dest] = operations[src]; } + /** @hide */ public long getElapsedRealtime() { return elapsedRealtime; } + /** @hide */ public void setElapsedRealtime(long time) { elapsedRealtime = time; } @@ -478,21 +560,25 @@ public class NetworkStats implements Parcelable { /** * Return age of this {@link NetworkStats} object with respect to * {@link SystemClock#elapsedRealtime()}. + * @hide */ public long getElapsedRealtimeAge() { return SystemClock.elapsedRealtime() - elapsedRealtime; } + /** @hide */ @UnsupportedAppUsage public int size() { return size; } + /** @hide */ @VisibleForTesting public int internalSize() { return capacity; } + /** @hide */ @Deprecated public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { @@ -501,6 +587,7 @@ public class NetworkStats implements Parcelable { txPackets, operations); } + /** @hide */ public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return combineValues(new Entry( @@ -509,16 +596,20 @@ public class NetworkStats implements Parcelable { /** * Combine given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can - * also be used to subtract values from existing rows. + * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can + * also be used to subtract values from existing rows. This method mutates the referencing + * {@link NetworkStats} object. + * + * @param entry the {@link Entry} to combine. + * @return a reference to this mutated {@link NetworkStats} object. + * @hide */ - @UnsupportedAppUsage - public NetworkStats combineValues(Entry entry) { + public @NonNull NetworkStats combineValues(@NonNull Entry entry) { final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addValues(entry); + addEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -530,10 +621,33 @@ public class NetworkStats implements Parcelable { } /** + * Add given values with an existing row, or create a new row if + * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can + * also be used to subtract values from existing rows. + * + * @param entry the {@link Entry} to add. + * @return a new constructed {@link NetworkStats} object that contains the result. + */ + public @NonNull NetworkStats addValues(@NonNull Entry entry) { + return this.clone().combineValues(entry); + } + + /** + * Add the given {@link NetworkStats} objects. + * + * @return the sum of two objects. + */ + public @NonNull NetworkStats add(@NonNull NetworkStats another) { + final NetworkStats ret = this.clone(); + ret.combineAllValues(another); + return ret; + } + + /** * Combine all values from another {@link NetworkStats} into this object. + * @hide */ - @UnsupportedAppUsage - public void combineAllValues(NetworkStats another) { + public void combineAllValues(@NonNull NetworkStats another) { NetworkStats.Entry entry = null; for (int i = 0; i < another.size; i++) { entry = another.getValues(i, entry); @@ -543,6 +657,7 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. + * @hide */ public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork) { @@ -560,6 +675,7 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters, starting * search around the hinted index as an optimization. + * @hide */ @VisibleForTesting public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, @@ -589,6 +705,7 @@ public class NetworkStats implements Parcelable { * Splice in {@link #operations} from the given {@link NetworkStats} based * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, * since operation counts are at data layer. + * @hide */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { @@ -604,6 +721,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique interfaces known by this data structure. + * @hide */ public String[] getUniqueIfaces() { final HashSet<String> ifaces = new HashSet<String>(); @@ -617,6 +735,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique UIDs known by this data structure. + * @hide */ @UnsupportedAppUsage public int[] getUniqueUids() { @@ -636,6 +755,7 @@ public class NetworkStats implements Parcelable { /** * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. + * @hide */ @UnsupportedAppUsage public long getTotalBytes() { @@ -645,6 +765,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object. + * @hide */ @UnsupportedAppUsage public Entry getTotal(Entry recycle) { @@ -654,6 +775,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object matching * the requested {@link #uid}. + * @hide */ @UnsupportedAppUsage public Entry getTotal(Entry recycle, int limitUid) { @@ -663,11 +785,13 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object matching * the requested {@link #iface}. + * @hide */ public Entry getTotal(Entry recycle, HashSet<String> limitIface) { return getTotal(recycle, limitIface, UID_ALL, false); } + /** @hide */ @UnsupportedAppUsage public Entry getTotalIncludingTags(Entry recycle) { return getTotal(recycle, null, UID_ALL, true); @@ -717,6 +841,7 @@ public class NetworkStats implements Parcelable { /** * Fast path for battery stats. + * @hide */ public long getTotalPackets() { long total = 0; @@ -729,9 +854,12 @@ public class NetworkStats implements Parcelable { /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. + * time, and that none of them have disappeared. This method does not mutate + * the referencing object. + * + * @return the delta between two objects. */ - public NetworkStats subtract(NetworkStats right) { + public @NonNull NetworkStats subtract(@NonNull NetworkStats right) { return subtract(this, right, null, null); } @@ -742,6 +870,7 @@ public class NetworkStats implements Parcelable { * <p> * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. + * @hide */ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) { @@ -759,6 +888,7 @@ public class NetworkStats implements Parcelable { * If <var>recycle</var> is supplied, this NetworkStats object will be * reused (and returned) as the result if it is large enough to contain * the data. + * @hide */ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) { @@ -817,7 +947,7 @@ public class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addValues(entry); + result.addEntry(entry); } return result; @@ -847,6 +977,7 @@ public class NetworkStats implements Parcelable { * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @param useBpfStats True if eBPF is in use. + * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) { @@ -899,6 +1030,7 @@ public class NetworkStats implements Parcelable { * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as * base and stacked traffic. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + * @hide */ public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) { apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); @@ -907,6 +1039,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #iface}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByIface() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -938,6 +1071,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #uid}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByUid() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -968,6 +1102,7 @@ public class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * @hide */ public void removeUids(int[] uids) { int nextOutputEntry = 0; @@ -989,6 +1124,7 @@ public class NetworkStats implements Parcelable { * @param limitUid UID to filter for, or {@link #UID_ALL}. * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + * @hide */ public void filter(int limitUid, String[] limitIfaces, int limitTag) { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { @@ -1004,6 +1140,7 @@ public class NetworkStats implements Parcelable { * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. * * <p>This mutates the original structure in place. + * @hide */ public void filterDebugEntries() { filter(e -> e.set < SET_DEBUG_START); @@ -1024,6 +1161,7 @@ public class NetworkStats implements Parcelable { size = nextOutputEntry; } + /** @hide */ public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); @@ -1047,6 +1185,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToString(int set) { switch (set) { @@ -1067,6 +1206,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToCheckinString(int set) { switch (set) { @@ -1087,6 +1227,7 @@ public class NetworkStats implements Parcelable { /** * @return true if the querySet matches the dataSet. + * @hide */ public static boolean setMatches(int querySet, int dataSet) { if (querySet == dataSet) { @@ -1098,6 +1239,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #tag} value. + * @hide */ public static String tagToString(int tag) { return "0x" + Integer.toHexString(tag); @@ -1105,6 +1247,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #metered} value. + * @hide */ public static String meteredToString(int metered) { switch (metered) { @@ -1121,6 +1264,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #roaming} value. + * @hide */ public static String roamingToString(int roaming) { switch (roaming) { @@ -1137,6 +1281,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #defaultNetwork} value. + * @hide */ public static String defaultNetworkToString(int defaultNetwork) { switch (defaultNetwork) { @@ -1151,6 +1296,7 @@ public class NetworkStats implements Parcelable { } } + /** @hide */ @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); @@ -1163,8 +1309,7 @@ public class NetworkStats implements Parcelable { return 0; } - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { + public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { @Override public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); @@ -1176,6 +1321,7 @@ public class NetworkStats implements Parcelable { } }; + /** @hide */ public interface NonMonotonicObserver<C> { public void foundNonMonotonic( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); @@ -1195,6 +1341,7 @@ public class NetworkStats implements Parcelable { * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel * @param underlyingIfaces underlying network ifaces used by the VPN application + * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, @NonNull String[] underlyingIfaces) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 162d6e27bd42..8108cf08d5c3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -89,7 +89,7 @@ public class TrafficStats { * * @hide */ - public static final int UID_TETHERING = -5; + public static final int UID_TETHERING = NetworkStats.UID_TETHERING; /** * Tag values in this range are reserved for the network stack. The network stack is diff --git a/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java new file mode 100644 index 000000000000..740aa92ad484 --- /dev/null +++ b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.NetworkStats; + +/** + * A base class that allows external modules to implement a custom network statistics provider. + * @hide + */ +@SystemApi +public abstract class AbstractNetworkStatsProvider { + /** + * A value used by {@link #setLimit} and {@link #setAlert} indicates there is no limit. + */ + public static final int QUOTA_UNLIMITED = -1; + + /** + * Called by {@code NetworkStatsService} when global polling is needed. Custom + * implementation of providers MUST respond to it by calling + * {@link NetworkStatsProviderCallback#onStatsUpdated} within one minute. Responding + * later than this may cause the stats to be dropped. + * + * @param token a positive number identifying the new state of the system under which + * {@link NetworkStats} have to be gathered from now on. When this is called, + * custom implementations of providers MUST report the latest stats with the + * previous token, under which stats were being gathered so far. + */ + public abstract void requestStatsUpdate(int token); + + /** + * Called by {@code NetworkStatsService} when setting the interface quota for the specified + * upstream interface. When this is called, the custom implementation should block all egress + * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have + * been reached, and MUST respond to it by calling + * {@link NetworkStatsProviderCallback#onLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + */ + public abstract void setLimit(@NonNull String iface, long quotaBytes); + + /** + * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations + * MUST call {@link NetworkStatsProviderCallback#onAlertReached()} when {@code quotaBytes} bytes + * have been reached. Unlike {@link #setLimit(String, long)}, the custom implementation should + * not block all egress packets. + * + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. + */ + public abstract void setAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl new file mode 100644 index 000000000000..55b3d4edb157 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +/** + * Interface for NetworkStatsService to query network statistics and set data limits. + * + * @hide + */ +oneway interface INetworkStatsProvider { + void requestStatsUpdate(int token); + void setLimit(String iface, long quotaBytes); + void setAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl new file mode 100644 index 000000000000..3ea9318f10d4 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.net.NetworkStats; + +/** + * Interface for implementor of {@link INetworkStatsProviderCallback} to push events + * such as network statistics update or notify limit reached. + * @hide + */ +oneway interface INetworkStatsProviderCallback { + void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void onAlertReached(); + void onLimitReached(); + void unregister(); +} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java new file mode 100644 index 000000000000..e17a8eee7ff0 --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.net.NetworkStats; +import android.os.RemoteException; + +/** + * A callback class that allows callers to report events to the system. + * @hide + */ +@SystemApi +@SuppressLint("CallbackMethodName") +public class NetworkStatsProviderCallback { + @NonNull private final INetworkStatsProviderCallback mBinder; + + /** @hide */ + public NetworkStatsProviderCallback(@NonNull INetworkStatsProviderCallback binder) { + mBinder = binder; + } + + /** + * Notify the system of new network statistics. + * + * Send the network statistics recorded since the last call to {@link #onStatsUpdated}. Must be + * called within one minute of {@link AbstractNetworkStatsProvider#requestStatsUpdate(int)} + * being called. The provider can also call this whenever it wants to reports new stats for any + * reason. Note that the system will not necessarily immediately propagate the statistics to + * reflect the update. + * + * @param token the token under which these stats were gathered. Providers can call this method + * with the current token as often as they want, until the token changes. + * {@see AbstractNetworkStatsProvider#requestStatsUpdate()} + * @param ifaceStats the {@link NetworkStats} per interface to be reported. + * The provider should not include any traffic that is already counted by + * kernel interface counters. + * @param uidStats the same stats as above, but counts {@link NetworkStats} + * per uid. + */ + public void onStatsUpdated(int token, @NonNull NetworkStats ifaceStats, + @NonNull NetworkStats uidStats) { + try { + mBinder.onStatsUpdated(token, ifaceStats, uidStats); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code setAlert} has been reached. + */ + public void onAlertReached() { + try { + mBinder.onAlertReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code setLimit} has been reached. + */ + public void onLimitReached() { + try { + mBinder.onLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregister the provider and the referencing callback. + */ + public void unregister() { + try { + mBinder.unregister(); + } catch (RemoteException e) { + // Ignore error. + } + } +} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java new file mode 100644 index 000000000000..4bf7c9bc086e --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; + +/** + * A wrapper class of {@link INetworkStatsProvider} that hides the binder interface from exposing + * to outer world. + * + * @hide + */ +public class NetworkStatsProviderWrapper extends INetworkStatsProvider.Stub { + @NonNull final AbstractNetworkStatsProvider mProvider; + + public NetworkStatsProviderWrapper(AbstractNetworkStatsProvider provider) { + mProvider = provider; + } + + @Override + public void requestStatsUpdate(int token) { + mProvider.requestStatsUpdate(token); + } + + @Override + public void setLimit(@NonNull String iface, long quotaBytes) { + mProvider.setLimit(iface, quotaBytes); + } + + @Override + public void setAlert(long quotaBytes) { + mProvider.setAlert(quotaBytes); + } +} diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index c9ebed3bd0a2..1a4dac78855f 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -1886,29 +1886,7 @@ public final class Parcel { public final void writeException(@NonNull Exception e) { AppOpsManager.prefixParcelWithAppOpsIfNeeded(this); - int code = 0; - if (e instanceof Parcelable - && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) { - // We only send Parcelable exceptions that are in the - // BootClassLoader to ensure that the receiver can unpack them - code = EX_PARCELABLE; - } else if (e instanceof SecurityException) { - code = EX_SECURITY; - } else if (e instanceof BadParcelableException) { - code = EX_BAD_PARCELABLE; - } else if (e instanceof IllegalArgumentException) { - code = EX_ILLEGAL_ARGUMENT; - } else if (e instanceof NullPointerException) { - code = EX_NULL_POINTER; - } else if (e instanceof IllegalStateException) { - code = EX_ILLEGAL_STATE; - } else if (e instanceof NetworkOnMainThreadException) { - code = EX_NETWORK_MAIN_THREAD; - } else if (e instanceof UnsupportedOperationException) { - code = EX_UNSUPPORTED_OPERATION; - } else if (e instanceof ServiceSpecificException) { - code = EX_SERVICE_SPECIFIC; - } + int code = getExceptionCode(e); writeInt(code); StrictMode.clearGatheredViolations(); if (code == 0) { @@ -1922,20 +1900,7 @@ public final class Parcel { if (sParcelExceptionStackTrace && (timeNow - sLastWriteExceptionStackTrace > WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS)) { sLastWriteExceptionStackTrace = timeNow; - final int sizePosition = dataPosition(); - writeInt(0); // Header size will be filled in later - StackTraceElement[] stackTrace = e.getStackTrace(); - final int truncatedSize = Math.min(stackTrace.length, 5); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < truncatedSize; i++) { - sb.append("\tat ").append(stackTrace[i]).append('\n'); - } - writeString(sb.toString()); - final int payloadPosition = dataPosition(); - setDataPosition(sizePosition); - // Write stack trace header size. Used in native side to skip the header - writeInt(payloadPosition - sizePosition); - setDataPosition(payloadPosition); + writeStackTrace(e); } else { writeInt(0); } @@ -1956,6 +1921,52 @@ public final class Parcel { } } + /** @hide */ + public static int getExceptionCode(@NonNull Throwable e) { + int code = 0; + if (e instanceof Parcelable + && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) { + // We only send Parcelable exceptions that are in the + // BootClassLoader to ensure that the receiver can unpack them + code = EX_PARCELABLE; + } else if (e instanceof SecurityException) { + code = EX_SECURITY; + } else if (e instanceof BadParcelableException) { + code = EX_BAD_PARCELABLE; + } else if (e instanceof IllegalArgumentException) { + code = EX_ILLEGAL_ARGUMENT; + } else if (e instanceof NullPointerException) { + code = EX_NULL_POINTER; + } else if (e instanceof IllegalStateException) { + code = EX_ILLEGAL_STATE; + } else if (e instanceof NetworkOnMainThreadException) { + code = EX_NETWORK_MAIN_THREAD; + } else if (e instanceof UnsupportedOperationException) { + code = EX_UNSUPPORTED_OPERATION; + } else if (e instanceof ServiceSpecificException) { + code = EX_SERVICE_SPECIFIC; + } + return code; + } + + /** @hide */ + public void writeStackTrace(@NonNull Throwable e) { + final int sizePosition = dataPosition(); + writeInt(0); // Header size will be filled in later + StackTraceElement[] stackTrace = e.getStackTrace(); + final int truncatedSize = Math.min(stackTrace.length, 5); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < truncatedSize; i++) { + sb.append("\tat ").append(stackTrace[i]).append('\n'); + } + writeString(sb.toString()); + final int payloadPosition = dataPosition(); + setDataPosition(sizePosition); + // Write stack trace header size. Used in native side to skip the header + writeInt(payloadPosition - sizePosition); + setDataPosition(payloadPosition); + } + /** * Special function for writing information at the front of the Parcel * indicating that no exception occurred. @@ -2069,14 +2080,7 @@ public final class Parcel { if (remoteStackTrace != null) { RemoteException cause = new RemoteException( "Remote stack trace:\n" + remoteStackTrace, null, false, false); - try { - Throwable rootCause = ExceptionUtils.getRootCause(e); - if (rootCause != null) { - rootCause.initCause(cause); - } - } catch (RuntimeException ex) { - Log.e(TAG, "Cannot set cause " + cause + " for " + e, ex); - } + ExceptionUtils.appendCause(e, cause); } SneakyThrow.sneakyThrow(e); } @@ -2088,6 +2092,14 @@ public final class Parcel { * @param msg The exception message. */ private Exception createException(int code, String msg) { + Exception exception = createExceptionOrNull(code, msg); + return exception != null + ? exception + : new RuntimeException("Unknown exception code: " + code + " msg " + msg); + } + + /** @hide */ + public Exception createExceptionOrNull(int code, String msg) { switch (code) { case EX_PARCELABLE: if (readInt() > 0) { @@ -2111,9 +2123,9 @@ public final class Parcel { return new UnsupportedOperationException(msg); case EX_SERVICE_SPECIFIC: return new ServiceSpecificException(readInt(), msg); + default: + return null; } - return new RuntimeException("Unknown exception code: " + code - + " msg " + msg); } /** diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 983053bbe7fd..89ddf8cbd96a 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -31,6 +31,9 @@ import static android.system.OsConstants.S_ISLNK; import static android.system.OsConstants.S_ISREG; import static android.system.OsConstants.S_IWOTH; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -253,6 +256,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * be opened with the requested mode. * @see #parseMode(String) */ + // We can't accept a generic Executor here, since we need to use + // MessageQueue.addOnFileDescriptorEventListener() + @SuppressLint("ExecutorRegistration") public static ParcelFileDescriptor open(File file, int mode, Handler handler, final OnCloseListener listener) throws IOException { if (handler == null) { @@ -268,9 +274,22 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { return fromFd(fd, handler, listener); } - /** {@hide} */ - public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler, - final OnCloseListener listener) throws IOException { + /** + * Create a new ParcelFileDescriptor wrapping an already-opened file. + * + * @param pfd The already-opened file. + * @param handler to call listener from. + * @param listener to be invoked when the returned descriptor has been + * closed. + * @return a new ParcelFileDescriptor pointing to the given file. + * @hide + */ + @SystemApi + // We can't accept a generic Executor here, since we need to use + // MessageQueue.addOnFileDescriptorEventListener() + @SuppressLint("ExecutorRegistration") + public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd, + @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException { final FileDescriptor original = new FileDescriptor(); original.setInt$(pfd.detachFd()); return fromFd(original, handler, listener); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 94623bc71346..3ef86ed9f994 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -89,6 +89,12 @@ public class Process { public static final int DRM_UID = 1019; /** + * Defines the GID for the group that allows write access to the internal media storage. + * @hide + */ + public static final int SDCARD_RW_GID = 1015; + + /** * Defines the UID/GID for the group that controls VPN services. * @hide */ diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 62b8953b158a..3846f894c4c3 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -594,6 +594,8 @@ public class ZygoteProcess { argsForZygote.add("--mount-external-legacy"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) { argsForZygote.add("--mount-external-pass-through"); + } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) { + argsForZygote.add("--mount-external-android-writable"); } argsForZygote.add("--target-sdk-version=" + targetSdkVersion); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 8959fcf7ac18..f0a11748fbd6 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -31,6 +31,7 @@ import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.BytesLong; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -72,6 +73,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.os.SystemProperties; +import android.os.UserHandle; import android.provider.MediaStore; import android.provider.Settings; import android.sysprop.VoldProperties; @@ -93,7 +95,6 @@ import com.android.internal.os.AppFuseMount; import com.android.internal.os.FuseAppLoop; import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.os.RoSystemProperties; -import com.android.internal.os.SomeArgs; import com.android.internal.util.Preconditions; import dalvik.system.BlockGuard; @@ -114,6 +115,7 @@ import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -305,109 +307,85 @@ public class StorageManager { private final Looper mLooper; private final AtomicInteger mNextNonce = new AtomicInteger(0); + @GuardedBy("mDelegates") private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>(); - private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements - Handler.Callback { - private static final int MSG_STORAGE_STATE_CHANGED = 1; - private static final int MSG_VOLUME_STATE_CHANGED = 2; - private static final int MSG_VOLUME_RECORD_CHANGED = 3; - private static final int MSG_VOLUME_FORGOTTEN = 4; - private static final int MSG_DISK_SCANNED = 5; - private static final int MSG_DISK_DESTROYED = 6; + private class StorageEventListenerDelegate extends IStorageEventListener.Stub { + final Executor mExecutor; + final StorageEventListener mListener; + final StorageVolumeCallback mCallback; - final StorageEventListener mCallback; - final Handler mHandler; - - public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) { + public StorageEventListenerDelegate(@NonNull Executor executor, + @NonNull StorageEventListener listener, @NonNull StorageVolumeCallback callback) { + mExecutor = executor; + mListener = listener; mCallback = callback; - mHandler = new Handler(looper, this); - } - - @Override - public boolean handleMessage(Message msg) { - final SomeArgs args = (SomeArgs) msg.obj; - switch (msg.what) { - case MSG_STORAGE_STATE_CHANGED: - mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2, - (String) args.arg3); - args.recycle(); - return true; - case MSG_VOLUME_STATE_CHANGED: - mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3); - args.recycle(); - return true; - case MSG_VOLUME_RECORD_CHANGED: - mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1); - args.recycle(); - return true; - case MSG_VOLUME_FORGOTTEN: - mCallback.onVolumeForgotten((String) args.arg1); - args.recycle(); - return true; - case MSG_DISK_SCANNED: - mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2); - args.recycle(); - return true; - case MSG_DISK_DESTROYED: - mCallback.onDiskDestroyed((DiskInfo) args.arg1); - args.recycle(); - return true; - } - args.recycle(); - return false; } @Override public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException { - // Ignored + mExecutor.execute(() -> { + mListener.onUsbMassStorageConnectionChanged(connected); + }); } @Override public void onStorageStateChanged(String path, String oldState, String newState) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = path; - args.arg2 = oldState; - args.arg3 = newState; - mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onStorageStateChanged(path, oldState, newState); + + if (path != null) { + for (StorageVolume sv : getStorageVolumes()) { + if (Objects.equals(path, sv.getPath())) { + mCallback.onStateChanged(sv); + } + } + } + }); } @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = vol; - args.argi2 = oldState; - args.argi3 = newState; - mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onVolumeStateChanged(vol, oldState, newState); + + final File path = vol.getPathForUser(UserHandle.myUserId()); + if (path != null) { + for (StorageVolume sv : getStorageVolumes()) { + if (Objects.equals(path.getAbsolutePath(), sv.getPath())) { + mCallback.onStateChanged(sv); + } + } + } + }); } @Override public void onVolumeRecordChanged(VolumeRecord rec) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = rec; - mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onVolumeRecordChanged(rec); + }); } @Override public void onVolumeForgotten(String fsUuid) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = fsUuid; - mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onVolumeForgotten(fsUuid); + }); } @Override public void onDiskScanned(DiskInfo disk, int volumeCount) { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = disk; - args.argi2 = volumeCount; - mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onDiskScanned(disk, volumeCount); + }); } @Override public void onDiskDestroyed(DiskInfo disk) throws RemoteException { - final SomeArgs args = SomeArgs.obtain(); - args.arg1 = disk; - mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget(); + mExecutor.execute(() -> { + mListener.onDiskDestroyed(disk); + }); } } @@ -525,8 +503,8 @@ public class StorageManager { @UnsupportedAppUsage public void registerListener(StorageEventListener listener) { synchronized (mDelegates) { - final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener, - mLooper); + final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate( + mContext.getMainExecutor(), listener, new StorageVolumeCallback()); try { mStorageManager.registerListener(delegate); } catch (RemoteException e) { @@ -548,7 +526,76 @@ public class StorageManager { synchronized (mDelegates) { for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) { final StorageEventListenerDelegate delegate = i.next(); - if (delegate.mCallback == listener) { + if (delegate.mListener == listener) { + try { + mStorageManager.unregisterListener(delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + i.remove(); + } + } + } + } + + /** + * Callback that delivers {@link StorageVolume} related events. + * <p> + * For example, this can be used to detect when a volume changes to the + * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED} + * states. + * + * @see StorageManager#registerStorageVolumeCallback + * @see StorageManager#unregisterStorageVolumeCallback + */ + public static class StorageVolumeCallback { + /** + * Called when {@link StorageVolume#getState()} changes, such as + * changing to the {@link Environment#MEDIA_MOUNTED} or + * {@link Environment#MEDIA_UNMOUNTED} states. + * <p> + * The given argument is a snapshot in time and can be used to process + * events in the order they occurred, or you can call + * {@link StorageManager#getStorageVolumes()} to observe the latest + * value. + */ + public void onStateChanged(@NonNull StorageVolume volume) { } + } + + /** + * Registers the given callback to listen for {@link StorageVolume} changes. + * <p> + * For example, this can be used to detect when a volume changes to the + * {@link Environment#MEDIA_MOUNTED} or {@link Environment#MEDIA_UNMOUNTED} + * states. + * + * @see StorageManager#unregisterStorageVolumeCallback + */ + public void registerStorageVolumeCallback(@CallbackExecutor @NonNull Executor executor, + @NonNull StorageVolumeCallback callback) { + synchronized (mDelegates) { + final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate( + executor, new StorageEventListener(), callback); + try { + mStorageManager.registerListener(delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mDelegates.add(delegate); + } + } + + /** + * Unregisters the given callback from listening for {@link StorageVolume} + * changes. + * + * @see StorageManager#registerStorageVolumeCallback + */ + public void unregisterStorageVolumeCallback(@NonNull StorageVolumeCallback callback) { + synchronized (mDelegates) { + for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) { + final StorageEventListenerDelegate delegate = i.next(); + if (delegate.mCallback == callback) { try { mStorageManager.unregisterListener(delegate); } catch (RemoteException e) { @@ -829,7 +876,14 @@ public class StorageManager { */ public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException { Preconditions.checkNotNull(path); - final String pathString = path.getCanonicalPath(); + String pathString = path.getCanonicalPath(); + if (path.getPath().startsWith("/sdcard")) { + // On FUSE enabled devices, realpath(2) /sdcard is /mnt/user/<userid>/emulated/<userid> + // as opposed to /storage/emulated/<userid>. + // And vol.path below expects to match with a path starting with /storage + pathString = pathString.replaceFirst("^/mnt/user/[0-9]+/", "/storage/"); + } + if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) { return UUID_DEFAULT; } diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index 2ab226f81bb4..e251f8072b1f 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -18,6 +18,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -162,9 +163,13 @@ public final class StorageVolume implements Parcelable { mState = in.readString(); } - /** {@hide} */ - @UnsupportedAppUsage - public String getId() { + /** + * Return an opaque ID that can be used to identify this volume. + * + * @hide + */ + @SystemApi + public @NonNull String getId() { return mId; } diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 0a3c333ae7b1..ef8a2860cf4f 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -553,7 +553,9 @@ public final class DocumentsContract { /** * Flag indicating that a document is a directory that wants to block itself * from being selected when the user launches an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} - * intent. Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}. + * intent. Individual files can still be selected when launched via other intents + * like {@link Intent#ACTION_OPEN_DOCUMENT} and {@link Intent#ACTION_GET_CONTENT}. + * Only valid when {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}. * <p> * Note that this flag <em>only</em> applies to the single directory to which it is * applied. It does <em>not</em> block the user from selecting either a parent or diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 07cbcfbb298b..9ee4cc30949d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -218,7 +218,9 @@ public final class Settings { * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_TETHER_PROVISIONING = + @SystemApi + @TestApi + public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI"; /** @@ -9697,6 +9699,8 @@ public final class Settings { * is interpreted as |false|. * @hide */ + @SystemApi + @TestApi public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; /** diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index d51e4ca6398f..939ae878816a 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -609,10 +609,12 @@ public final class FillResponse implements Parcelable { "must add at least 1 dataset when using header or footer"); } - for (final Dataset dataset : mDatasets) { - if (dataset.getFieldInlinePresentation(0) != null) { - mSupportsInlineSuggestions = true; - break; + if (mDatasets != null) { + for (final Dataset dataset : mDatasets) { + if (dataset.getFieldInlinePresentation(0) != null) { + mSupportsInlineSuggestions = true; + break; + } } } diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 771695c2b873..a3245b9916ec 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -257,10 +257,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll for (int i = items.size() - 1; i >= 0; i--) { final InsetsSourceControl control = items.valueAt(i); final InsetsSource source = mInitialInsetsState.getSource(control.getType()); - if (control == null) { - // TODO: remove this check when we ensure the elements will not be null. - continue; - } final SurfaceControl leash = control.getLeash(); mTmpMatrix.setTranslate(control.getSurfacePosition().x, control.getSurfacePosition().y); diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 4d4ace27cac9..2a7a4e3a922c 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -375,8 +375,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } cancelExistingControllers(types); - final ArraySet<Integer> internalTypes = mState.toInternalType(types); - final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>(); + final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Pair<Integer, Boolean> typesReadyPair = collectSourceControls( @@ -441,7 +440,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } typesReady |= InsetsState.toPublicType(consumer.getType()); } - controls.put(consumer.getType(), consumer.getControl()); + final InsetsSourceControl control = consumer.getControl(); + if (control != null) { + controls.put(consumer.getType(), control); + } } return new Pair<>(typesReady, isReady); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index f6d6522f80d6..ff8455ab0915 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -677,6 +677,22 @@ public final class SurfaceControl implements Parcelable { } /** + * Set the initial visibility for the SurfaceControl. + * + * @param hidden Whether the Surface is initially HIDDEN. + * @hide + */ + @NonNull + public Builder setHidden(boolean hidden) { + if (hidden) { + mFlags |= HIDDEN; + } else { + mFlags &= ~HIDDEN; + } + return this; + } + + /** * Set a parent surface for our new SurfaceControl. * * Child surfaces are constrained to the onscreen region of their parent. @@ -789,8 +805,7 @@ public final class SurfaceControl implements Parcelable { * @param name The surface name, must not be null. * @param w The surface initial width. * @param h The surface initial height. - * @param flags The surface creation flags. Should always include {@link #HIDDEN} - * in the creation flags. + * @param flags The surface creation flags. * @param metadata Initial metadata. * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ @@ -801,15 +816,6 @@ public final class SurfaceControl implements Parcelable { throw new IllegalArgumentException("name must not be null"); } - if ((flags & SurfaceControl.HIDDEN) == 0) { - Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set " - + "to ensure that they are not made visible prematurely before " - + "all of the surface's properties have been configured. " - + "Set the other properties and make the surface visible within " - + "a transaction. New surface name: " + name, - new Throwable()); - } - mName = name; mWidth = w; mHeight = h; diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java index f9ba34ed1c3a..0a0d05ce8fc8 100644 --- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java +++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java @@ -61,7 +61,6 @@ public class AccessibilityButtonChooserActivity extends Activity { private int mShortcutType; private List<AccessibilityButtonTarget> mTargets = new ArrayList<>(); - private List<AccessibilityButtonTarget> mReadyToBeDisabledTargets = new ArrayList<>(); private AlertDialog mAlertDialog; private TargetAdapter mTargetAdapter; @@ -117,7 +116,6 @@ public class AccessibilityButtonChooserActivity extends Activity { ACCESSIBILITY_BUTTON); mTargets.addAll(getServiceTargets(this, mShortcutType)); - // TODO(b/146815548): Will add title to separate which one type mTargetAdapter = new TargetAdapter(mTargets); mAlertDialog = new AlertDialog.Builder(this) .setAdapter(mTargetAdapter, /* listener= */ null) @@ -269,8 +267,10 @@ public class AccessibilityButtonChooserActivity extends Activity { switch (target.getFragmentType()) { case AccessibilityServiceFragmentType.LEGACY: + updateLegacyActionItemVisibility(context, holder); + break; case AccessibilityServiceFragmentType.INVISIBLE: - updateLegacyOrInvisibleActionItemVisibility(context, holder); + updateInvisibleActionItemVisibility(context, holder); break; case AccessibilityServiceFragmentType.INTUITIVE: updateIntuitiveActionItemVisibility(context, holder, target); @@ -283,9 +283,21 @@ public class AccessibilityButtonChooserActivity extends Activity { } } - private void updateLegacyOrInvisibleActionItemVisibility(@NonNull Context context, + private void updateLegacyActionItemVisibility(@NonNull Context context, + @NonNull ViewHolder holder) { + final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); + + holder.mLabelView.setEnabled(!isEditMenuMode); + holder.mViewItem.setEnabled(!isEditMenuMode); + holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item)); + holder.mViewItem.setVisibility(View.VISIBLE); + holder.mSwitchItem.setVisibility(View.GONE); + holder.mItemContainer.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE); + } + + private void updateInvisibleActionItemVisibility(@NonNull Context context, @NonNull ViewHolder holder) { - final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT; + final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item)); holder.mViewItem.setVisibility(View.VISIBLE); @@ -295,7 +307,7 @@ public class AccessibilityButtonChooserActivity extends Activity { private void updateIntuitiveActionItemVisibility(@NonNull Context context, @NonNull ViewHolder holder, AccessibilityButtonTarget target) { - final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT; + final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item)); holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE); @@ -306,7 +318,7 @@ public class AccessibilityButtonChooserActivity extends Activity { private void updateBounceActionItemVisibility(@NonNull Context context, @NonNull ViewHolder holder) { - final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT; + final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); holder.mViewItem.setImageDrawable( isEditMenuMode ? context.getDrawable(R.drawable.ic_delete_item) @@ -383,20 +395,23 @@ public class AccessibilityButtonChooserActivity extends Activity { } private void onTargetDeleted(AdapterView<?> parent, View view, int position, long id) { - // TODO(b/147027236): Will discuss with UX designer what UX behavior about deleting item - // is good for user. - mReadyToBeDisabledTargets.add(mTargets.get(position)); - mTargets.remove(position); - mTargetAdapter.notifyDataSetChanged(); + // TODO(b/146967898): disable service when deleting the target and the target only have + // last one shortcut item, only remove it from shortcut list otherwise. + if ((mShortcutType == ACCESSIBILITY_BUTTON) && (mTargets.get(position).mFragmentType + != AccessibilityServiceFragmentType.LEGACY)) { + mTargets.remove(position); + mTargetAdapter.notifyDataSetChanged(); + } + + if (mTargets.isEmpty()) { + mAlertDialog.dismiss(); + } } private void onCancelButtonClicked() { - resetAndUpdateTargets(); - mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH); mTargetAdapter.notifyDataSetChanged(); - mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText( getString(R.string.edit_accessibility_shortcut_menu_button)); @@ -407,49 +422,19 @@ public class AccessibilityButtonChooserActivity extends Activity { mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT); mTargetAdapter.notifyDataSetChanged(); - mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setText( - getString(R.string.cancel_accessibility_shortcut_menu_button)); - mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.VISIBLE); - mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText( - getString(R.string.save_accessibility_shortcut_menu_button)); - - updateDialogListeners(); - } - - private void onSaveButtonClicked() { - disableTargets(); - resetAndUpdateTargets(); - - mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH); - mTargetAdapter.notifyDataSetChanged(); - - mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText( - getString(R.string.edit_accessibility_shortcut_menu_button)); + getString(R.string.cancel_accessibility_shortcut_menu_button)); updateDialogListeners(); } private void updateDialogListeners() { final boolean isEditMenuMode = - mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT; + (mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT); - mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener( - view -> onCancelButtonClicked()); mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener( - isEditMenuMode ? view -> onSaveButtonClicked() : view -> onEditButtonClicked()); + isEditMenuMode ? view -> onCancelButtonClicked() : view -> onEditButtonClicked()); mAlertDialog.getListView().setOnItemClickListener( isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected); } - - private void disableTargets() { - for (AccessibilityButtonTarget service : mReadyToBeDisabledTargets) { - // TODO(b/146967898): disable services. - } - } - - private void resetAndUpdateTargets() { - mTargets.clear(); - mTargets.addAll(getServiceTargets(this, mShortcutType)); - } } diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java index b250578c8454..9f15d8991fa7 100644 --- a/core/java/com/android/internal/infra/AndroidFuture.java +++ b/core/java/com/android/internal/infra/AndroidFuture.java @@ -75,6 +75,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable private static final boolean DEBUG = false; private static final String LOG_TAG = AndroidFuture.class.getSimpleName(); + private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; private final @NonNull Object mLock = new Object(); @GuardedBy("mLock") @@ -95,15 +96,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable // Done if (in.readBoolean()) { // Failed - try { - in.readException(); - } catch (Throwable e) { - completeExceptionally(e); - } - if (!isCompletedExceptionally()) { - throw new IllegalStateException( - "Error unparceling AndroidFuture: exception expected"); - } + completeExceptionally(unparcelException(in)); } else { // Success complete((T) in.readValue(null)); @@ -512,14 +505,9 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable T result; try { result = get(); - } catch (Exception t) { - // Exceptions coming out of get() are wrapped in ExecutionException, which is not - // handled by Parcel. - if (t instanceof ExecutionException && t.getCause() instanceof Exception) { - t = (Exception) t.getCause(); - } + } catch (Throwable t) { dest.writeBoolean(true); - dest.writeException(t); + parcelException(dest, unwrapExecutionException(t)); return; } dest.writeBoolean(false); @@ -528,22 +516,76 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable dest.writeStrongBinder(new IAndroidFuture.Stub() { @Override public void complete(AndroidFuture resultContainer) { + boolean changed; try { - AndroidFuture.this.complete((T) resultContainer.get()); + changed = AndroidFuture.this.complete((T) resultContainer.get()); } catch (Throwable t) { - // If resultContainer was completed exceptionally, get() wraps the - // underlying exception in an ExecutionException. Unwrap it now to avoid - // double-layering ExecutionExceptions. - if (t instanceof ExecutionException && t.getCause() != null) { - t = t.getCause(); - } - completeExceptionally(t); + changed = completeExceptionally(unwrapExecutionException(t)); + } + if (!changed) { + Log.w(LOG_TAG, "Remote result " + resultContainer + + " ignored, as local future is already completed: " + + AndroidFuture.this); } } }.asBinder()); } } + /** + * Exceptions coming out of {@link #get} are wrapped in {@link ExecutionException} + */ + Throwable unwrapExecutionException(Throwable t) { + return t instanceof ExecutionException + ? t.getCause() + : t; + } + + /** + * Alternative to {@link Parcel#writeException} that stores the stack trace, in a + * way consistent with the binder IPC exception propagation behavior. + */ + private static void parcelException(Parcel p, @Nullable Throwable t) { + p.writeBoolean(t == null); + if (t == null) { + return; + } + + p.writeInt(Parcel.getExceptionCode(t)); + p.writeString(t.getClass().getName()); + p.writeString(t.getMessage()); + p.writeStackTrace(t); + parcelException(p, t.getCause()); + } + + /** + * @see #parcelException + */ + private static @Nullable Throwable unparcelException(Parcel p) { + if (p.readBoolean()) { + return null; + } + + int exCode = p.readInt(); + String cls = p.readString(); + String msg = p.readString(); + String stackTrace = p.readInt() > 0 ? p.readString() : "\t<stack trace unavailable>"; + msg += "\n" + stackTrace; + + Exception ex = p.createExceptionOrNull(exCode, msg); + if (ex == null) { + ex = new RuntimeException(cls + ": " + msg); + } + ex.setStackTrace(EMPTY_STACK_TRACE); + + Throwable cause = unparcelException(p); + if (cause != null) { + ex.initCause(ex); + } + + return ex; + } + @Override public int describeContents() { return 0; diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 2248b8853f8c..f0a346ab25fd 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -145,6 +145,11 @@ public final class Zygote { /** The lower file system should be bind mounted directly on external storage */ public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH; + /** Use the regular scoped storage filesystem, but Android/ should be writable. + * Used to support the applications hosting DownloadManager and the MTP server. + */ + public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE; + /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */ static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8; diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index d3499541a3a3..37f570bba238 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -376,6 +376,8 @@ class ZygoteArguments { mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY; } else if (arg.equals("--mount-external-pass-through")) { mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH; + } else if (arg.equals("--mount-external-android-writable")) { + mMountExternal = Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; } else if (arg.equals("--query-abi-list")) { mAbiListQuery = true; } else if (arg.equals("--get-pid")) { diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 8a59c998dacb..74b481c938c3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -218,6 +218,7 @@ public class SystemConfig { final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>(); private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); + private final ArraySet<String> mAppDataIsolationWhitelistedApps = new ArraySet<>(); // Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService(). private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>(); @@ -389,6 +390,10 @@ public class SystemConfig { return mRollbackWhitelistedPackages; } + public ArraySet<String> getAppDataIsolationWhitelistedApps() { + return mAppDataIsolationWhitelistedApps; + } + /** * Gets map of packagesNames to userTypes, dictating on which user types each package should be * initially installed, and then removes this map from SystemConfig. @@ -1045,6 +1050,16 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "app-data-isolation-whitelisted-app": { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mAppDataIsolationWhitelistedApps.add(pkgname); + } + XmlUtils.skipCurrentTag(parser); + } break; case "bugreport-whitelisted": { String pkgname = parser.getAttributeValue(null, "package"); if (pkgname == null) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d17d0a4ebbe2..5039213954d7 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -319,7 +319,8 @@ enum MountExternalKind { MOUNT_EXTERNAL_INSTALLER = 5, MOUNT_EXTERNAL_FULL = 6, MOUNT_EXTERNAL_PASS_THROUGH = 7, - MOUNT_EXTERNAL_COUNT = 8 + MOUNT_EXTERNAL_ANDROID_WRITABLE = 8, + MOUNT_EXTERNAL_COUNT = 9 }; // The order of entries here must be kept in sync with MountExternalKind enum values. @@ -331,6 +332,8 @@ static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorage "/mnt/runtime/write", // MOUNT_EXTERNAL_LEGACY "/mnt/runtime/write", // MOUNT_EXTERNAL_INSTALLER "/mnt/runtime/full", // MOUNT_EXTERNAL_FULL + "/mnt/runtime/full", // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE) + "/mnt/runtime/full", // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE) }; // Must match values in com.android.internal.os.Zygote. @@ -755,12 +758,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn); if (isFuse) { - if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH || mount_mode == - MOUNT_EXTERNAL_INSTALLER || mount_mode == MOUNT_EXTERNAL_FULL) { - // For now, MediaProvider, installers and "full" get the pass_through mount - // view, which is currently identical to the sdcardfs write view. - // - // TODO(b/146189163): scope down MOUNT_EXTERNAL_INSTALLER + if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) { BindMount(pass_through_source, "/storage", fail_fn); } else { BindMount(user_source, "/storage", fail_fn); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ea70dcf28e69..a808ed8fcc81 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4756,6 +4756,10 @@ <!-- Allows input events to be monitored. Very dangerous! @hide --> <permission android:name="android.permission.MONITOR_INPUT" android:protectionLevel="signature" /> + <!-- Allows the caller to change the associations between input devices and displays. + Very dangerous! @hide --> + <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT" + android:protectionLevel="signature" /> <!-- Allows query of any normal app on the device, regardless of manifest declarations. --> <permission android:name="android.permission.QUERY_ALL_PACKAGES" diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml index 1edd2cdfcfe3..d19e313055ae 100644 --- a/core/res/res/layout/accessibility_button_chooser_item.xml +++ b/core/res/res/layout/accessibility_button_chooser_item.xml @@ -36,7 +36,7 @@ android:id="@+id/accessibility_button_target_label" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" + android:layout_marginStart="14dp" android:layout_weight="1" android:textColor="?attr/textColorPrimary"/> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 66267d136e10..a0e40646ead9 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4358,10 +4358,7 @@ <string name="accessibility_shortcut_menu_button">Empty</string> <!-- Text in button that edit the accessibility shortcut menu. [CHAR LIMIT=100] --> - <string name="edit_accessibility_shortcut_menu_button">Edit</string> - - <!-- Text in button that save the accessibility shortcut menu changed status. [CHAR LIMIT=100] --> - <string name="save_accessibility_shortcut_menu_button">Save</string> + <string name="edit_accessibility_shortcut_menu_button">Edit shortcuts</string> <!-- Text in button that cancel the accessibility shortcut menu changed status. [CHAR LIMIT=100] --> <string name="cancel_accessibility_shortcut_menu_button">Cancel</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index cdbf14bf969a..973d5f6392f4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3212,7 +3212,6 @@ <java-symbol type="id" name="accessibility_button_target_switch_item" /> <java-symbol type="string" name="accessibility_magnification_chooser_text" /> <java-symbol type="string" name="edit_accessibility_shortcut_menu_button" /> - <java-symbol type="string" name="save_accessibility_shortcut_menu_button" /> <java-symbol type="string" name="cancel_accessibility_shortcut_menu_button" /> <java-symbol type="drawable" name="ic_accessibility_magnification" /> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java index f0a83678f70b..a296ca27e268 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java @@ -16,6 +16,7 @@ package com.android.connectivitymanagertest; +import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; @@ -136,7 +137,7 @@ public class WifiConfigurationHelper { config.enterpriseConfig.setPhase2Method(phase2); config.enterpriseConfig.setIdentity(identity); config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity); - config.enterpriseConfig.setCaCertificateAlias(caCert); + config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert}); config.enterpriseConfig.setClientCertificateAlias(clientCert); return config; } @@ -147,8 +148,12 @@ public class WifiConfigurationHelper { private static WifiConfiguration createGenericConfig(String ssid) { WifiConfiguration config = new WifiConfiguration(); config.SSID = quotedString(ssid); - config.setIpAssignment(IpAssignment.DHCP); - config.setProxySettings(ProxySettings.NONE); + + IpConfiguration ipConfiguration = config.getIpConfiguration(); + ipConfiguration.setIpAssignment(IpAssignment.DHCP); + ipConfiguration.setProxySettings(ProxySettings.NONE); + config.setIpConfiguration(ipConfiguration); + return config; } @@ -237,6 +242,7 @@ public class WifiConfigurationHelper { throw new IllegalArgumentException(); } + IpConfiguration ipConfiguration = config.getIpConfiguration(); if (jsonConfig.has("ip")) { StaticIpConfiguration staticIpConfig = new StaticIpConfiguration(); @@ -247,13 +253,14 @@ public class WifiConfigurationHelper { staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1"))); staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2"))); - config.setIpAssignment(IpAssignment.STATIC); - config.setStaticIpConfiguration(staticIpConfig); + ipConfiguration.setIpAssignment(IpAssignment.STATIC); + ipConfiguration.setStaticIpConfiguration(staticIpConfig); } else { - config.setIpAssignment(IpAssignment.DHCP); + ipConfiguration.setIpAssignment(IpAssignment.DHCP); } + ipConfiguration.setProxySettings(ProxySettings.NONE); + config.setIpConfiguration(ipConfiguration); - config.setProxySettings(ProxySettings.NONE); return config; } diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java index 2989df83866c..5d42915fc82b 100644 --- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java +++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java @@ -268,7 +268,7 @@ public class BandwidthTest extends InstrumentationTestCase { File snd_stat = new File (root_filepath + "tcp_snd"); int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat); NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, + stats.addEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE, rx, 0, tx, 0, 0); return stats; } diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java index 707d7b30e09b..239f971664e9 100644 --- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java +++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java @@ -54,7 +54,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 150000; recycle.txPackets = 1500; recycle.operations = 0; - mNetworkStats.addValues(recycle); + mNetworkStats.addEntry(recycle); if (recycle.set == 1) { uid++; } @@ -70,7 +70,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 180000 * mSize; recycle.txPackets = 1200 * mSize; recycle.operations = 0; - mNetworkStats.addValues(recycle); + mNetworkStats.addEntry(recycle); } } diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index beaaa373b1a0..d8b527c8a11a 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -438,8 +438,7 @@ public class ActivityThreadTest { } private static ClientTransaction newStopTransaction(Activity activity) { - final StopActivityItem stopStateRequest = - StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */); + final StopActivityItem stopStateRequest = StopActivityItem.obtain(0 /* configChanges */); final ClientTransaction transaction = newTransaction(activity); transaction.setLifecycleStateRequest(stopStateRequest); diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 37d21f0928be..4b29d59de332 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -274,30 +274,15 @@ public class ObjectPoolTests { @Test public void testRecycleStopItem() { - StopActivityItem emptyItem = StopActivityItem.obtain(false, 0); - StopActivityItem item = StopActivityItem.obtain(true, 4); + StopActivityItem emptyItem = StopActivityItem.obtain(0); + StopActivityItem item = StopActivityItem.obtain(4); assertNotSame(item, emptyItem); assertFalse(item.equals(emptyItem)); item.recycle(); assertEquals(item, emptyItem); - StopActivityItem item2 = StopActivityItem.obtain(true, 3); - assertSame(item, item2); - assertFalse(item2.equals(emptyItem)); - } - - @Test - public void testRecycleWindowVisibleItem() { - WindowVisibilityItem emptyItem = WindowVisibilityItem.obtain(false); - WindowVisibilityItem item = WindowVisibilityItem.obtain(true); - assertNotSame(item, emptyItem); - assertFalse(item.equals(emptyItem)); - - item.recycle(); - assertEquals(item, emptyItem); - - WindowVisibilityItem item2 = WindowVisibilityItem.obtain(true); + StopActivityItem item2 = StopActivityItem.obtain(3); assertSame(item, item2); assertFalse(item2.equals(emptyItem)); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 39bf7421b15e..ecea9011e704 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -61,6 +61,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -180,31 +181,6 @@ public class TransactionParcelTests { } @Test - public void testWindowVisibilityChange() { - // Write to parcel - WindowVisibilityItem item = WindowVisibilityItem.obtain(true /* showWindow */); - writeAndPrepareForReading(item); - - // Read from parcel and assert - WindowVisibilityItem result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel); - - assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); - - // Check different value - item = WindowVisibilityItem.obtain(false); - - mParcel = Parcel.obtain(); - writeAndPrepareForReading(item); - - // Read from parcel and assert - result = WindowVisibilityItem.CREATOR.createFromParcel(mParcel); - - assertEquals(item.hashCode(), result.hashCode()); - assertTrue(item.equals(result)); - } - - @Test public void testDestroy() { DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */, 135 /* configChanges */); @@ -299,8 +275,7 @@ public class TransactionParcelTests { @Test public void testStop() { // Write to parcel - StopActivityItem item = StopActivityItem.obtain(true /* showWindow */, - 14 /* configChanges */); + StopActivityItem item = StopActivityItem.obtain(14 /* configChanges */); writeAndPrepareForReading(item); // Read from parcel and assert @@ -311,14 +286,26 @@ public class TransactionParcelTests { } @Test + public void testStart() { + // Write to parcel + StartActivityItem item = StartActivityItem.obtain(); + writeAndPrepareForReading(item); + + // Read from parcel and assert + StartActivityItem result = StartActivityItem.CREATOR.createFromParcel(mParcel); + + assertEquals(item.hashCode(), result.hashCode()); + assertEquals(item, result); + } + + @Test public void testClientTransaction() { // Write to parcel - WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true); + NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true); ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain( config()); - StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */, - 78 /* configChanges */); + StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */); IApplicationThread appThread = new StubAppThread(); Binder activityToken = new Binder(); @@ -340,7 +327,7 @@ public class TransactionParcelTests { @Test public void testClientTransactionCallbacksOnly() { // Write to parcel - WindowVisibilityItem callback1 = WindowVisibilityItem.obtain(true); + NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true); ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain( config()); @@ -363,8 +350,7 @@ public class TransactionParcelTests { @Test public void testClientTransactionLifecycleOnly() { // Write to parcel - StopActivityItem lifecycleRequest = StopActivityItem.obtain(true /* showWindow */, - 78 /* configChanges */); + StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */); IApplicationThread appThread = new StubAppThread(); Binder activityToken = new Binder(); diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java index ffc925ff82cd..f108eb8aeb0b 100644 --- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java +++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java @@ -121,7 +121,12 @@ public class AndroidFutureTest { AndroidFuture future2 = AndroidFuture.CREATOR.createFromParcel(parcel); ExecutionException executionException = expectThrows(ExecutionException.class, future2::get); - assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class); + + Throwable cause = executionException.getCause(); + String msg = cause.getMessage(); + assertThat(cause).isInstanceOf(UnsupportedOperationException.class); + assertThat(msg).contains(getClass().getName()); + assertThat(msg).contains("testWriteToParcel_Exception"); } @Test diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 66d84aaf35cd..9018320e479c 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -79,138 +79,6 @@ public class ActivityThreadClientTest { @Test @UiThreadTest - public void testWindowVisibilityChange_OnCreate() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - clientSession.launchActivity(r); - assertEquals(ON_CREATE, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_CREATE, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_CREATE, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnCreate_Finished() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - Activity activity = clientSession.launchActivity(r); - activity.finish(); - assertEquals(ON_CREATE, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_CREATE, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_CREATE, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnStart() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - clientSession.launchActivity(r); - clientSession.startActivity(r); - assertEquals(ON_START, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_STOP, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_START, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnStart_Finished() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - Activity activity = clientSession.launchActivity(r); - clientSession.startActivity(r); - activity.finish(); - assertEquals(ON_START, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_STOP, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_START, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnResume() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - clientSession.launchActivity(r); - clientSession.startActivity(r); - clientSession.resumeActivity(r); - assertEquals(ON_RESUME, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_STOP, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_START, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnPause() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - clientSession.launchActivity(r); - clientSession.startActivity(r); - clientSession.resumeActivity(r); - clientSession.pauseActivity(r); - assertEquals(ON_PAUSE, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_STOP, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_START, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest - public void testWindowVisibilityChange_OnStop() throws Exception { - try (ClientMockSession clientSession = new ClientMockSession()) { - ActivityClientRecord r = clientSession.stubActivityRecord(); - - clientSession.launchActivity(r); - clientSession.startActivity(r); - clientSession.resumeActivity(r); - clientSession.pauseActivity(r); - clientSession.stopActivity(r); - assertEquals(ON_STOP, r.getLifecycleState()); - - clientSession.changeVisibility(r, true); - assertEquals(ON_START, r.getLifecycleState()); - - clientSession.changeVisibility(r, false); - assertEquals(ON_STOP, r.getLifecycleState()); - } - } - - @Test - @UiThreadTest public void testLifecycleAfterFinished_OnCreate() throws Exception { try (ClientMockSession clientSession = new ClientMockSession()) { ActivityClientRecord r = clientSession.stubActivityRecord(); @@ -308,7 +176,7 @@ public class ActivityThreadClientTest { } private void startActivity(ActivityClientRecord r) { - mThread.handleStartActivity(r, null /* pendingActions */); + mThread.handleStartActivity(r.token, null /* pendingActions */); } private void resumeActivity(ActivityClientRecord r) { @@ -323,7 +191,7 @@ public class ActivityThreadClientTest { } private void stopActivity(ActivityClientRecord r) { - mThread.handleStopActivity(r.token, false /* show */, 0 /* configChanges */, + mThread.handleStopActivity(r.token, 0 /* configChanges */, new PendingTransactionActions(), false /* finalStateRequest */, "test"); } @@ -332,10 +200,6 @@ public class ActivityThreadClientTest { false /* getNonConfigInstance */, "test"); } - private void changeVisibility(ActivityClientRecord r, boolean show) { - mThread.handleWindowVisibility(r.token, show); - } - private ActivityClientRecord stubActivityRecord() { ComponentName component = new ComponentName( InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class); diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd index cc01a31224bc..543504764ee3 100644 --- a/core/xsd/permission.xsd +++ b/core/xsd/permission.xsd @@ -46,6 +46,7 @@ <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/> <xs:element name="allow-association" type="allow-association"/> <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/> + <xs:element name="app-data-isolation-whitelisted-app" type="app-data-isolation-whitelisted-app"/> </xs:choice> </xs:complexType> </xs:element> @@ -161,6 +162,9 @@ <xs:attribute name="target" type="xs:string"/> <xs:attribute name="allowed" type="xs:string"/> </xs:complexType> + <xs:complexType name="app-data-isolation-whitelisted-app"> + <xs:attribute name="package" type="xs:string"/> + </xs:complexType> <xs:complexType name="bugreport-whitelisted"> <xs:attribute name="package" type="xs:string"/> </xs:complexType> diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt index 771c1dffb909..c36c422a852d 100644 --- a/core/xsd/schema/current.txt +++ b/core/xsd/schema/current.txt @@ -45,6 +45,12 @@ package com.android.xml.permission.configfile { method public void set_package(String); } + public class AppDataIsolationWhitelistedApp { + ctor public AppDataIsolationWhitelistedApp(); + method public String get_package(); + method public void set_package(String); + } + public class AppLink { ctor public AppLink(); method public String get_package(); @@ -160,6 +166,7 @@ package com.android.xml.permission.configfile { method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle_optional(); method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave_optional(); method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation_optional(); + method public java.util.List<com.android.xml.permission.configfile.AppDataIsolationWhitelistedApp> getAppDataIsolationWhitelistedApp_optional(); method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink_optional(); method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission_optional(); method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService_optional(); diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl index 02a381669893..51fa4eeaf4d8 100644 --- a/media/java/android/media/IMediaRoute2Provider.aidl +++ b/media/java/android/media/IMediaRoute2Provider.aidl @@ -25,7 +25,7 @@ import android.media.IMediaRoute2ProviderClient; oneway interface IMediaRoute2Provider { void setClient(IMediaRoute2ProviderClient client); void requestCreateSession(String packageName, String routeId, - String controlCategory, long requestId); + String routeType, long requestId); void releaseSession(int sessionId); void selectRoute(int sessionId, String routeId); diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl index b7cb7059ce3d..e8af21e59cc1 100644 --- a/media/java/android/media/IMediaRouter2Manager.aidl +++ b/media/java/android/media/IMediaRouter2Manager.aidl @@ -24,7 +24,7 @@ import android.media.MediaRoute2Info; */ oneway interface IMediaRouter2Manager { void notifyRouteSelected(String packageName, in MediaRoute2Info route); - void notifyControlCategoriesChanged(String packageName, in List<String> categories); + void notifyRouteTypesChanged(String packageName, in List<String> routeTypes); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); void notifyRoutesChanged(in List<MediaRoute2Info> routes); diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index e5b62ff10aa6..b573f64da51d 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -22,6 +22,7 @@ import android.media.IMediaRouter2Manager; import android.media.IMediaRouterClient; import android.media.MediaRoute2Info; import android.media.MediaRouterClientState; +import android.media.RouteDiscoveryRequest; import android.media.RouteSessionInfo; /** @@ -51,8 +52,8 @@ interface IMediaRouterService { void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction); void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route, - String controlCategory, int requestId); - void setControlCategories(IMediaRouter2Client client, in List<String> categories); + String routeType, int requestId); + void setDiscoveryRequest2(IMediaRouter2Client client, in RouteDiscoveryRequest request); void selectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route); void deselectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route); void transferToRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route); diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 4e6b4af56597..13640a438e7b 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -83,12 +83,14 @@ public final class MediaRoute2Info implements Parcelable { * controlled from this object. An example of fixed playback volume is a remote player, * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather * than attenuate at the source. + * * @see #getVolumeHandling() */ public static final int PLAYBACK_VOLUME_FIXED = 0; /** * Playback information indicating the playback volume is variable and can be controlled * from this object. + * * @see #getVolumeHandling() */ public static final int PLAYBACK_VOLUME_VARIABLE = 1; @@ -148,7 +150,7 @@ public final class MediaRoute2Info implements Parcelable { @Nullable final String mClientPackageName; @NonNull - final List<String> mSupportedCategories; + final List<String> mRouteTypes; final int mVolume; final int mVolumeMax; final int mVolumeHandling; @@ -164,7 +166,7 @@ public final class MediaRoute2Info implements Parcelable { mConnectionState = builder.mConnectionState; mIconUri = builder.mIconUri; mClientPackageName = builder.mClientPackageName; - mSupportedCategories = builder.mSupportedCategories; + mRouteTypes = builder.mRouteTypes; mVolume = builder.mVolume; mVolumeMax = builder.mVolumeMax; mVolumeHandling = builder.mVolumeHandling; @@ -180,7 +182,7 @@ public final class MediaRoute2Info implements Parcelable { mConnectionState = in.readInt(); mIconUri = in.readParcelable(null); mClientPackageName = in.readString(); - mSupportedCategories = in.createStringArrayList(); + mRouteTypes = in.createStringArrayList(); mVolume = in.readInt(); mVolumeMax = in.readInt(); mVolumeHandling = in.readInt(); @@ -226,7 +228,7 @@ public final class MediaRoute2Info implements Parcelable { && (mConnectionState == other.mConnectionState) && Objects.equals(mIconUri, other.mIconUri) && Objects.equals(mClientPackageName, other.mClientPackageName) - && Objects.equals(mSupportedCategories, other.mSupportedCategories) + && Objects.equals(mRouteTypes, other.mRouteTypes) && (mVolume == other.mVolume) && (mVolumeMax == other.mVolumeMax) && (mVolumeHandling == other.mVolumeHandling) @@ -238,7 +240,7 @@ public final class MediaRoute2Info implements Parcelable { @Override public int hashCode() { return Objects.hash(mId, mName, mDescription, mConnectionState, mIconUri, - mSupportedCategories, mVolume, mVolumeMax, mVolumeHandling, mDeviceType); + mRouteTypes, mVolume, mVolumeMax, mVolumeHandling, mDeviceType); } /** @@ -327,8 +329,8 @@ public final class MediaRoute2Info implements Parcelable { * Gets the supported categories of the route. */ @NonNull - public List<String> getSupportedCategories() { - return mSupportedCategories; + public List<String> getRouteTypes() { + return mRouteTypes; } //TODO: once device types are confirmed, reflect those into the comment. @@ -372,32 +374,15 @@ public final class MediaRoute2Info implements Parcelable { } /** - * Returns if the route supports the specified control category - * - * @param controlCategory control category to consider - * @return true if the route supports at the category - */ - public boolean supportsControlCategory(@NonNull String controlCategory) { - Objects.requireNonNull(controlCategory, "control category must not be null"); - for (String supportedCategory : getSupportedCategories()) { - if (TextUtils.equals(controlCategory, supportedCategory)) { - return true; - } - } - return false; - } - - //TODO: Move this if we re-define control category / selector things. - /** - * Returns if the route supports at least one of the specified control categories + * Returns if the route contains at least one of the specified route types. * - * @param controlCategories the list of control categories to consider - * @return true if the route supports at least one category + * @param routeTypes the list of route types to consider + * @return true if the route contains at least one type in the list */ - public boolean supportsControlCategories(@NonNull Collection<String> controlCategories) { - Objects.requireNonNull(controlCategories, "control categories must not be null"); - for (String controlCategory : controlCategories) { - if (supportsControlCategory(controlCategory)) { + public boolean containsRouteTypes(@NonNull Collection<String> routeTypes) { + Objects.requireNonNull(routeTypes, "routeTypes must not be null"); + for (String routeType : routeTypes) { + if (getRouteTypes().contains(routeType)) { return true; } } @@ -418,7 +403,7 @@ public final class MediaRoute2Info implements Parcelable { dest.writeInt(mConnectionState); dest.writeParcelable(mIconUri, flags); dest.writeString(mClientPackageName); - dest.writeStringList(mSupportedCategories); + dest.writeStringList(mRouteTypes); dest.writeInt(mVolume); dest.writeInt(mVolumeMax); dest.writeInt(mVolumeHandling); @@ -456,7 +441,7 @@ public final class MediaRoute2Info implements Parcelable { int mConnectionState; Uri mIconUri; String mClientPackageName; - List<String> mSupportedCategories; + List<String> mRouteTypes; int mVolume; int mVolumeMax; int mVolumeHandling = PLAYBACK_VOLUME_FIXED; @@ -467,7 +452,7 @@ public final class MediaRoute2Info implements Parcelable { public Builder(@NonNull String id, @NonNull CharSequence name) { setId(id); setName(name); - mSupportedCategories = new ArrayList<>(); + mRouteTypes = new ArrayList<>(); } public Builder(@NonNull MediaRoute2Info routeInfo) { @@ -484,7 +469,7 @@ public final class MediaRoute2Info implements Parcelable { mConnectionState = routeInfo.mConnectionState; mIconUri = routeInfo.mIconUri; setClientPackageName(routeInfo.mClientPackageName); - setSupportedCategories(routeInfo.mSupportedCategories); + setRouteTypes(routeInfo.mRouteTypes); setVolume(routeInfo.mVolume); setVolumeMax(routeInfo.mVolumeMax); setVolumeHandling(routeInfo.mVolumeHandling); @@ -589,35 +574,35 @@ public final class MediaRoute2Info implements Parcelable { } /** - * Sets the supported categories of the route. + * Sets the types of the route. */ @NonNull - public Builder setSupportedCategories(@NonNull Collection<String> categories) { - mSupportedCategories = new ArrayList<>(); - return addSupportedCategories(categories); + public Builder setRouteTypes(@NonNull Collection<String> routeTypes) { + mRouteTypes = new ArrayList<>(); + return addRouteTypes(routeTypes); } /** - * Adds supported categories for the route. + * Adds types for the route. */ @NonNull - public Builder addSupportedCategories(@NonNull Collection<String> categories) { - Objects.requireNonNull(categories, "categories must not be null"); - for (String category: categories) { - addSupportedCategory(category); + public Builder addRouteTypes(@NonNull Collection<String> routeTypes) { + Objects.requireNonNull(routeTypes, "routeTypes must not be null"); + for (String routeType: routeTypes) { + addRouteType(routeType); } return this; } /** - * Add a supported category for the route. + * Add a type for the route. */ @NonNull - public Builder addSupportedCategory(@NonNull String category) { - if (TextUtils.isEmpty(category)) { - throw new IllegalArgumentException("category must not be null or empty"); + public Builder addRouteType(@NonNull String routeType) { + if (TextUtils.isEmpty(routeType)) { + throw new IllegalArgumentException("routeType must not be null or empty"); } - mSupportedCategories.add(category); + mRouteTypes.add(routeType); return this; } diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index 99bd1dcde3bb..91cc44807a73 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -246,11 +246,11 @@ public abstract class MediaRoute2ProviderService extends Service { * * @param packageName the package name of the application that selected the route * @param routeId the id of the route initially being connected - * @param controlCategory the control category of the new session + * @param routeType the route type of the new session * @param requestId the id of this session creation request */ public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId, - @NonNull String controlCategory, long requestId); + @NonNull String routeType, long requestId); /** * Called when a session is about to be destroyed. @@ -301,6 +301,25 @@ public abstract class MediaRoute2ProviderService extends Service { public abstract void onTransferToRoute(int sessionId, @NonNull String routeId); /** + * Called when the {@link RouteDiscoveryRequest discovery request} has changed. + * <p> + * Whenever an application registers a {@link MediaRouter2.RouteCallback callback}, + * it also provides a discovery request to specify types of routes that it is interested in. + * The media router combines all of these discovery request into a single discovery request + * and notifies each provider. + * </p><p> + * The provider should examine {@link RouteDiscoveryRequest#getRouteTypes() route types} + * in the discovery request to determine what kind of routes it should try to discover + * and whether it should perform active or passive scans. In many cases, the provider may be + * able to save power by not performing any scans when the request doesn't have any matching + * route types. + * </p> + * + * @param request the new discovery request + */ + public void onDiscoveryRequestChanged(@NonNull RouteDiscoveryRequest request) {} + + /** * Updates provider info and publishes routes and session info. */ public final void updateProviderInfo(@NonNull MediaRoute2ProviderInfo providerInfo) { @@ -357,12 +376,12 @@ public abstract class MediaRoute2ProviderService extends Service { @Override public void requestCreateSession(String packageName, String routeId, - String controlCategory, long requestId) { + String routeType, long requestId) { if (!checkCallerisSystem()) { return; } mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession, - MediaRoute2ProviderService.this, packageName, routeId, controlCategory, + MediaRoute2ProviderService.this, packageName, routeId, routeType, requestId)); } @Override diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index bddfa6930b11..dea8b045e72a 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -39,7 +39,6 @@ import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -48,6 +47,7 @@ import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * A new Media Router @@ -118,7 +118,7 @@ public class MediaRouter2 { final Map<String, MediaRoute2Info> mRoutes = new HashMap<>(); @GuardedBy("sLock") - private List<String> mControlCategories = Collections.emptyList(); + private RouteDiscoveryRequest mDiscoveryRequest = RouteDiscoveryRequest.EMPTY; // TODO: Make MediaRouter2 is always connected to the MediaRouterService. @GuardedBy("sLock") @@ -152,7 +152,6 @@ public class MediaRouter2 { mMediaRouterService = IMediaRouterService.Stub.asInterface( ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); mPackageName = mContext.getPackageName(); - //TODO: read control categories from the manifest mHandler = new Handler(Looper.getMainLooper()); List<MediaRoute2Info> currentSystemRoutes = null; @@ -188,24 +187,18 @@ public class MediaRouter2 { /** * Registers a callback to discover routes and to receive events when they change. - */ - public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull RouteCallback routeCallback) { - registerRouteCallback(executor, routeCallback, 0); - } - - /** - * Registers a callback to discover routes and to receive events when they change. * <p> * If you register the same callback twice or more, it will be ignored. * </p> */ public void registerRouteCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull RouteCallback routeCallback, int flags) { + @NonNull RouteCallback routeCallback, + @NonNull RouteDiscoveryRequest request) { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(routeCallback, "callback must not be null"); + Objects.requireNonNull(request, "request must not be null"); - RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, flags); + RouteCallbackRecord record = new RouteCallbackRecord(executor, routeCallback, request); if (!mRouteCallbackRecords.addIfAbsent(record)) { Log.w(TAG, "Ignoring the same callback"); return; @@ -216,7 +209,8 @@ public class MediaRouter2 { Client2 client = new Client2(); try { mMediaRouterService.registerClient2(client, mPackageName); - mMediaRouterService.setControlCategories(client, mControlCategories); + updateDiscoveryRequestLocked(); + mMediaRouterService.setDiscoveryRequest2(client, mDiscoveryRequest); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router.", ex); @@ -238,7 +232,7 @@ public class MediaRouter2 { Objects.requireNonNull(routeCallback, "callback must not be null"); if (!mRouteCallbackRecords.remove( - new RouteCallbackRecord(null, routeCallback, 0))) { + new RouteCallbackRecord(null, routeCallback, null))) { Log.w(TAG, "Ignoring unknown callback"); return; } @@ -256,30 +250,10 @@ public class MediaRouter2 { } } - //TODO(b/139033746): Rename "Control Category" when it's finalized. - /** - * Sets the control categories of the application. - * Routes that support at least one of the given control categories are handled - * by the media router. - */ - public void setControlCategories(@NonNull Collection<String> controlCategories) { - Objects.requireNonNull(controlCategories, "control categories must not be null"); - - List<String> newControlCategories = new ArrayList<>(controlCategories); - - synchronized (sRouterLock) { - mShouldUpdateRoutes = true; - - // invoke callbacks due to control categories change - handleControlCategoriesChangedLocked(newControlCategories); - if (mClient != null) { - try { - mMediaRouterService.setControlCategories(mClient, mControlCategories); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to set control categories.", ex); - } - } - } + private void updateDiscoveryRequestLocked() { + mDiscoveryRequest = new RouteDiscoveryRequest.Builder( + mRouteCallbackRecords.stream().map(record -> record.mRequest).collect( + Collectors.toList())).build(); } /** @@ -287,8 +261,8 @@ public class MediaRouter2 { * known to the media router. * Please note that the list can be changed before callbacks are invoked. * - * @return the list of routes that support at least one of the control categories set by - * the application + * @return the list of routes that contains at least one of the route types in discovery + * requests registered by the application */ @NonNull public List<MediaRoute2Info> getRoutes() { @@ -298,7 +272,7 @@ public class MediaRouter2 { List<MediaRoute2Info> filteredRoutes = new ArrayList<>(); for (MediaRoute2Info route : mRoutes.values()) { - if (route.supportsControlCategories(mControlCategories)) { + if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) { filteredRoutes.add(route); } } @@ -350,26 +324,26 @@ public class MediaRouter2 { * Requests the media route provider service to create a session with the given route. * * @param route the route you want to create a session with. - * @param controlCategory the control category of the session. Should not be empty + * @param routeType the route type of the session. Should not be empty * * @see SessionCallback#onSessionCreated * @see SessionCallback#onSessionCreationFailed */ @NonNull public void requestCreateSession(@NonNull MediaRoute2Info route, - @NonNull String controlCategory) { + @NonNull String routeType) { Objects.requireNonNull(route, "route must not be null"); - if (TextUtils.isEmpty(controlCategory)) { - throw new IllegalArgumentException("controlCategory must not be empty"); + if (TextUtils.isEmpty(routeType)) { + throw new IllegalArgumentException("routeType must not be empty"); } // TODO: Check the given route exists - // TODO: Check the route supports the given controlCategory + // TODO: Check the route supports the given routeType final int requestId; requestId = mSessionCreationRequestCnt.getAndIncrement(); SessionCreationRequest request = new SessionCreationRequest( - requestId, route, controlCategory); + requestId, route, routeType); mSessionCreationRequests.add(request); Client2 client; @@ -379,7 +353,7 @@ public class MediaRouter2 { if (client != null) { try { mMediaRouterService.requestCreateSession( - client, route, controlCategory, requestId); + client, route, routeType, requestId); } catch (RemoteException ex) { Log.e(TAG, "Unable to request to create session.", ex); mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler, @@ -461,36 +435,6 @@ public class MediaRouter2 { } } - private void handleControlCategoriesChangedLocked(List<String> newControlCategories) { - List<MediaRoute2Info> addedRoutes = new ArrayList<>(); - List<MediaRoute2Info> removedRoutes = new ArrayList<>(); - - List<String> prevControlCategories = mControlCategories; - mControlCategories = newControlCategories; - - for (MediaRoute2Info route : mRoutes.values()) { - boolean preSupported = route.supportsControlCategories(prevControlCategories); - boolean postSupported = route.supportsControlCategories(newControlCategories); - if (preSupported == postSupported) { - continue; - } - if (preSupported) { - removedRoutes.add(route); - } else { - addedRoutes.add(route); - } - } - - if (removedRoutes.size() > 0) { - mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesRemoved, - MediaRouter2.this, removedRoutes)); - } - if (addedRoutes.size() > 0) { - mHandler.sendMessage(obtainMessage(MediaRouter2::notifyRoutesAdded, - MediaRouter2.this, addedRoutes)); - } - } - void addRoutesOnHandler(List<MediaRoute2Info> routes) { // TODO: When onRoutesAdded is first called, // 1) clear mRoutes before adding the routes @@ -500,7 +444,7 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); - if (route.supportsControlCategories(mControlCategories)) { + if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) { addedRoutes.add(route); } } @@ -516,7 +460,7 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.remove(route.getId()); - if (route.supportsControlCategories(mControlCategories)) { + if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) { removedRoutes.add(route); } } @@ -532,7 +476,7 @@ public class MediaRouter2 { synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { mRoutes.put(route.getId(), route); - if (route.supportsControlCategories(mControlCategories)) { + if (route.containsRouteTypes(mDiscoveryRequest.getRouteTypes())) { changedRoutes.add(route); } } @@ -562,27 +506,27 @@ public class MediaRouter2 { mSessionCreationRequests.remove(matchingRequest); MediaRoute2Info requestedRoute = matchingRequest.mRoute; - String requestedControlCategory = matchingRequest.mControlCategory; + String requestedRouteType = matchingRequest.mRouteType; if (sessionInfo == null) { // TODO: We may need to distinguish between failure and rejection. // One way can be introducing 'reason'. - notifySessionCreationFailed(requestedRoute, requestedControlCategory); + notifySessionCreationFailed(requestedRoute, requestedRouteType); return; - } else if (!TextUtils.equals(requestedControlCategory, - sessionInfo.getControlCategory())) { - Log.w(TAG, "The session has different control category from what we requested. " - + "(requested=" + requestedControlCategory - + ", actual=" + sessionInfo.getControlCategory() + } else if (!TextUtils.equals(requestedRouteType, + sessionInfo.getRouteType())) { + Log.w(TAG, "The session has different route type from what we requested. " + + "(requested=" + requestedRouteType + + ", actual=" + sessionInfo.getRouteType() + ")"); - notifySessionCreationFailed(requestedRoute, requestedControlCategory); + notifySessionCreationFailed(requestedRoute, requestedRouteType); return; } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) { Log.w(TAG, "The session does not contain the requested route. " + "(requestedRouteId=" + requestedRoute.getId() + ", actualRoutes=" + sessionInfo.getSelectedRoutes() + ")"); - notifySessionCreationFailed(requestedRoute, requestedControlCategory); + notifySessionCreationFailed(requestedRoute, requestedRouteType); return; } else if (!TextUtils.equals(requestedRoute.getProviderId(), sessionInfo.getProviderId())) { @@ -590,7 +534,7 @@ public class MediaRouter2 { + "(requested route's providerId=" + requestedRoute.getProviderId() + ", actual providerId=" + sessionInfo.getProviderId() + ")"); - notifySessionCreationFailed(requestedRoute, requestedControlCategory); + notifySessionCreationFailed(requestedRoute, requestedRouteType); return; } } @@ -666,24 +610,41 @@ public class MediaRouter2 { notifyControllerReleased(matchingController); } + private List<MediaRoute2Info> filterRoutes(List<MediaRoute2Info> routes, + RouteDiscoveryRequest discoveryRequest) { + return routes.stream() + .filter( + route -> route.containsRouteTypes(discoveryRequest.getRouteTypes())) + .collect(Collectors.toList()); + } + private void notifyRoutesAdded(List<MediaRoute2Info> routes) { for (RouteCallbackRecord record: mRouteCallbackRecords) { - record.mExecutor.execute( - () -> record.mRouteCallback.onRoutesAdded(routes)); + List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest); + if (!filteredRoutes.isEmpty()) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesAdded(filteredRoutes)); + } } } private void notifyRoutesRemoved(List<MediaRoute2Info> routes) { for (RouteCallbackRecord record: mRouteCallbackRecords) { - record.mExecutor.execute( - () -> record.mRouteCallback.onRoutesRemoved(routes)); + List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest); + if (!filteredRoutes.isEmpty()) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesRemoved(filteredRoutes)); + } } } private void notifyRoutesChanged(List<MediaRoute2Info> routes) { for (RouteCallbackRecord record: mRouteCallbackRecords) { - record.mExecutor.execute( - () -> record.mRouteCallback.onRoutesChanged(routes)); + List<MediaRoute2Info> filteredRoutes = filterRoutes(routes, record.mRequest); + if (!filteredRoutes.isEmpty()) { + record.mExecutor.execute( + () -> record.mRouteCallback.onRoutesChanged(filteredRoutes)); + } } } @@ -694,10 +655,10 @@ public class MediaRouter2 { } } - private void notifySessionCreationFailed(MediaRoute2Info route, String controlCategory) { + private void notifySessionCreationFailed(MediaRoute2Info route, String routeType) { for (SessionCallbackRecord record: mSessionCallbackRecords) { record.mExecutor.execute( - () -> record.mSessionCallback.onSessionCreationFailed(route, controlCategory)); + () -> record.mSessionCallback.onSessionCreationFailed(route, routeType)); } } @@ -764,10 +725,10 @@ public class MediaRouter2 { * Called when the session creation request failed. * * @param requestedRoute the route info which was used for the request - * @param requestedControlCategory the control category which was used for the request + * @param requestedRouteType the route type which was used for the request */ public void onSessionCreationFailed(@NonNull MediaRoute2Info requestedRoute, - @NonNull String requestedControlCategory) {} + @NonNull String requestedRouteType) {} /** * Called when the session info has changed. @@ -840,12 +801,12 @@ public class MediaRouter2 { } /** - * @return the category of routes that the session includes. + * @return the type of routes that the session includes. */ @NonNull - public String getControlCategory() { + public String getRouteType() { synchronized (mControllerLock) { - return mSessionInfo.getControlCategory(); + return mSessionInfo.getRouteType(); } } @@ -1104,11 +1065,11 @@ public class MediaRouter2 { // TODO: This method uses two locks (mLock outside, sLock inside). // Check if there is any possiblity of deadlock. private List<MediaRoute2Info> getRoutesWithIdsLocked(List<String> routeIds) { + List<MediaRoute2Info> routes = new ArrayList<>(); synchronized (sRouterLock) { for (String routeId : routeIds) { - MediaRoute2Info route = mRoutes.get( - MediaRoute2Info.toUniqueId(mSessionInfo.mProviderId, routeId)); + MediaRoute2Info route = mRoutes.get(routeId); if (route != null) { routes.add(route); } @@ -1121,13 +1082,13 @@ public class MediaRouter2 { final class RouteCallbackRecord { public final Executor mExecutor; public final RouteCallback mRouteCallback; - public final int mFlags; + public final RouteDiscoveryRequest mRequest; RouteCallbackRecord(@Nullable Executor executor, @NonNull RouteCallback routeCallback, - int flags) { + @Nullable RouteDiscoveryRequest request) { mRouteCallback = routeCallback; mExecutor = executor; - mFlags = flags; + mRequest = request; } @Override @@ -1176,13 +1137,13 @@ public class MediaRouter2 { final class SessionCreationRequest { public final MediaRoute2Info mRoute; - public final String mControlCategory; + public final String mRouteType; public final int mRequestId; SessionCreationRequest(int requestId, @NonNull MediaRoute2Info route, - @NonNull String controlCategory) { + @NonNull String routeType) { mRoute = route; - mControlCategory = controlCategory; + mRouteType = routeType; mRequestId = requestId; } } diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 3cbbea1f3c07..1e6ec51442d6 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -65,7 +65,7 @@ public class MediaRouter2Manager { @GuardedBy("mRoutesLock") private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>(); @NonNull - final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>(); + final ConcurrentMap<String, List<String>> mRouteTypeMap = new ConcurrentHashMap<>(); private AtomicInteger mNextRequestId = new AtomicInteger(1); @@ -144,7 +144,7 @@ public class MediaRouter2Manager { } //TODO: clear mRoutes? mClient = null; - mControlCategoryMap.clear(); + mRouteTypeMap.clear(); } } } @@ -160,14 +160,14 @@ public class MediaRouter2Manager { public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) { Objects.requireNonNull(packageName, "packageName must not be null"); - List<String> controlCategories = mControlCategoryMap.get(packageName); - if (controlCategories == null) { + List<String> routeTypes = mRouteTypeMap.get(packageName); + if (routeTypes == null) { return Collections.emptyList(); } List<MediaRoute2Info> routes = new ArrayList<>(); synchronized (mRoutesLock) { for (MediaRoute2Info route : mRoutes.values()) { - if (route.supportsControlCategories(controlCategories)) { + if (route.containsRouteTypes(routeTypes)) { routes.add(route); } } @@ -352,15 +352,15 @@ public class MediaRouter2Manager { } } - void updateControlCategories(String packageName, List<String> categories) { - List<String> prevCategories = mControlCategoryMap.put(packageName, categories); - if ((prevCategories == null && categories.size() == 0) - || Objects.equals(categories, prevCategories)) { + void updateRouteTypes(String packageName, List<String> routeTypes) { + List<String> prevTypes = mRouteTypeMap.put(packageName, routeTypes); + if ((prevTypes == null && routeTypes.size() == 0) + || Objects.equals(routeTypes, prevTypes)) { return; } for (CallbackRecord record : mCallbackRecords) { record.mExecutor.execute( - () -> record.mCallback.onControlCategoriesChanged(packageName, categories)); + () -> record.mCallback.onControlCategoriesChanged(packageName, routeTypes)); } } @@ -398,13 +398,13 @@ public class MediaRouter2Manager { /** - * Called when the control categories of an app is changed. + * Called when the route types of an app is changed. * * @param packageName the package name of the application - * @param controlCategories the list of control categories set by an application. + * @param routeTypes the list of route types set by an application. */ public void onControlCategoriesChanged(@NonNull String packageName, - @NonNull List<String> controlCategories) {} + @NonNull List<String> routeTypes) {} } final class CallbackRecord { @@ -440,10 +440,9 @@ public class MediaRouter2Manager { MediaRouter2Manager.this, packageName, route)); } - @Override - public void notifyControlCategoriesChanged(String packageName, List<String> categories) { - mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateControlCategories, - MediaRouter2Manager.this, packageName, categories)); + public void notifyRouteTypesChanged(String packageName, List<String> routeTypes) { + mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateRouteTypes, + MediaRouter2Manager.this, packageName, routeTypes)); } @Override diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java index 40e90731f2a2..05fa511fc81a 100644 --- a/media/java/android/media/MediaScannerConnection.java +++ b/media/java/android/media/MediaScannerConnection.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; diff --git a/media/java/android/media/RouteDiscoveryRequest.aidl b/media/java/android/media/RouteDiscoveryRequest.aidl new file mode 100644 index 000000000000..744f6569325d --- /dev/null +++ b/media/java/android/media/RouteDiscoveryRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 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 android.media; + +parcelable RouteDiscoveryRequest; diff --git a/media/java/android/media/RouteDiscoveryRequest.java b/media/java/android/media/RouteDiscoveryRequest.java new file mode 100644 index 000000000000..88b31fb30ffc --- /dev/null +++ b/media/java/android/media/RouteDiscoveryRequest.java @@ -0,0 +1,200 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + + +/** + * @hide + */ +public final class RouteDiscoveryRequest implements Parcelable { + @NonNull + public static final Creator<RouteDiscoveryRequest> CREATOR = + new Creator<RouteDiscoveryRequest>() { + @Override + public RouteDiscoveryRequest createFromParcel(Parcel in) { + return new RouteDiscoveryRequest(in); + } + + @Override + public RouteDiscoveryRequest[] newArray(int size) { + return new RouteDiscoveryRequest[size]; + } + }; + + @NonNull + private final List<String> mRouteTypes; + private final boolean mActiveScan; + @Nullable + private final Bundle mExtras; + + /** + * @hide + */ + public static final RouteDiscoveryRequest EMPTY = + new Builder(Collections.emptyList(), false).build(); + + RouteDiscoveryRequest(@NonNull Builder builder) { + mRouteTypes = builder.mRouteTypes; + mActiveScan = builder.mActiveScan; + mExtras = builder.mExtras; + } + + RouteDiscoveryRequest(@NonNull Parcel in) { + mRouteTypes = in.createStringArrayList(); + mActiveScan = in.readBoolean(); + mExtras = in.readBundle(); + } + + @NonNull + public List<String> getRouteTypes() { + return mRouteTypes; + } + + public boolean isActiveScan() { + return mActiveScan; + } + + /** + * @hide + */ + public Bundle getExtras() { + return mExtras; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStringList(mRouteTypes); + dest.writeBoolean(mActiveScan); + dest.writeBundle(mExtras); + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder() + .append("RouteDiscoveryRequest{ ") + .append("routeTypes={") + .append(String.join(", ", mRouteTypes)) + .append("}") + .append(", activeScan=") + .append(mActiveScan) + .append(" }"); + + return result.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RouteDiscoveryRequest)) { + return false; + } + RouteDiscoveryRequest other = (RouteDiscoveryRequest) o; + return Objects.equals(mRouteTypes, other.mRouteTypes) + && mActiveScan == other.mActiveScan; + } + + /** + * Builder for {@link RouteDiscoveryRequest}. + */ + public static final class Builder { + List<String> mRouteTypes; + boolean mActiveScan; + Bundle mExtras; + + public Builder(@NonNull List<String> routeTypes, boolean activeScan) { + mRouteTypes = new ArrayList<>( + Objects.requireNonNull(routeTypes, "routeTypes must not be null")); + mActiveScan = activeScan; + } + + public Builder(@NonNull RouteDiscoveryRequest request) { + Objects.requireNonNull(request, "request must not be null"); + + mRouteTypes = request.getRouteTypes(); + mActiveScan = request.isActiveScan(); + mExtras = request.getExtras(); + } + + /** + * A constructor to combine all of the requests into a single request. + * It ignores extras of requests. + */ + Builder(@NonNull Collection<RouteDiscoveryRequest> requests) { + Set<String> routeTypeSet = new HashSet<>(); + mActiveScan = false; + for (RouteDiscoveryRequest request : requests) { + routeTypeSet.addAll(request.mRouteTypes); + mActiveScan |= request.mActiveScan; + } + mRouteTypes = new ArrayList<>(routeTypeSet); + } + + /** + * Sets route types to discover. + */ + public Builder setRouteTypes(@NonNull List<String> routeTypes) { + mRouteTypes = new ArrayList<>( + Objects.requireNonNull(routeTypes, "routeTypes must not be null")); + return this; + } + + /** + * Sets if active scanning should be performed. + */ + public Builder setActiveScan(boolean activeScan) { + mActiveScan = activeScan; + return this; + } + + /** + * Sets the extras of the route. + * @hide + */ + public Builder setExtras(@Nullable Bundle extras) { + mExtras = extras; + return this; + } + + /** + * Builds the {@link RouteDiscoveryRequest}. + */ + public RouteDiscoveryRequest build() { + return new RouteDiscoveryRequest(this); + } + } +} diff --git a/media/java/android/media/RouteSessionInfo.java b/media/java/android/media/RouteSessionInfo.java index 4a9298ac64be..cb1688600fac 100644 --- a/media/java/android/media/RouteSessionInfo.java +++ b/media/java/android/media/RouteSessionInfo.java @@ -48,7 +48,7 @@ public class RouteSessionInfo implements Parcelable { final int mSessionId; final String mPackageName; - final String mControlCategory; + final String mRouteType; @Nullable final String mProviderId; final List<String> mSelectedRoutes; @@ -63,7 +63,7 @@ public class RouteSessionInfo implements Parcelable { mSessionId = builder.mSessionId; mPackageName = builder.mPackageName; - mControlCategory = builder.mControlCategory; + mRouteType = builder.mRouteType; mProviderId = builder.mProviderId; mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes); @@ -79,7 +79,7 @@ public class RouteSessionInfo implements Parcelable { mSessionId = src.readInt(); mPackageName = ensureString(src.readString()); - mControlCategory = ensureString(src.readString()); + mRouteType = ensureString(src.readString()); mProviderId = src.readString(); mSelectedRoutes = ensureList(src.createStringArrayList()); @@ -154,7 +154,7 @@ public class RouteSessionInfo implements Parcelable { */ public boolean isValid() { return !TextUtils.isEmpty(mPackageName) - && !TextUtils.isEmpty(mControlCategory) + && !TextUtils.isEmpty(mRouteType) && mSelectedRoutes.size() > 0; } @@ -175,12 +175,12 @@ public class RouteSessionInfo implements Parcelable { } /** - * Gets the control category of the session. - * Routes that don't support the category can't be added to the session. + * Gets the route type of the session. + * Routes that don't have the type can't be added to the session. */ @NonNull - public String getControlCategory() { - return mControlCategory; + public String getRouteType() { + return mRouteType; } /** @@ -254,7 +254,7 @@ public class RouteSessionInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSessionId); dest.writeString(mPackageName); - dest.writeString(mControlCategory); + dest.writeString(mRouteType); dest.writeString(mProviderId); dest.writeStringList(mSelectedRoutes); dest.writeStringList(mSelectableRoutes); @@ -268,7 +268,7 @@ public class RouteSessionInfo implements Parcelable { StringBuilder result = new StringBuilder() .append("RouteSessionInfo{ ") .append("sessionId=").append(mSessionId) - .append(", controlCategory=").append(mControlCategory) + .append(", routeType=").append(mRouteType) .append(", selectedRoutes={") .append(String.join(",", mSelectedRoutes)) .append("}") @@ -291,7 +291,7 @@ public class RouteSessionInfo implements Parcelable { public static final class Builder { final String mPackageName; final int mSessionId; - final String mControlCategory; + final String mRouteType; String mProviderId; final List<String> mSelectedRoutes; final List<String> mSelectableRoutes; @@ -300,11 +300,11 @@ public class RouteSessionInfo implements Parcelable { Bundle mControlHints; public Builder(int sessionId, @NonNull String packageName, - @NonNull String controlCategory) { + @NonNull String routeType) { mSessionId = sessionId; mPackageName = Objects.requireNonNull(packageName, "packageName must not be null"); - mControlCategory = Objects.requireNonNull(controlCategory, - "controlCategory must not be null"); + mRouteType = Objects.requireNonNull(routeType, + "routeType must not be null"); mSelectedRoutes = new ArrayList<>(); mSelectableRoutes = new ArrayList<>(); @@ -315,7 +315,7 @@ public class RouteSessionInfo implements Parcelable { public Builder(RouteSessionInfo sessionInfo) { mSessionId = sessionInfo.mSessionId; mPackageName = sessionInfo.mPackageName; - mControlCategory = sessionInfo.mControlCategory; + mRouteType = sessionInfo.mRouteType; mProviderId = sessionInfo.mProviderId; mSelectedRoutes = new ArrayList<>(sessionInfo.mSelectedRoutes); diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index 56e5566df29c..77596a5de815 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java +++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java @@ -22,7 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index 61b3e76e7cee..1c38301c7935 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.hardware.soundtrigger.ModelParams; diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 1b9cac0c8c99..377b2bc19c6b 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.StringRes; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 5c11ed9bb7b4..7fbb3376d5fb 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -22,9 +22,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index c17beba2b9d1..4318a0ae7d06 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -63,6 +63,7 @@ public final class TvTrackInfo implements Parcelable { private final int mAudioSampleRate; private final boolean mAudioDescription; private final boolean mHardOfHearing; + private final boolean mSpokenSubtitle; private final int mVideoWidth; private final int mVideoHeight; private final float mVideoFrameRate; @@ -73,8 +74,9 @@ public final class TvTrackInfo implements Parcelable { private TvTrackInfo(int type, String id, String language, CharSequence description, boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription, - boolean hardOfHearing, int videoWidth, int videoHeight, float videoFrameRate, - float videoPixelAspectRatio, byte videoActiveFormatDescription, Bundle extra) { + boolean hardOfHearing, boolean spokenSubtitle, int videoWidth, int videoHeight, + float videoFrameRate, float videoPixelAspectRatio, byte videoActiveFormatDescription, + Bundle extra) { mType = type; mId = id; mLanguage = language; @@ -84,6 +86,7 @@ public final class TvTrackInfo implements Parcelable { mAudioSampleRate = audioSampleRate; mAudioDescription = audioDescription; mHardOfHearing = hardOfHearing; + mSpokenSubtitle = spokenSubtitle; mVideoWidth = videoWidth; mVideoHeight = videoHeight; mVideoFrameRate = videoFrameRate; @@ -102,6 +105,7 @@ public final class TvTrackInfo implements Parcelable { mAudioSampleRate = in.readInt(); mAudioDescription = in.readInt() != 0; mHardOfHearing = in.readInt() != 0; + mSpokenSubtitle = in.readInt() != 0; mVideoWidth = in.readInt(); mVideoHeight = in.readInt(); mVideoFrameRate = in.readFloat(); @@ -212,6 +216,22 @@ public final class TvTrackInfo implements Parcelable { } /** + * Returns {@code true} if the track is a spoken subtitle for people with visual impairment, + * {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks. + * + * <p>For example of broadcast, spoken subtitle information may be referred to broadcast + * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track + */ + public boolean isSpokenSubtitle() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + return mSpokenSubtitle; + } + + /** * Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -308,6 +328,7 @@ public final class TvTrackInfo implements Parcelable { dest.writeInt(mAudioSampleRate); dest.writeInt(mAudioDescription ? 1 : 0); dest.writeInt(mHardOfHearing ? 1 : 0); + dest.writeInt(mSpokenSubtitle ? 1 : 0); dest.writeInt(mVideoWidth); dest.writeInt(mVideoHeight); dest.writeFloat(mVideoFrameRate); @@ -331,6 +352,7 @@ public final class TvTrackInfo implements Parcelable { if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType || !TextUtils.equals(mLanguage, obj.mLanguage) || !TextUtils.equals(mDescription, obj.mDescription) + || mEncrypted != obj.mEncrypted || !Objects.equals(mExtra, obj.mExtra)) { return false; } @@ -340,7 +362,8 @@ public final class TvTrackInfo implements Parcelable { return mAudioChannelCount == obj.mAudioChannelCount && mAudioSampleRate == obj.mAudioSampleRate && mAudioDescription == obj.mAudioDescription - && mHardOfHearing == obj.mHardOfHearing; + && mHardOfHearing == obj.mHardOfHearing + && mSpokenSubtitle == obj.mSpokenSubtitle; case TYPE_VIDEO: return mVideoWidth == obj.mVideoWidth @@ -387,6 +410,7 @@ public final class TvTrackInfo implements Parcelable { private int mAudioSampleRate; private boolean mAudioDescription; private boolean mHardOfHearing; + private boolean mSpokenSubtitle; private int mVideoWidth; private int mVideoHeight; private float mVideoFrameRate; @@ -521,6 +545,25 @@ public final class TvTrackInfo implements Parcelable { } /** + * Sets the spoken subtitle attribute of the audio. Valid only for {@link #TYPE_AUDIO} + * tracks. + * + * <p>For example of broadcast, spoken subtitle information may be referred to broadcast + * standard (e.g. Supplementary Audio Language Descriptor of ETSI EN 300 468). + * + * @param spokenSubtitle The spoken subtitle attribute of the audio. + * @throws IllegalStateException if not called on an audio track + */ + @NonNull + public Builder setSpokenSubtitle(boolean spokenSubtitle) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mSpokenSubtitle = spokenSubtitle; + return this; + } + + /** * Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -623,8 +666,8 @@ public final class TvTrackInfo implements Parcelable { public TvTrackInfo build() { return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted, mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing, - mVideoWidth, mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio, - mVideoActiveFormatDescription, mExtra); + mSpokenSubtitle, mVideoWidth, mVideoHeight, mVideoFrameRate, + mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra); } } } diff --git a/media/java/android/media/tv/tuner/FrontendCapabilities.java b/media/java/android/media/tv/tuner/FrontendCapabilities.java deleted file mode 100644 index fcfd7c8c8639..000000000000 --- a/media/java/android/media/tv/tuner/FrontendCapabilities.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright 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 android.media.tv.tuner; - -/** - * Frontend Capabilities. - * @hide - */ -public class FrontendCapabilities { - /** Analog Capabilities. */ - public class Analog extends FrontendCapabilities { - private final int mTypeCap; - private final int mSifStandardCap; - - Analog(int typeCap, int sifStandardCap) { - mTypeCap = typeCap; - mSifStandardCap = sifStandardCap; - } - /** - * Gets type capability. - */ - public int getTypeCapability() { - return mTypeCap; - } - /** Gets SIF standard capability. */ - public int getSifStandardCapability() { - return mSifStandardCap; - } - } - - /** ATSC Capabilities. */ - public class Atsc extends FrontendCapabilities { - private final int mModulationCap; - - Atsc(int modulationCap) { - mModulationCap = modulationCap; - } - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - } - - /** ATSC-3 Capabilities. */ - public class Atsc3 extends FrontendCapabilities { - private final int mBandwidthCap; - private final int mModulationCap; - private final int mTimeInterleaveModeCap; - private final int mCodeRateCap; - private final int mFecCap; - private final int mDemodOutputFormatCap; - - Atsc3(int bandwidthCap, int modulationCap, int timeInterleaveModeCap, int codeRateCap, - int fecCap, int demodOutputFormatCap) { - mBandwidthCap = bandwidthCap; - mModulationCap = modulationCap; - mTimeInterleaveModeCap = timeInterleaveModeCap; - mCodeRateCap = codeRateCap; - mFecCap = fecCap; - mDemodOutputFormatCap = demodOutputFormatCap; - } - - /** Gets bandwidth capability. */ - public int getBandwidthCapability() { - return mBandwidthCap; - } - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets time interleave mod capability. */ - public int getTimeInterleaveModeCapability() { - return mTimeInterleaveModeCap; - } - /** Gets code rate capability. */ - public int getCodeRateCapability() { - return mCodeRateCap; - } - /** Gets FEC capability. */ - public int getFecCapability() { - return mFecCap; - } - /** Gets demodulator output format capability. */ - public int getDemodOutputFormatCapability() { - return mDemodOutputFormatCap; - } - } - - /** DVBS Capabilities. */ - public class Dvbs extends FrontendCapabilities { - private final int mModulationCap; - private final long mInnerFecCap; - private final int mStandard; - - Dvbs(int modulationCap, long innerFecCap, int standard) { - mModulationCap = modulationCap; - mInnerFecCap = innerFecCap; - mStandard = standard; - } - - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets inner FEC capability. */ - public long getInnerFecCapability() { - return mInnerFecCap; - } - /** Gets DVBS standard capability. */ - public int getStandardCapability() { - return mStandard; - } - } - - /** DVBC Capabilities. */ - public class Dvbc extends FrontendCapabilities { - private final int mModulationCap; - private final int mFecCap; - private final int mAnnexCap; - - Dvbc(int modulationCap, int fecCap, int annexCap) { - mModulationCap = modulationCap; - mFecCap = fecCap; - mAnnexCap = annexCap; - } - - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets FEC capability. */ - public int getFecCapability() { - return mFecCap; - } - /** Gets annex capability. */ - public int getAnnexCapability() { - return mAnnexCap; - } - } - - /** DVBT Capabilities. */ - public class Dvbt extends FrontendCapabilities { - private final int mTransmissionModeCap; - private final int mBandwidthCap; - private final int mConstellationCap; - private final int mCoderateCap; - private final int mHierarchyCap; - private final int mGuardIntervalCap; - private final boolean mIsT2Supported; - private final boolean mIsMisoSupported; - - Dvbt(int transmissionModeCap, int bandwidthCap, int constellationCap, int coderateCap, - int hierarchyCap, int guardIntervalCap, boolean isT2Supported, - boolean isMisoSupported) { - mTransmissionModeCap = transmissionModeCap; - mBandwidthCap = bandwidthCap; - mConstellationCap = constellationCap; - mCoderateCap = coderateCap; - mHierarchyCap = hierarchyCap; - mGuardIntervalCap = guardIntervalCap; - mIsT2Supported = isT2Supported; - mIsMisoSupported = isMisoSupported; - } - - /** Gets transmission mode capability. */ - public int getTransmissionModeCapability() { - return mTransmissionModeCap; - } - /** Gets bandwidth capability. */ - public int getBandwidthCapability() { - return mBandwidthCap; - } - /** Gets constellation capability. */ - public int getConstellationCapability() { - return mConstellationCap; - } - /** Gets code rate capability. */ - public int getCodeRateCapability() { - return mCoderateCap; - } - /** Gets hierarchy capability. */ - public int getHierarchyCapability() { - return mHierarchyCap; - } - /** Gets guard interval capability. */ - public int getGuardIntervalCapability() { - return mGuardIntervalCap; - } - /** Returns whether T2 is supported. */ - public boolean getIsT2Supported() { - return mIsT2Supported; - } - /** Returns whether MISO is supported. */ - public boolean getIsMisoSupported() { - return mIsMisoSupported; - } - } - - /** ISDBS Capabilities. */ - public class Isdbs extends FrontendCapabilities { - private final int mModulationCap; - private final int mCoderateCap; - - Isdbs(int modulationCap, int coderateCap) { - mModulationCap = modulationCap; - mCoderateCap = coderateCap; - } - - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets code rate capability. */ - public int getCodeRateCapability() { - return mCoderateCap; - } - } - - /** ISDBS-3 Capabilities. */ - public class Isdbs3 extends FrontendCapabilities { - private final int mModulationCap; - private final int mCoderateCap; - - Isdbs3(int modulationCap, int coderateCap) { - mModulationCap = modulationCap; - mCoderateCap = coderateCap; - } - - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets code rate capability. */ - public int getCodeRateCapability() { - return mCoderateCap; - } - } - - /** ISDBC Capabilities. */ - public class Isdbc extends FrontendCapabilities { - private final int mModeCap; - private final int mBandwidthCap; - private final int mModulationCap; - private final int mCoderateCap; - private final int mGuardIntervalCap; - - Isdbc(int modeCap, int bandwidthCap, int modulationCap, int coderateCap, - int guardIntervalCap) { - mModeCap = modeCap; - mBandwidthCap = bandwidthCap; - mModulationCap = modulationCap; - mCoderateCap = coderateCap; - mGuardIntervalCap = guardIntervalCap; - } - - /** Gets mode capability. */ - public int getModeCapability() { - return mModeCap; - } - /** Gets bandwidth capability. */ - public int getBandwidthCapability() { - return mBandwidthCap; - } - /** Gets modulation capability. */ - public int getModulationCapability() { - return mModulationCap; - } - /** Gets code rate capability. */ - public int getCodeRateCapability() { - return mCoderateCap; - } - /** Gets guard interval capability. */ - public int getGuardIntervalCapability() { - return mGuardIntervalCap; - } - } -} diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java new file mode 100644 index 000000000000..2962e98790e5 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendCapabilities.java @@ -0,0 +1,41 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * Analog Capabilities. + * @hide + */ +public class AnalogFrontendCapabilities extends FrontendCapabilities { + private final int mTypeCap; + private final int mSifStandardCap; + + AnalogFrontendCapabilities(int typeCap, int sifStandardCap) { + mTypeCap = typeCap; + mSifStandardCap = sifStandardCap; + } + /** + * Gets type capability. + */ + public int getTypeCapability() { + return mTypeCap; + } + /** Gets SIF standard capability. */ + public int getSifStandardCapability() { + return mSifStandardCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java new file mode 100644 index 000000000000..677f9387c6d2 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendCapabilities.java @@ -0,0 +1,65 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * ATSC-3 Capabilities. + * @hide + */ +public class Atsc3FrontendCapabilities extends FrontendCapabilities { + private final int mBandwidthCap; + private final int mModulationCap; + private final int mTimeInterleaveModeCap; + private final int mCodeRateCap; + private final int mFecCap; + private final int mDemodOutputFormatCap; + + Atsc3FrontendCapabilities(int bandwidthCap, int modulationCap, int timeInterleaveModeCap, + int codeRateCap, int fecCap, int demodOutputFormatCap) { + mBandwidthCap = bandwidthCap; + mModulationCap = modulationCap; + mTimeInterleaveModeCap = timeInterleaveModeCap; + mCodeRateCap = codeRateCap; + mFecCap = fecCap; + mDemodOutputFormatCap = demodOutputFormatCap; + } + + /** Gets bandwidth capability. */ + public int getBandwidthCapability() { + return mBandwidthCap; + } + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets time interleave mod capability. */ + public int getTimeInterleaveModeCapability() { + return mTimeInterleaveModeCap; + } + /** Gets code rate capability. */ + public int getCodeRateCapability() { + return mCodeRateCap; + } + /** Gets FEC capability. */ + public int getFecCapability() { + return mFecCap; + } + /** Gets demodulator output format capability. */ + public int getDemodOutputFormatCapability() { + return mDemodOutputFormatCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java new file mode 100644 index 000000000000..6ae3c632f5db --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendCapabilities.java @@ -0,0 +1,33 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * ATSC Capabilities. + * @hide + */ +public class AtscFrontendCapabilities extends FrontendCapabilities { + private final int mModulationCap; + + AtscFrontendCapabilities(int modulationCap) { + mModulationCap = modulationCap; + } + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java new file mode 100644 index 000000000000..edea7af06774 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java @@ -0,0 +1,46 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * DVBC Capabilities. + * @hide + */ +public class DvbcFrontendCapabilities extends FrontendCapabilities { + private final int mModulationCap; + private final int mFecCap; + private final int mAnnexCap; + + DvbcFrontendCapabilities(int modulationCap, int fecCap, int annexCap) { + mModulationCap = modulationCap; + mFecCap = fecCap; + mAnnexCap = annexCap; + } + + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets FEC capability. */ + public int getFecCapability() { + return mFecCap; + } + /** Gets annex capability. */ + public int getAnnexCapability() { + return mAnnexCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java new file mode 100644 index 000000000000..f5a41574cd04 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendCapabilities.java @@ -0,0 +1,46 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * DVBS Capabilities. + * @hide + */ +public class DvbsFrontendCapabilities extends FrontendCapabilities { + private final int mModulationCap; + private final long mInnerFecCap; + private final int mStandard; + + DvbsFrontendCapabilities(int modulationCap, long innerFecCap, int standard) { + mModulationCap = modulationCap; + mInnerFecCap = innerFecCap; + mStandard = standard; + } + + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets inner FEC capability. */ + public long getInnerFecCapability() { + return mInnerFecCap; + } + /** Gets DVBS standard capability. */ + public int getStandardCapability() { + return mStandard; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java new file mode 100644 index 000000000000..e9c16ddd4dc8 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendCapabilities.java @@ -0,0 +1,78 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * DVBT Capabilities. + * @hide + */ +public class DvbtFrontendCapabilities extends FrontendCapabilities { + private final int mTransmissionModeCap; + private final int mBandwidthCap; + private final int mConstellationCap; + private final int mCoderateCap; + private final int mHierarchyCap; + private final int mGuardIntervalCap; + private final boolean mIsT2Supported; + private final boolean mIsMisoSupported; + + DvbtFrontendCapabilities(int transmissionModeCap, int bandwidthCap, int constellationCap, + int coderateCap, int hierarchyCap, int guardIntervalCap, boolean isT2Supported, + boolean isMisoSupported) { + mTransmissionModeCap = transmissionModeCap; + mBandwidthCap = bandwidthCap; + mConstellationCap = constellationCap; + mCoderateCap = coderateCap; + mHierarchyCap = hierarchyCap; + mGuardIntervalCap = guardIntervalCap; + mIsT2Supported = isT2Supported; + mIsMisoSupported = isMisoSupported; + } + + /** Gets transmission mode capability. */ + public int getTransmissionModeCapability() { + return mTransmissionModeCap; + } + /** Gets bandwidth capability. */ + public int getBandwidthCapability() { + return mBandwidthCap; + } + /** Gets constellation capability. */ + public int getConstellationCapability() { + return mConstellationCap; + } + /** Gets code rate capability. */ + public int getCodeRateCapability() { + return mCoderateCap; + } + /** Gets hierarchy capability. */ + public int getHierarchyCapability() { + return mHierarchyCap; + } + /** Gets guard interval capability. */ + public int getGuardIntervalCapability() { + return mGuardIntervalCap; + } + /** Returns whether T2 is supported. */ + public boolean getIsT2Supported() { + return mIsT2Supported; + } + /** Returns whether MISO is supported. */ + public boolean getIsMisoSupported() { + return mIsMisoSupported; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java new file mode 100644 index 000000000000..7350bc0c3914 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/FrontendCapabilities.java @@ -0,0 +1,24 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * Frontend Capabilities. + * @hide + */ +public abstract class FrontendCapabilities { +} diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java index ef6c029fe626..5d03570eea80 100644 --- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java +++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java @@ -16,7 +16,6 @@ package android.media.tv.tuner.frontend; -import android.media.tv.tuner.FrontendCapabilities; import android.media.tv.tuner.TunerConstants.FrontendType; /** diff --git a/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java new file mode 100644 index 000000000000..6544b17609c2 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/IsdbcFrontendCapabilities.java @@ -0,0 +1,59 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * ISDBC Capabilities. + * @hide + */ +public class IsdbcFrontendCapabilities extends FrontendCapabilities { + private final int mModeCap; + private final int mBandwidthCap; + private final int mModulationCap; + private final int mCoderateCap; + private final int mGuardIntervalCap; + + IsdbcFrontendCapabilities(int modeCap, int bandwidthCap, int modulationCap, int coderateCap, + int guardIntervalCap) { + mModeCap = modeCap; + mBandwidthCap = bandwidthCap; + mModulationCap = modulationCap; + mCoderateCap = coderateCap; + mGuardIntervalCap = guardIntervalCap; + } + + /** Gets mode capability. */ + public int getModeCapability() { + return mModeCap; + } + /** Gets bandwidth capability. */ + public int getBandwidthCapability() { + return mBandwidthCap; + } + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets code rate capability. */ + public int getCodeRateCapability() { + return mCoderateCap; + } + /** Gets guard interval capability. */ + public int getGuardIntervalCapability() { + return mGuardIntervalCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java new file mode 100644 index 000000000000..92832b7fcbdd --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities.java @@ -0,0 +1,40 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * ISDBS-3 Capabilities. + * @hide + */ +public class Isdbs3FrontendCapabilities extends FrontendCapabilities { + private final int mModulationCap; + private final int mCoderateCap; + + Isdbs3FrontendCapabilities(int modulationCap, int coderateCap) { + mModulationCap = modulationCap; + mCoderateCap = coderateCap; + } + + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets code rate capability. */ + public int getCodeRateCapability() { + return mCoderateCap; + } +} diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java new file mode 100644 index 000000000000..b930b2578092 --- /dev/null +++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendCapabilities.java @@ -0,0 +1,40 @@ +/* + * Copyright 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 android.media.tv.tuner.frontend; + +/** + * ISDBS Capabilities. + * @hide + */ +public class IsdbsFrontendCapabilities extends FrontendCapabilities { + private final int mModulationCap; + private final int mCoderateCap; + + IsdbsFrontendCapabilities(int modulationCap, int coderateCap) { + mModulationCap = modulationCap; + mCoderateCap = coderateCap; + } + + /** Gets modulation capability. */ + public int getModulationCapability() { + return mModulationCap; + } + /** Gets code rate capability. */ + public int getCodeRateCapability() { + return mCoderateCap; + } +} diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java index 557f099c25c1..53d838d84518 100644 --- a/media/java/android/mtp/MtpPropertyList.java +++ b/media/java/android/mtp/MtpPropertyList.java @@ -16,7 +16,8 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; import java.util.List; diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index c7dbca61f90a..ba752633718c 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -16,9 +16,8 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; -import android.provider.MediaStore; /** * This class represents a storage unit on an MTP device. diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 86a1076af122..06adf30a8303 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -21,8 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java index dfbf5d20e074..121443f56285 100644 --- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java +++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java @@ -17,12 +17,11 @@ package android.media.effect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.Filter; import android.filterfw.core.FilterFactory; import android.filterfw.core.FilterFunction; import android.filterfw.core.Frame; -import android.media.effect.EffectContext; /** * Effect subclass for effects based on a single Filter. Subclasses need only invoke the diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java index 52615bf09faa..3a7f1ed4f7ec 100644 --- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java @@ -17,11 +17,11 @@ package android.filterfw; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.filterfw.core.AsyncRunner; -import android.filterfw.core.FilterGraph; import android.filterfw.core.FilterContext; +import android.filterfw.core.FilterGraph; import android.filterfw.core.FrameManager; import android.filterfw.core.GraphRunner; import android.filterfw.core.RoundRobinScheduler; diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java index 4f56b923f6ed..a608ef5be3f4 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Filter.java +++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java @@ -17,19 +17,15 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FilterContext; -import android.filterfw.core.FilterPort; -import android.filterfw.core.KeyValueMap; -import android.filterfw.io.TextGraphReader; -import android.filterfw.io.GraphIOException; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.format.ObjectFormat; +import android.filterfw.io.GraphIOException; +import android.filterfw.io.TextGraphReader; import android.util.Log; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; -import java.lang.Thread; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java index a19220ef85f8..6b0a2193dceb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java @@ -17,11 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Filter; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameManager; -import android.filterfw.core.GLEnvironment; +import android.compat.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java index e6ca11ffca3c..35a298fd6dfb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java @@ -17,6 +17,11 @@ package android.filterfw.core; +import android.compat.annotation.UnsupportedAppUsage; +import android.filterpacks.base.FrameBranch; +import android.filterpacks.base.NullFilter; +import android.util.Log; + import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -25,14 +30,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.Stack; -import android.filterfw.core.FilterContext; -import android.filterfw.core.KeyValueMap; -import android.filterpacks.base.FrameBranch; -import android.filterpacks.base.NullFilter; - -import android.annotation.UnsupportedAppUsage; -import android.util.Log; - /** * @hide */ diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java index e880783247a3..c4d935ae4873 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Frame.java +++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java index eb0ff0a32c3f..a87e9b9ffbcf 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.KeyValueMap; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; import java.util.Map.Entry; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java index 85c8fcd9787d..e49aaf1d6fad 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java @@ -17,10 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java index e25d6a7d70ab..7e4e8a64a81f 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java @@ -17,13 +17,12 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.NativeAllocatorTag; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; +import android.media.MediaRecorder; import android.os.Looper; import android.util.Log; import android.view.Surface; -import android.media.MediaRecorder; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java index 9e3025fafb6e..1ccd7feaa7c3 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java @@ -17,15 +17,10 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; -import android.filterfw.core.NativeFrame; -import android.filterfw.core.StopWatchMap; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; -import android.opengl.GLES20; import android.graphics.Rect; +import android.opengl.GLES20; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java index 250cfaaba9d4..b57e8bb7262e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java +++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java @@ -17,7 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java index ae2ad99899f0..da00b1ffb180 100644 --- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.KeyValueMap; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java index 376c08554eb2..145388e4437e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Program.java +++ b/media/mca/filterfw/java/android/filterfw/core/Program.java @@ -17,8 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java index f41636e7cf76..e043be0e27bd 100644 --- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java +++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java @@ -17,12 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.NativeAllocatorTag; -import android.filterfw.core.Program; -import android.filterfw.core.StopWatchMap; -import android.filterfw.core.VertexFrame; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.geometry.Quad; import android.opengl.GLES20; diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java index ac087305287f..0e05092d0cdd 100644 --- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java +++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java @@ -17,7 +17,7 @@ package android.filterfw.format; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.FrameFormat; import android.filterfw.core.MutableFrameFormat; import android.graphics.Bitmap; diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java index d7acf12dd1de..96d2d7b08b74 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java @@ -17,8 +17,7 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java index 610e5b80399d..2b308a91576f 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java @@ -17,10 +17,8 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.geometry.Point; +import android.compat.annotation.UnsupportedAppUsage; -import java.lang.Float; import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java index 04fccc7e0f94..ec177321bba3 100644 --- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java +++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java @@ -46,8 +46,8 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to"; public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to"; - public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category"; - public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route"; + public static final String ROUTE_ID_SPECIAL_TYPE = "route_special_type"; + public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route"; public static final int VOLUME_MAX = 100; public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume"; @@ -58,10 +58,10 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService public static final String ACTION_REMOVE_ROUTE = "com.android.mediarouteprovider.action_remove_route"; - public static final String CATEGORY_SAMPLE = - "com.android.mediarouteprovider.CATEGORY_SAMPLE"; - public static final String CATEGORY_SPECIAL = - "com.android.mediarouteprovider.CATEGORY_SPECIAL"; + public static final String TYPE_SAMPLE = + "com.android.mediarouteprovider.TYPE_SAMPLE"; + public static final String TYPE_SPECIAL = + "com.android.mediarouteprovider.TYPE_SPECIAL"; Map<String, MediaRoute2Info> mRoutes = new HashMap<>(); Map<String, Integer> mRouteSessionMap = new HashMap<>(); @@ -69,38 +69,38 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService private void initializeRoutes() { MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setDeviceType(DEVICE_TYPE_TV) .build(); MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setDeviceType(DEVICE_TYPE_SPEAKER) .build(); MediaRoute2Info route3 = new MediaRoute2Info.Builder( ROUTE_ID3_SESSION_CREATION_FAILED, ROUTE_NAME3) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .build(); MediaRoute2Info route4 = new MediaRoute2Info.Builder( ROUTE_ID4_TO_SELECT_AND_DESELECT, ROUTE_NAME4) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .build(); MediaRoute2Info route5 = new MediaRoute2Info.Builder( ROUTE_ID5_TO_TRANSFER_TO, ROUTE_NAME5) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .build(); MediaRoute2Info routeSpecial = - new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_CATEGORY, ROUTE_NAME_SPECIAL_CATEGORY) - .addSupportedCategory(CATEGORY_SAMPLE) - .addSupportedCategory(CATEGORY_SPECIAL) + new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_TYPE, ROUTE_NAME_SPECIAL_TYPE) + .addRouteType(TYPE_SAMPLE) + .addRouteType(TYPE_SPECIAL) .build(); MediaRoute2Info fixedVolumeRoute = new MediaRoute2Info.Builder(ROUTE_ID_FIXED_VOLUME, ROUTE_NAME_FIXED_VOLUME) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_FIXED) .build(); MediaRoute2Info variableVolumeRoute = new MediaRoute2Info.Builder(ROUTE_ID_VARIABLE_VOLUME, ROUTE_NAME_VARIABLE_VOLUME) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(VOLUME_MAX) .build(); @@ -167,7 +167,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService } @Override - public void onCreateSession(String packageName, String routeId, String controlCategory, + public void onCreateSession(String packageName, String routeId, String routeType, long requestId) { MediaRoute2Info route = mRoutes.get(routeId); if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) { @@ -186,7 +186,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService mRouteSessionMap.put(routeId, sessionId); RouteSessionInfo sessionInfo = new RouteSessionInfo.Builder( - sessionId, packageName, controlCategory) + sessionId, packageName, routeType) .addSelectedRoute(routeId) .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT) .addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO) diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java index 86b9706bf590..af69c7e8699f 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java @@ -23,18 +23,18 @@ import static android.media.MediaRoute2Info.DEVICE_TYPE_TV; import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED; import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE; -import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_ALL; -import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORIES_SPECIAL; -import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SAMPLE; -import static com.android.mediaroutertest.MediaRouterManagerTest.CATEGORY_SPECIAL; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID1; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID2; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID3_SESSION_CREATION_FAILED; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID4_TO_SELECT_AND_DESELECT; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID5_TO_TRANSFER_TO; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_CATEGORY; +import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_TYPE; import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME; import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID; +import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_ALL; +import static com.android.mediaroutertest.MediaRouterManagerTest.TYPES_SPECIAL; +import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SAMPLE; +import static com.android.mediaroutertest.MediaRouterManagerTest.TYPE_SPECIAL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -50,6 +50,7 @@ import android.media.MediaRouter2; import android.media.MediaRouter2.RouteCallback; import android.media.MediaRouter2.RouteSessionController; import android.media.MediaRouter2.SessionCallback; +import android.media.RouteDiscoveryRequest; import android.media.RouteSessionInfo; import android.net.Uri; import android.os.Parcel; @@ -95,14 +96,14 @@ public class MediaRouter2Test { } /** - * Tests if we get proper routes for application that has special control category. + * Tests if we get proper routes for application that has special route type. */ @Test public void testGetRoutes() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_SPECIAL); assertEquals(1, routes.size()); - assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); + assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE)); } @Test @@ -114,7 +115,7 @@ public class MediaRouter2Test { .setIconUri(new Uri.Builder().path("icon").build()) .setVolume(5) .setVolumeMax(20) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE) .setDeviceType(DEVICE_TYPE_SPEAKER) .build(); @@ -137,7 +138,7 @@ public class MediaRouter2Test { .setClientPackageName("com.android.mediaroutertest") .setConnectionState(CONNECTION_STATE_CONNECTING) .setIconUri(new Uri.Builder().path("icon").build()) - .addSupportedCategory(CATEGORY_SAMPLE) + .addRouteType(TYPE_SAMPLE) .setVolume(5) .setVolumeMax(20) .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE) @@ -168,9 +169,9 @@ public class MediaRouter2Test { .setClientPackageName("another.client.package").build(); assertNotEquals(route, routeClient); - MediaRoute2Info routeCategory = new MediaRoute2Info.Builder(route) - .addSupportedCategory(CATEGORY_SPECIAL).build(); - assertNotEquals(route, routeCategory); + MediaRoute2Info routeType = new MediaRoute2Info.Builder(route) + .addRouteType(TYPE_SPECIAL).build(); + assertNotEquals(route, routeType); MediaRoute2Info routeVolume = new MediaRoute2Info.Builder(route) .setVolume(10).build(); @@ -191,7 +192,7 @@ public class MediaRouter2Test { @Test public void testControlVolumeWithRouter() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(TYPES_ALL); MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); assertNotNull(volRoute); @@ -202,12 +203,14 @@ public class MediaRouter2Test { awaitOnRouteChanged( () -> mRouter2.requestUpdateVolume(volRoute, deltaVolume), ROUTE_ID_VARIABLE_VOLUME, - (route -> route.getVolume() == originalVolume + deltaVolume)); + (route -> route.getVolume() == originalVolume + deltaVolume), + TYPES_ALL); awaitOnRouteChanged( () -> mRouter2.requestSetVolume(volRoute, originalVolume), ROUTE_ID_VARIABLE_VOLUME, - (route -> route.getVolume() == originalVolume)); + (route -> route.getVolume() == originalVolume), + TYPES_ALL); } @Test @@ -234,13 +237,13 @@ public class MediaRouter2Test { @Test public void testRequestCreateSessionWithInvalidArguments() { MediaRoute2Info route = new MediaRoute2Info.Builder("id", "name").build(); - String controlCategory = "controlCategory"; + String routeType = "routeType"; // Tests null route assertThrows(NullPointerException.class, - () -> mRouter2.requestCreateSession(null, controlCategory)); + () -> mRouter2.requestCreateSession(null, routeType)); - // Tests null or empty control category + // Tests null or empty route type assertThrows(IllegalArgumentException.class, () -> mRouter2.requestCreateSession(route, null)); assertThrows(IllegalArgumentException.class, @@ -249,10 +252,10 @@ public class MediaRouter2Test { @Test public void testRequestCreateSessionSuccess() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info route = routes.get(ROUTE_ID1); assertNotNull(route); @@ -266,25 +269,25 @@ public class MediaRouter2Test { public void onSessionCreated(RouteSessionController controller) { assertNotNull(controller); assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType())); controllers.add(controller); successLatch.countDown(); } @Override public void onSessionCreationFailed(MediaRoute2Info requestedRoute, - String requestedControlCategory) { + String requestedRouteType) { failureLatch.countDown(); } }; // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(route, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(route, TYPE_SAMPLE); assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); // onSessionCreationFailed should not be called. @@ -298,10 +301,10 @@ public class MediaRouter2Test { @Test public void testRequestCreateSessionFailure() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info route = routes.get(ROUTE_ID3_SESSION_CREATION_FAILED); assertNotNull(route); @@ -319,20 +322,20 @@ public class MediaRouter2Test { @Override public void onSessionCreationFailed(MediaRoute2Info requestedRoute, - String requestedControlCategory) { + String requestedRouteType) { assertEquals(route, requestedRoute); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, requestedControlCategory)); + assertTrue(TextUtils.equals(TYPE_SAMPLE, requestedRouteType)); failureLatch.countDown(); } }; // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(route, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(route, TYPE_SAMPLE); assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); // onSessionCreated should not be called. @@ -346,8 +349,8 @@ public class MediaRouter2Test { @Test public void testRequestCreateSessionMultipleSessions() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); final CountDownLatch successLatch = new CountDownLatch(2); final CountDownLatch failureLatch = new CountDownLatch(1); @@ -363,12 +366,12 @@ public class MediaRouter2Test { @Override public void onSessionCreationFailed(MediaRoute2Info requestedRoute, - String requestedControlCategory) { + String requestedRouteType) { failureLatch.countDown(); } }; - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info route1 = routes.get(ROUTE_ID1); MediaRoute2Info route2 = routes.get(ROUTE_ID2); assertNotNull(route1); @@ -376,12 +379,12 @@ public class MediaRouter2Test { // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(route1, CATEGORY_SAMPLE); - mRouter2.requestCreateSession(route2, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(route1, TYPE_SAMPLE); + mRouter2.requestCreateSession(route2, TYPE_SAMPLE); assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); // onSessionCreationFailed should not be called. @@ -395,8 +398,8 @@ public class MediaRouter2Test { assertNotEquals(controller1.getSessionId(), controller2.getSessionId()); assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(ROUTE_ID1)); assertTrue(createRouteMap(controller2.getSelectedRoutes()).containsKey(ROUTE_ID2)); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller1.getControlCategory())); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller2.getControlCategory())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller1.getRouteType())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller2.getRouteType())); } finally { releaseControllers(createdControllers); mRouter2.unregisterRouteCallback(routeCallback); @@ -406,10 +409,10 @@ public class MediaRouter2Test { @Test public void testSessionCallbackIsNotCalledAfterUnregistered() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info route = routes.get(ROUTE_ID1); assertNotNull(route); @@ -427,18 +430,18 @@ public class MediaRouter2Test { @Override public void onSessionCreationFailed(MediaRoute2Info requestedRoute, - String requestedControlCategory) { + String requestedRouteType) { failureLatch.countDown(); } }; // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(route, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(route, TYPE_SAMPLE); // Unregisters session callback mRouter2.unregisterSessionCallback(sessionCallback); @@ -456,10 +459,10 @@ public class MediaRouter2Test { // TODO: Add tests for illegal inputs if needed (e.g. selecting already selected route) @Test public void testRouteSessionControllerSelectAndDeselectRoute() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); assertNotNull(routeToCreateSessionWith); @@ -474,7 +477,7 @@ public class MediaRouter2Test { public void onSessionCreated(RouteSessionController controller) { assertNotNull(controller); assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType())); controllers.add(controller); onSessionCreatedLatch.countDown(); } @@ -522,11 +525,11 @@ public class MediaRouter2Test { // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE); assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals(1, controllers.size()); @@ -554,10 +557,10 @@ public class MediaRouter2Test { @Test public void testRouteSessionControllerTransferToRoute() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); assertNotNull(routeToCreateSessionWith); @@ -570,8 +573,12 @@ public class MediaRouter2Test { @Override public void onSessionCreated(RouteSessionController controller) { assertNotNull(controller); + android.util.Log.d(TAG, "selected route ids "); + for (String routeId : getRouteIds(controller.getSelectedRoutes())) { + android.util.Log.d(TAG, "route id : " + routeId); + } assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType())); controllers.add(controller); onSessionCreatedLatch.countDown(); } @@ -603,11 +610,11 @@ public class MediaRouter2Test { // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE); assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals(1, controllers.size()); @@ -632,10 +639,10 @@ public class MediaRouter2Test { @Test public void testRouteSessionControllerReleaseShouldIgnoreTransferTo() throws Exception { - final List<String> sampleControlCategory = new ArrayList<>(); - sampleControlCategory.add(CATEGORY_SAMPLE); + final List<String> sampleRouteType = new ArrayList<>(); + sampleRouteType.add(TYPE_SAMPLE); - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleControlCategory); + Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); assertNotNull(routeToCreateSessionWith); @@ -649,7 +656,7 @@ public class MediaRouter2Test { public void onSessionCreated(RouteSessionController controller) { assertNotNull(controller); assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - assertTrue(TextUtils.equals(CATEGORY_SAMPLE, controller.getControlCategory())); + assertTrue(TextUtils.equals(TYPE_SAMPLE, controller.getRouteType())); controllers.add(controller); onSessionCreatedLatch.countDown(); } @@ -667,11 +674,11 @@ public class MediaRouter2Test { // TODO: Remove this once the MediaRouter2 becomes always connected to the service. RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); try { mRouter2.registerSessionCallback(mExecutor, sessionCallback); - mRouter2.requestCreateSession(routeToCreateSessionWith, CATEGORY_SAMPLE); + mRouter2.requestCreateSession(routeToCreateSessionWith, TYPE_SAMPLE); assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertEquals(1, controllers.size()); @@ -706,11 +713,11 @@ public class MediaRouter2Test { return routeMap; } - Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories) + Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes) throws Exception { CountDownLatch latch = new CountDownLatch(1); - // A dummy callback is required to send control category info. + // A dummy callback is required to send route type info. RouteCallback routeCallback = new RouteCallback() { @Override public void onRoutesAdded(List<MediaRoute2Info> routes) { @@ -723,8 +730,8 @@ public class MediaRouter2Test { } }; - mRouter2.setControlCategories(controlCategories); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, + new RouteDiscoveryRequest.Builder(routeTypes, true).build()); try { latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); return createRouteMap(mRouter2.getRoutes()); @@ -751,7 +758,8 @@ public class MediaRouter2Test { } void awaitOnRouteChanged(Runnable task, String routeId, - Predicate<MediaRoute2Info> predicate) throws Exception { + Predicate<MediaRoute2Info> predicate, + List<String> routeTypes) throws Exception { CountDownLatch latch = new CountDownLatch(1); RouteCallback routeCallback = new RouteCallback() { @Override @@ -762,7 +770,8 @@ public class MediaRouter2Test { } } }; - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, + new RouteDiscoveryRequest.Builder(routeTypes, true).build()); try { task.run(); assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java index 1fd014113299..c23a5b0d76e3 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -31,6 +31,7 @@ import android.media.MediaRouter2; import android.media.MediaRouter2.RouteCallback; import android.media.MediaRouter2.SessionCallback; import android.media.MediaRouter2Manager; +import android.media.RouteDiscoveryRequest; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -75,9 +76,9 @@ public class MediaRouterManagerTest { SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id5_to_transfer_to"; public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to"; - public static final String ROUTE_ID_SPECIAL_CATEGORY = - SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_special_category"; - public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route"; + public static final String ROUTE_ID_SPECIAL_TYPE = + SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_special_type"; + public static final String ROUTE_NAME_SPECIAL_TYPE = "Special Type Route"; public static final String SYSTEM_PROVIDER_ID = "com.android.server.media/.SystemMediaRoute2Provider"; @@ -93,12 +94,12 @@ public class MediaRouterManagerTest { public static final String ACTION_REMOVE_ROUTE = "com.android.mediarouteprovider.action_remove_route"; - public static final String CATEGORY_SAMPLE = - "com.android.mediarouteprovider.CATEGORY_SAMPLE"; - public static final String CATEGORY_SPECIAL = - "com.android.mediarouteprovider.CATEGORY_SPECIAL"; + public static final String TYPE_SAMPLE = + "com.android.mediarouteprovider.TYPE_SAMPLE"; + public static final String TYPE_SPECIAL = + "com.android.mediarouteprovider.TYPE_SPECIAL"; - private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO"; + private static final String TYPE_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO"; private static final int TIMEOUT_MS = 5000; @@ -112,18 +113,18 @@ public class MediaRouterManagerTest { private final List<RouteCallback> mRouteCallbacks = new ArrayList<>(); private final List<SessionCallback> mSessionCallbacks = new ArrayList<>(); - public static final List<String> CATEGORIES_ALL = new ArrayList(); - public static final List<String> CATEGORIES_SPECIAL = new ArrayList(); - private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>(); + public static final List<String> TYPES_ALL = new ArrayList(); + public static final List<String> TYPES_SPECIAL = new ArrayList(); + private static final List<String> TYPES_LIVE_AUDIO = new ArrayList<>(); static { - CATEGORIES_ALL.add(CATEGORY_SAMPLE); - CATEGORIES_ALL.add(CATEGORY_SPECIAL); - CATEGORIES_ALL.add(CATEGORY_LIVE_AUDIO); + TYPES_ALL.add(TYPE_SAMPLE); + TYPES_ALL.add(TYPE_SPECIAL); + TYPES_ALL.add(TYPE_LIVE_AUDIO); - CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL); + TYPES_SPECIAL.add(TYPE_SPECIAL); - CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO); + TYPES_LIVE_AUDIO.add(TYPE_LIVE_AUDIO); } @Before @@ -180,7 +181,7 @@ public class MediaRouterManagerTest { @Test public void testOnRoutesRemoved() throws Exception { CountDownLatch latch = new CountDownLatch(1); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); addRouterCallback(new RouteCallback()); addManagerCallback(new MediaRouter2Manager.Callback() { @@ -202,14 +203,14 @@ public class MediaRouterManagerTest { } /** - * Tests if we get proper routes for application that has special control category. + * Tests if we get proper routes for application that has special route type. */ @Test - public void testControlCategory() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL); + public void testRouteType() throws Exception { + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_SPECIAL); assertEquals(1, routes.size()); - assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); + assertNotNull(routes.get(ROUTE_ID_SPECIAL_TYPE)); } /** @@ -218,7 +219,7 @@ public class MediaRouterManagerTest { */ @Test public void testRouterOnSessionCreated() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); CountDownLatch latch = new CountDownLatch(1); @@ -254,7 +255,7 @@ public class MediaRouterManagerTest { @Ignore("TODO: test session created callback instead of onRouteSelected") public void testManagerOnRouteSelected() throws Exception { CountDownLatch latch = new CountDownLatch(1); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); addRouterCallback(new RouteCallback()); addManagerCallback(new MediaRouter2Manager.Callback() { @@ -284,7 +285,7 @@ public class MediaRouterManagerTest { public void testGetActiveRoutes() throws Exception { CountDownLatch latch = new CountDownLatch(1); - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); addRouterCallback(new RouteCallback()); addManagerCallback(new MediaRouter2Manager.Callback() { @Override @@ -320,7 +321,7 @@ public class MediaRouterManagerTest { @Test @Ignore("TODO: enable when session is released") public void testSingleProviderSelect() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); addRouterCallback(new RouteCallback()); awaitOnRouteChangedManager( @@ -345,7 +346,7 @@ public class MediaRouterManagerTest { @Test public void testControlVolumeWithManager() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); int originalVolume = volRoute.getVolume(); @@ -364,7 +365,7 @@ public class MediaRouterManagerTest { @Test public void testVolumeHandling() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL); + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(TYPES_ALL); MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME); MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); @@ -374,11 +375,11 @@ public class MediaRouterManagerTest { assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax()); } - Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> controlCategories) + Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeTypes) throws Exception { CountDownLatch latch = new CountDownLatch(2); - // A dummy callback is required to send control category info. + // A dummy callback is required to send route type info. RouteCallback routeCallback = new RouteCallback(); MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() { @Override @@ -393,16 +394,16 @@ public class MediaRouterManagerTest { } @Override - public void onControlCategoriesChanged(String packageName, List<String> categories) { + public void onControlCategoriesChanged(String packageName, List<String> routeTypes) { if (TextUtils.equals(mPackageName, packageName) - && controlCategories.equals(categories)) { + && routeTypes.equals(routeTypes)) { latch.countDown(); } } }; mManager.registerCallback(mExecutor, managerCallback); - mRouter2.setControlCategories(controlCategories); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, + new RouteDiscoveryRequest.Builder(routeTypes, true).build()); try { latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); return createRouteMap(mManager.getAvailableRoutes(mPackageName)); @@ -449,7 +450,7 @@ public class MediaRouterManagerTest { private void addRouterCallback(RouteCallback routeCallback) { mRouteCallbacks.add(routeCallback); - mRouter2.registerRouteCallback(mExecutor, routeCallback); + mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryRequest.EMPTY); } private void addSessionCallback(SessionCallback sessionCallback) { diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java new file mode 100644 index 000000000000..60d131a8fb7e --- /dev/null +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryRequestTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2020 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.mediaroutertest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.media.RouteDiscoveryRequest; +import android.os.Parcel; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class RouteDiscoveryRequestTest { + @Before + public void setUp() throws Exception { } + + @After + public void tearDown() throws Exception { } + + @Test + public void testEquality() { + List<String> testTypes = new ArrayList<>(); + testTypes.add("TEST_TYPE_1"); + testTypes.add("TEST_TYPE_2"); + RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true) + .build(); + + RouteDiscoveryRequest requestRebuilt = new RouteDiscoveryRequest.Builder(request) + .build(); + + assertEquals(request, requestRebuilt); + + Parcel parcel = Parcel.obtain(); + parcel.writeParcelable(request, 0); + parcel.setDataPosition(0); + RouteDiscoveryRequest requestFromParcel = parcel.readParcelable(null); + + assertEquals(request, requestFromParcel); + } + + @Test + public void testInequality() { + List<String> testTypes = new ArrayList<>(); + testTypes.add("TEST_TYPE_1"); + testTypes.add("TEST_TYPE_2"); + + List<String> testTypes2 = new ArrayList<>(); + testTypes.add("TEST_TYPE_3"); + + RouteDiscoveryRequest request = new RouteDiscoveryRequest.Builder(testTypes, true) + .build(); + + RouteDiscoveryRequest requestTypes = new RouteDiscoveryRequest.Builder(request) + .setRouteTypes(testTypes2) + .build(); + assertNotEquals(request, requestTypes); + + RouteDiscoveryRequest requestActiveScan = new RouteDiscoveryRequest.Builder(request) + .setActiveScan(false) + .build(); + assertNotEquals(request, requestActiveScan); + } +} diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java index 728e6e18cc31..90b46fd5901a 100644 --- a/opengl/java/android/opengl/EGL14.java +++ b/opengl/java/android/opengl/EGL14.java @@ -18,11 +18,11 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; -import android.view.SurfaceView; import android.view.SurfaceHolder; +import android.view.SurfaceView; /** * EGL 1.4 diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java index d66e7ac84a3b..e853e4447daa 100644 --- a/opengl/java/android/opengl/GLES20.java +++ b/opengl/java/android/opengl/GLES20.java @@ -19,7 +19,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** OpenGL ES 2.0 */ diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 8a3e6a0b0fd5..75131b0f6b9c 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -16,7 +16,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java index 8a2517062d4d..ea571c7311a1 100644 --- a/opengl/java/javax/microedition/khronos/egl/EGL10.java +++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java @@ -16,8 +16,7 @@ package javax.microedition.khronos.egl; -import android.annotation.UnsupportedAppUsage; -import java.lang.String; +import android.compat.annotation.UnsupportedAppUsage; public interface EGL10 extends EGL { int EGL_SUCCESS = 0x3000; diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 1e19786f5d41..ec445d4dcbee 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -160,7 +160,7 @@ public class ExternalStorageProvider extends FileSystemProvider { final int userId = UserHandle.myUserId(); final List<VolumeInfo> volumes = mStorageManager.getVolumes(); for (VolumeInfo volume : volumes) { - if (!volume.isMountedReadable()) continue; + if (!volume.isMountedReadable() || volume.getMountUserId() != userId) continue; final String rootId; final String title; @@ -192,9 +192,8 @@ public class ExternalStorageProvider extends FileSystemProvider { title = mStorageManager.getBestVolumeDescription(privateVol); storageUuid = StorageManager.convert(privateVol.fsUuid); } - } else if ((volume.getType() == VolumeInfo.TYPE_PUBLIC - || volume.getType() == VolumeInfo.TYPE_STUB) - && volume.getMountUserId() == userId) { + } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC + || volume.getType() == VolumeInfo.TYPE_STUB) { rootId = volume.getFsUuid(); title = mStorageManager.getBestVolumeDescription(volume); storageUuid = null; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 5b4ef3a47386..70b56ed0b391 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -194,6 +194,14 @@ public class LocalMediaManager implements BluetoothCallback { } } + void dispatchDeviceAttributesChanged() { + synchronized (mCallbacks) { + for (DeviceCallback callback : mCallbacks) { + callback.onDeviceAttributesChanged(); + } + } + } + /** * Stop scan MediaDevice */ @@ -306,14 +314,12 @@ public class LocalMediaManager implements BluetoothCallback { } mCurrentConnectedDevice = connectDevice; updatePhoneMediaDeviceSummary(); - dispatchDeviceListUpdate(); + dispatchDeviceAttributesChanged(); } @Override public void onDeviceAttributesChanged() { - addPhoneDeviceIfNecessary(); - removePhoneMediaDeviceIfNecessary(); - dispatchDeviceListUpdate(); + dispatchDeviceAttributesChanged(); } } @@ -327,7 +333,7 @@ public class LocalMediaManager implements BluetoothCallback { * * @param devices MediaDevice list */ - void onDeviceListUpdate(List<MediaDevice> devices); + default void onDeviceListUpdate(List<MediaDevice> devices) {}; /** * Callback for notifying the connected device is changed. @@ -338,6 +344,12 @@ public class LocalMediaManager implements BluetoothCallback { * {@link MediaDeviceState#STATE_CONNECTING}, * {@link MediaDeviceState#STATE_DISCONNECTED} */ - void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state); + default void onSelectedDeviceStateChanged(MediaDevice device, + @MediaDeviceState int state) {}; + + /** + * Callback for notifying the device attributes is changed. + */ + default void onDeviceAttributesChanged() {}; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 98bb74ad0718..894aa78a978e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -355,7 +355,7 @@ public class LocalMediaManagerTest { mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2); assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2); - verify(mCallback).onDeviceListUpdate(any()); + verify(mCallback).onDeviceAttributesChanged(); } @Test @@ -373,7 +373,7 @@ public class LocalMediaManagerTest { mLocalMediaManager.registerCallback(mCallback); mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1); - verify(mCallback, never()).onDeviceListUpdate(any()); + verify(mCallback, never()).onDeviceAttributesChanged(); } @Test @@ -382,6 +382,6 @@ public class LocalMediaManagerTest { mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged(); - verify(mCallback).onDeviceListUpdate(any()); + verify(mCallback).onDeviceAttributesChanged(); } } diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index f40d3a160513..96a98dca8a5b 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -8,6 +8,7 @@ android_app { libs: [ "telephony-common", "ims-common", + "unsupportedappusage", ], static_libs: [ "junit", @@ -40,6 +41,7 @@ android_test { libs: [ "android.test.base", "android.test.mock", + "unsupportedappusage", ], resource_dirs: ["res"], aaptflags: [ diff --git a/packages/SettingsProvider/res/values/overlayable.xml b/packages/SettingsProvider/res/values/overlayable.xml deleted file mode 100644 index dc41a77d0e2d..000000000000 --- a/packages/SettingsProvider/res/values/overlayable.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!-- 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. ---> -<resources xmlns:android="http://schemas.android.com/apk/res/android"> - <overlayable name="SettingsToNotRestore"> - <policy type="product|system|vendor"> - <item type="array" name="restore_blocked_device_specific_settings" /> - <item type="array" name="restore_blocked_global_settings" /> - <item type="array" name="restore_blocked_secure_settings" /> - <item type="array" name="restore_blocked_system_settings" /> - </policy> - </overlayable> -</resources> diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 049b9f0e903e..5636cc8a3ca3 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -16,7 +16,7 @@ package android.provider.settings.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.provider.Settings; /** Information relating to the Secure settings which should be backed up */ diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java index 89b19de8dfcb..3f5b0daa06a7 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java @@ -16,7 +16,7 @@ package android.provider.settings.backup; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.provider.Settings; /** Information about the system settings to back up */ diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java index 94ab0f11927d..c5d4fa9f1b40 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java @@ -25,7 +25,7 @@ import static android.provider.settings.validators.SettingsValidators.URI_VALIDA import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.hardware.display.ColorDisplayManager; import android.os.BatteryManager; diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 0be853a81fb2..797b713d8614 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -20,7 +20,7 @@ java_defaults { srcs: [ "src/**/*.java", ":framework-tethering-shared-srcs", - ":net-module-utils-srcs", + ":tethering-module-utils-srcs", ":services-tethering-shared-srcs", ], static_libs: [ diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index a49ab85d2faf..11e57186c666 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -15,8 +15,6 @@ */ package android.net; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; - import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager.OnTetheringEventCallback; @@ -52,6 +50,103 @@ public class TetheringManager { private TetheringConfigurationParcel mTetheringConfiguration; private TetherStatesParcel mTetherStatesParcel; + /** + * Broadcast Action: A tetherable connection has come or gone. + * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER}, + * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY}, + * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and + * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate + * the current state of tethering. Each include a list of + * interface names in that state (may be empty). + */ + public static final String ACTION_TETHER_STATE_CHANGED = + "android.net.conn.TETHER_STATE_CHANGED"; + + /** + * gives a String[] listing all the interfaces configured for + * tethering and currently available for tethering. + */ + public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; + + /** + * gives a String[] listing all the interfaces currently in local-only + * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) + */ + public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + + /** + * gives a String[] listing all the interfaces currently tethered + * (ie, has DHCPv4 support and packets potentially forwarded/NATed) + */ + public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; + + /** + * gives a String[] listing all the interfaces we tried to tether and + * failed. Use {@link #getLastTetherError} to find the error code + * for any interfaces listed here. + */ + public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + + /** + * Invalid tethering type. + * @see #startTethering. + */ + public static final int TETHERING_INVALID = -1; + + /** + * Wifi tethering type. + * @see #startTethering. + */ + public static final int TETHERING_WIFI = 0; + + /** + * USB tethering type. + * @see #startTethering. + */ + public static final int TETHERING_USB = 1; + + /** + * Bluetooth tethering type. + * @see #startTethering. + */ + public static final int TETHERING_BLUETOOTH = 2; + + /** + * Wifi P2p tethering type. + * Wifi P2p tethering is set through events automatically, and don't + * need to start from #startTethering. + */ + public static final int TETHERING_WIFI_P2P = 3; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering to + * enable if any. + */ + public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType"; + + /** + * Extra used for communicating with the TetherService. Includes the type of tethering for + * which to cancel provisioning. + */ + public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType"; + + /** + * Extra used for communicating with the TetherService. True to schedule a recheck of tether + * provisioning. + */ + public static final String EXTRA_SET_ALARM = "extraSetAlarm"; + + /** + * Tells the TetherService to run a provision check now. + */ + public static final String EXTRA_RUN_PROVISION = "extraRunProvision"; + + /** + * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver} + * which will receive provisioning results. Can be left empty. + */ + public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback"; + public static final int TETHER_ERROR_NO_ERROR = 0; public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; @@ -470,7 +565,7 @@ public class TetheringManager { * failed. Re-attempting to tether may cause them to reset to the Tethered * state. Alternatively, causing the interface to be destroyed and recreated * may cause them to reset to the available state. - * {@link ConnectivityManager#getLastTetherError} can be used to get more + * {@link TetheringManager#getLastTetherError} can be used to get more * information on the cause of the errors. * * @return an array of 0 or more String indicating the interface names diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt index d93531bac58e..c6efa41e580a 100644 --- a/packages/Tethering/jarjar-rules.txt +++ b/packages/Tethering/jarjar-rules.txt @@ -11,6 +11,7 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering. rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 +rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index abfb33c7af9e..6ac467e39a9d 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -24,25 +24,24 @@ import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; import static android.net.util.TetheringMessageBase.BASE_IPSERVER; -import android.net.ConnectivityManager; import android.net.INetd; import android.net.INetworkStackStatusCallback; import android.net.INetworkStatsService; -import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.RouteInfo; +import android.net.TetheringManager; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.DhcpServingParamsParcelExt; import android.net.dhcp.IDhcpServer; import android.net.ip.RouterAdvertisementDaemon.RaParams; +import android.net.shared.NetdUtils; +import android.net.shared.RouteUtils; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; -import android.net.util.NetdService; import android.net.util.SharedLog; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -119,7 +118,7 @@ public class IpServer extends StateMachine { * * @param who the calling instance of IpServer * @param state one of STATE_* - * @param lastError one of ConnectivityManager.TETHER_ERROR_* + * @param lastError one of TetheringManager.TETHER_ERROR_* */ public void updateInterfaceState(IpServer who, int state, int lastError) { } @@ -144,10 +143,6 @@ public class IpServer extends StateMachine { return InterfaceParams.getByName(ifName); } - public INetd getNetdService() { - return NetdService.getInstance(); - } - /** Create a DhcpServer instance to be used by IpServer. */ public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb); @@ -180,7 +175,6 @@ public class IpServer extends StateMachine { private final State mUnavailableState; private final SharedLog mLog; - private final INetworkManagementService mNMService; private final INetd mNetd; private final INetworkStatsService mStatsService; private final Callback mCallback; @@ -210,15 +204,15 @@ public class IpServer extends StateMachine { private int mDhcpServerStartIndex = 0; private IDhcpServer mDhcpServer; private RaParams mLastRaParams; + private LinkAddress mIpv4Address; public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetworkManagementService nMService, INetworkStatsService statsService, - Callback callback, boolean usingLegacyDhcp, Dependencies deps) { + INetd netd, INetworkStatsService statsService, Callback callback, + boolean usingLegacyDhcp, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); - mNMService = nMService; - mNetd = deps.getNetdService(); + mNetd = netd; mStatsService = statsService; mCallback = callback; mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); @@ -228,7 +222,7 @@ public class IpServer extends StateMachine { mUsingLegacyDhcp = usingLegacyDhcp; mDeps = deps; resetLinkProperties(); - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; mServingMode = STATE_AVAILABLE; mInitialState = new InitialState(); @@ -249,7 +243,7 @@ public class IpServer extends StateMachine { } /** - * Tethering downstream type. It would be one of ConnectivityManager#TETHERING_*. + * Tethering downstream type. It would be one of TetheringManager#TETHERING_*. */ public int interfaceType() { return mInterfaceType; @@ -347,13 +341,13 @@ public class IpServer extends StateMachine { } }); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw new IllegalStateException(e); } }); } private void handleError() { - mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; transitionTo(mInitialState); } } @@ -388,14 +382,15 @@ public class IpServer extends StateMachine { public void callback(int statusCode) { if (statusCode != STATUS_SUCCESS) { mLog.e("Error stopping DHCP server: " + statusCode); - mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR; // Not much more we can do here } } }); mDhcpServer = null; } catch (RemoteException e) { - e.rethrowFromSystemServer(); + mLog.e("Error stopping DHCP", e); + // Not much more we can do here } } } @@ -414,85 +409,69 @@ public class IpServer extends StateMachine { // NOTE: All of configureIPv4() will be refactored out of existence // into calls to InterfaceController, shared with startIPv4(). mInterfaceCtrl.clearIPv4Address(); + mIpv4Address = null; } - // TODO: Refactor this in terms of calls to InterfaceController. private boolean configureIPv4(boolean enabled) { if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); // TODO: Replace this hard-coded information with dynamically selected // config passed down to us by a higher layer IP-coordinating element. - String ipAsString = null; + final Inet4Address srvAddr; int prefixLen = 0; - if (mInterfaceType == ConnectivityManager.TETHERING_USB) { - ipAsString = USB_NEAR_IFACE_ADDR; - prefixLen = USB_PREFIX_LENGTH; - } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { - ipAsString = getRandomWifiIPv4Address(); - prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; - } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) { - ipAsString = WIFI_P2P_IFACE_ADDR; - prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; - } else { - // BT configures the interface elsewhere: only start DHCP. - final Inet4Address srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); - return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - } - - final LinkAddress linkAddr; try { - final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName); - if (ifcg == null) { - mLog.e("Received null interface config"); - return false; - } - - InetAddress addr = parseNumericAddress(ipAsString); - linkAddr = new LinkAddress(addr, prefixLen); - ifcg.setLinkAddress(linkAddr); - if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { - // The WiFi stack has ownership of the interface up/down state. - // It is unclear whether the Bluetooth or USB stacks will manage their own - // state. - ifcg.ignoreInterfaceUpDownStatus(); + if (mInterfaceType == TetheringManager.TETHERING_USB) { + srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR); + prefixLen = USB_PREFIX_LENGTH; + } else if (mInterfaceType == TetheringManager.TETHERING_WIFI) { + srvAddr = (Inet4Address) parseNumericAddress(getRandomWifiIPv4Address()); + prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; + } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { + srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR); + prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; } else { - if (enabled) { - ifcg.setInterfaceUp(); - } else { - ifcg.setInterfaceDown(); - } + // BT configures the interface elsewhere: only start DHCP. + // TODO: make all tethering types behave the same way, and delete the bluetooth + // code that calls into NetworkManagementService directly. + srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); + mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); + return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); } - ifcg.clearFlag("running"); + mIpv4Address = new LinkAddress(srvAddr, prefixLen); + } catch (IllegalArgumentException e) { + mLog.e("Error selecting ipv4 address", e); + if (!enabled) stopDhcp(); + return false; + } - // TODO: this may throw if the interface is already gone. Do proper handling and - // simplify the DHCP server start/stop. - mNMService.setInterfaceConfig(mIfaceName, ifcg); + final Boolean setIfaceUp; + if (mInterfaceType == TetheringManager.TETHERING_WIFI) { + // The WiFi stack has ownership of the interface up/down state. + // It is unclear whether the Bluetooth or USB stacks will manage their own + // state. + setIfaceUp = null; + } else { + setIfaceUp = enabled; + } + if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) { + mLog.e("Error configuring interface"); + if (!enabled) stopDhcp(); + return false; + } - if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) { - return false; - } - } catch (Exception e) { - mLog.e("Error configuring interface " + e); - if (!enabled) { - try { - // Calling stopDhcp several times is fine - stopDhcp(); - } catch (Exception dhcpError) { - mLog.e("Error stopping DHCP", dhcpError); - } - } + if (!configureDhcp(enabled, srvAddr, prefixLen)) { return false; } // Directly-connected route. - final IpPrefix ipv4Prefix = new IpPrefix(linkAddr.getAddress(), - linkAddr.getPrefixLength()); + final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), + mIpv4Address.getPrefixLength()); final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST); if (enabled) { - mLinkProperties.addLinkAddress(linkAddr); + mLinkProperties.addLinkAddress(mIpv4Address); mLinkProperties.addRoute(route); } else { - mLinkProperties.removeLinkAddress(linkAddr); + mLinkProperties.removeLinkAddress(mIpv4Address); mLinkProperties.removeRoute(route); } return true; @@ -584,14 +563,12 @@ public class IpServer extends StateMachine { if (!deprecatedPrefixes.isEmpty()) { final ArrayList<RouteInfo> toBeRemoved = getLocalRoutesFor(mIfaceName, deprecatedPrefixes); - try { - final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved); - if (removalFailures > 0) { - mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", - removalFailures)); - } - } catch (RemoteException e) { - mLog.e("Failed to remove IPv6 routes from local table: " + e); + // Remove routes from local network. + final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( + mNetd, toBeRemoved); + if (removalFailures > 0) { + mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", + removalFailures)); } for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); @@ -608,13 +585,18 @@ public class IpServer extends StateMachine { final ArrayList<RouteInfo> toBeAdded = getLocalRoutesFor(mIfaceName, addedPrefixes); try { - // It's safe to call addInterfaceToLocalNetwork() even if - // the interface is already in the local_network. Note also - // that adding routes that already exist does not cause an - // error (EEXIST is silently ignored). - mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded); - } catch (Exception e) { - mLog.e("Failed to add IPv6 routes to local table: " + e); + // It's safe to call networkAddInterface() even if + // the interface is already in the local_network. + mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); + try { + // Add routes from local network. Note that adding routes that + // already exist does not cause an error (EEXIST is silently ignored). + RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); + } catch (IllegalStateException e) { + mLog.e("Failed to add IPv6 routes to local table: " + e); + } + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to add " + mIfaceName + " to local table: ", e); } for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); @@ -728,7 +710,7 @@ public class IpServer extends StateMachine { logMessage(this, message.what); switch (message.what) { case CMD_TETHER_REQUESTED: - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; switch (message.arg1) { case STATE_LOCAL_ONLY: transitionTo(mLocalHotspotState); @@ -757,15 +739,17 @@ public class IpServer extends StateMachine { @Override public void enter() { if (!startIPv4()) { - mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; + mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; return; } try { - mNMService.tetherInterface(mIfaceName); - } catch (Exception e) { + final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), + mIpv4Address.getPrefixLength()); + NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix); + } catch (RemoteException | ServiceSpecificException e) { mLog.e("Error Tethering: " + e); - mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; + mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; return; } @@ -784,9 +768,9 @@ public class IpServer extends StateMachine { stopIPv6(); try { - mNMService.untetherInterface(mIfaceName); - } catch (Exception e) { - mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; + NetdUtils.untetherInterface(mNetd, mIfaceName); + } catch (RemoteException | ServiceSpecificException e) { + mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; mLog.e("Failed to untether interface: " + e); } @@ -816,7 +800,7 @@ public class IpServer extends StateMachine { case CMD_START_TETHERING_ERROR: case CMD_STOP_TETHERING_ERROR: case CMD_SET_DNS_FORWARDERS_ERROR: - mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR; + mLastError = TetheringManager.TETHER_ERROR_MASTER_ERROR; transitionTo(mInitialState); break; default: @@ -835,7 +819,7 @@ public class IpServer extends StateMachine { @Override public void enter() { super.enter(); - if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { transitionTo(mInitialState); } @@ -871,7 +855,7 @@ public class IpServer extends StateMachine { @Override public void enter() { super.enter(); - if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) { transitionTo(mInitialState); } @@ -901,17 +885,17 @@ public class IpServer extends StateMachine { // About to tear down NAT; gather remaining statistics. mStatsService.forceUpdate(); } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString()); + mLog.e("Exception in forceUpdate: " + e.toString()); } try { - mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface); - } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString()); + mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString()); } try { - mNMService.disableNat(mIfaceName, upstreamIface); - } catch (Exception e) { - if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString()); + mNetd.tetherRemoveForward(mIfaceName, upstreamIface); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception in disableNat: " + e.toString()); } } @@ -947,12 +931,12 @@ public class IpServer extends StateMachine { for (String ifname : added) { try { - mNMService.enableNat(mIfaceName, ifname); - mNMService.startInterfaceForwarding(mIfaceName, ifname); - } catch (Exception e) { - mLog.e("Exception enabling NAT: " + e); + mNetd.tetherAddForward(mIfaceName, ifname); + mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception enabling NAT: " + e.toString()); cleanupUpstream(); - mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; + mLastError = TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR; transitionTo(mInitialState); return true; } @@ -997,7 +981,7 @@ public class IpServer extends StateMachine { class UnavailableState extends State { @Override public void enter() { - mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; + mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; sendInterfaceState(STATE_UNAVAILABLE); } } diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java index bba61d72d8d6..6f017dcb623f 100644 --- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java @@ -668,7 +668,7 @@ public class RouterAdvertisementDaemon { } private final class UnicastResponder extends Thread { - private final InetSocketAddress mSolicitor = new InetSocketAddress(); + private final InetSocketAddress mSolicitor = new InetSocketAddress(0); // The recycled buffer for receiving Router Solicitations from clients. // If the RS is larger than IPV6_MIN_MTU the packets are truncated. // This is fine since currently only byte 0 is examined anyway. diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index 7e685fbe97f1..4e2a2c1c7af7 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -16,16 +16,16 @@ package com.android.server.connectivity.tethering; -import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE; -import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK; -import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_INVALID; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringManager.EXTRA_RUN_PROVISION; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; import static com.android.internal.R.string.config_wifi_tether_enable; @@ -59,7 +59,7 @@ import java.io.PrintWriter; /** * Re-check tethering provisioning for enabled downstream tether types. - * Reference ConnectivityManager.TETHERING_{@code *} for each tether type. + * Reference TetheringManager.TETHERING_{@code *} for each tether type. * * All methods of this class must be accessed from the thread of tethering * state machine. @@ -86,9 +86,9 @@ public class EntitlementManager { private static final int EVENT_GET_ENTITLEMENT_VALUE = 4; // The ArraySet contains enabled downstream types, ex: - // {@link ConnectivityManager.TETHERING_WIFI} - // {@link ConnectivityManager.TETHERING_USB} - // {@link ConnectivityManager.TETHERING_BLUETOOTH} + // {@link TetheringManager.TETHERING_WIFI} + // {@link TetheringManager.TETHERING_USB} + // {@link TetheringManager.TETHERING_BLUETOOTH} private final ArraySet<Integer> mCurrentTethers; private final Context mContext; private final int mPermissionChangeMessageCode; @@ -96,8 +96,8 @@ public class EntitlementManager { private final SparseIntArray mEntitlementCacheValue; private final EntitlementHandler mHandler; private final StateMachine mTetherMasterSM; - // Key: ConnectivityManager.TETHERING_*(downstream). - // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). + // Key: TetheringManager.TETHERING_*(downstream). + // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). private final SparseIntArray mCellularPermitted; private PendingIntent mProvisioningRecheckAlarm; private boolean mCellularUpstreamPermitted = true; @@ -133,7 +133,7 @@ public class EntitlementManager { /** * Ui entitlement check fails in |downstream|. * - * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}. + * @param downstream tethering type from TetheringManager.TETHERING_{@code *}. */ void onUiEntitlementFailed(int downstream); } @@ -169,7 +169,7 @@ public class EntitlementManager { * This is called when tethering starts. * Launch provisioning app if upstream is cellular. * - * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *} + * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *} * @param showProvisioningUi a boolean indicating whether to show the * provisioning app UI if there is one. */ @@ -210,7 +210,7 @@ public class EntitlementManager { /** * Tell EntitlementManager that a given type of tethering has been disabled * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} */ public void stopProvisioningIfNeeded(int type) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0)); @@ -296,7 +296,7 @@ public class EntitlementManager { /** * Re-check tethering provisioning for all enabled tether types. - * Reference ConnectivityManager.TETHERING_{@code *} for each tether type. + * Reference TetheringManager.TETHERING_{@code *} for each tether type. * * @param config an object that encapsulates the various tethering configuration elements. * Note: this method is only called from TetherMaster on the handler thread. @@ -363,7 +363,7 @@ public class EntitlementManager { /** * Run no UI tethering provisioning check. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param subId default data subscription ID. */ @VisibleForTesting @@ -390,7 +390,7 @@ public class EntitlementManager { /** * Run the UI-enabled tethering provisioning check. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param subId default data subscription ID. * @param receiver to receive entitlement check result. */ @@ -398,7 +398,7 @@ public class EntitlementManager { protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { if (DBG) mLog.i("runUiTetherProvisioning: " + type); - Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING); + Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); @@ -461,7 +461,7 @@ public class EntitlementManager { * Add the mapping between provisioning result and tethering type. * Notify UpstreamNetworkMonitor if Cellular permission changes. * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param resultCode Provisioning result */ protected void addDownstreamMapping(int type, int resultCode) { @@ -476,7 +476,7 @@ public class EntitlementManager { /** * Remove the mapping for input tethering type. - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} */ protected void removeDownstreamMapping(int type) { mLog.i("removeDownstreamMapping: " + type); @@ -625,7 +625,7 @@ public class EntitlementManager { /** * Update the last entitlement value to internal cache * - * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param type tethering type from TetheringManager.TETHERING_{@code *} * @param resultCode last entitlement value * @return the last updated entitlement value */ diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index 38fa91e7387e..ce7c2a669f0a 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -279,7 +279,7 @@ public class OffloadController { entry.iface = kv.getKey(); entry.rxBytes = value.rxBytes; entry.txBytes = value.txBytes; - stats.addValues(entry); + stats.addEntry(entry); } return stats; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 5b267046a851..d6abfb922a9c 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -20,23 +20,23 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; 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.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER; -import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER; -import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_INVALID; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHERING_WIFI_P2P; -import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL; -import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE; -import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; +import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; +import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; +import static android.net.TetheringManager.EXTRA_ERRORED_TETHER; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_MASTER_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; +import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.util.TetheringMessageBase.BASE_MASTER; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -71,10 +71,10 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkInfo; -import android.net.NetworkUtils; import android.net.TetherStatesParcel; import android.net.TetheringConfigurationParcel; import android.net.ip.IpServer; +import android.net.shared.NetdUtils; import android.net.util.BaseNetdUnsolicitedEventListener; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; @@ -87,12 +87,12 @@ import android.net.wifi.p2p.WifiP2pManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.os.UserManager; import android.telephony.PhoneStateListener; @@ -102,6 +102,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -139,6 +142,8 @@ public class Tethering { }; private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(sMessageClasses); + // Keep in sync with NETID_UNSET in system/netd/include/netid_client.h + private static final int NETID_UNSET = 0; private static class TetherState { public final IpServer ipServer; @@ -172,8 +177,6 @@ public class Tethering { private final Context mContext; private final ArrayMap<String, TetherState> mTetherStates; private final BroadcastReceiver mStateReceiver; - // Stopship: replace mNMService before production. - private final INetworkManagementService mNMService; private final INetworkStatsService mStatsService; private final INetworkPolicyManager mPolicyManager; private final Looper mLooper; @@ -210,7 +213,6 @@ public class Tethering { mLog.mark("Tethering.constructed"); mDeps = deps; mContext = mDeps.getContext(); - mNMService = mDeps.getINetworkManagementService(); mStatsService = mDeps.getINetworkStatsService(); mPolicyManager = mDeps.getINetworkPolicyManager(); mNetd = mDeps.getINetd(mContext); @@ -225,10 +227,9 @@ public class Tethering { mHandler = mTetherMasterSM.getHandler(); mOffloadController = new OffloadController(mHandler, - mDeps.getOffloadHardwareInterface(mHandler, mLog), - mContext.getContentResolver(), mNMService, - mLog); - mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, + mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(), + mDeps.getINetworkManagementService(), mLog); + mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); @@ -289,13 +290,6 @@ public class Tethering { filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, handler); - - filter = new IntentFilter(); - filter.addAction(Intent.ACTION_MEDIA_SHARED); - filter.addAction(Intent.ACTION_MEDIA_UNSHARED); - filter.addDataScheme("file"); - mContext.registerReceiver(mStateReceiver, filter, null, handler); - } private class TetheringThreadExecutor implements Executor { @@ -421,7 +415,6 @@ public class Tethering { } } - void interfaceRemoved(String iface) { if (VDBG) Log.d(TAG, "interfaceRemoved " + iface); synchronized (mPublicSync) { @@ -1022,8 +1015,8 @@ public class Tethering { String[] ifaces = null; try { - ifaces = mNMService.listInterfaces(); - } catch (Exception e) { + ifaces = mNetd.interfaceGetList(); + } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Error listing Interfaces", e); return; } @@ -1282,25 +1275,25 @@ public class Tethering { protected boolean turnOnMasterTetherSettings() { final TetheringConfiguration cfg = mConfig; try { - mNMService.setIpForwardingEnabled(true); - } catch (Exception e) { + mNetd.ipfwdEnableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mSetIpForwardingEnabledErrorState); return false; } + // TODO: Randomize DHCPv4 ranges, especially in hotspot mode. // Legacy DHCP server is disabled if passed an empty ranges array final String[] dhcpRanges = cfg.enableLegacyDhcpServer - ? cfg.legacyDhcpRanges - : new String[0]; + ? cfg.legacyDhcpRanges : new String[0]; try { - // TODO: Find a more accurate method name (startDHCPv4()?). - mNMService.startTethering(dhcpRanges); - } catch (Exception e) { + NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges); + } catch (RemoteException | ServiceSpecificException e) { try { - mNMService.stopTethering(); - mNMService.startTethering(dhcpRanges); - } catch (Exception ee) { + // Stop and retry. + mNetd.tetherStop(); + NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges); + } catch (RemoteException | ServiceSpecificException ee) { mLog.e(ee); transitionTo(mStartTetheringErrorState); return false; @@ -1312,15 +1305,15 @@ public class Tethering { protected boolean turnOffMasterTetherSettings() { try { - mNMService.stopTethering(); - } catch (Exception e) { + mNetd.tetherStop(); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mStopTetheringErrorState); return false; } try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { mLog.e(e); transitionTo(mSetIpForwardingDisabledErrorState); return false; @@ -1383,19 +1376,25 @@ public class Tethering { protected void setDnsForwarders(final Network network, final LinkProperties lp) { // TODO: Set v4 and/or v6 DNS per available connectivity. - String[] dnsServers = mConfig.defaultIPv4DNS; final Collection<InetAddress> dnses = lp.getDnsServers(); // TODO: Properly support the absence of DNS servers. + final String[] dnsServers; if (dnses != null && !dnses.isEmpty()) { - // TODO: remove this invocation of NetworkUtils.makeStrings(). - dnsServers = NetworkUtils.makeStrings(dnses); + dnsServers = new String[dnses.size()]; + int i = 0; + for (InetAddress dns : dnses) { + dnsServers[i++] = dns.getHostAddress(); + } + } else { + dnsServers = mConfig.defaultIPv4DNS; } + final int netId = (network != null) ? network.netId : NETID_UNSET; try { - mNMService.setDnsForwarders(network, dnsServers); + mNetd.tetherDnsSet(netId, dnsServers); mLog.log(String.format( "SET DNS forwarders: network=%s dnsServers=%s", network, Arrays.toString(dnsServers))); - } catch (Exception e) { + } catch (RemoteException | ServiceSpecificException e) { // TODO: Investigate how this can fail and what exactly // happens if/when such failures occur. mLog.e("setting DNS forwarders failed, " + e); @@ -1698,8 +1697,8 @@ public class Tethering { Log.e(TAG, "Error in startTethering"); notify(IpServer.CMD_START_TETHERING_ERROR); try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1709,8 +1708,8 @@ public class Tethering { Log.e(TAG, "Error in stopTethering"); notify(IpServer.CMD_STOP_TETHERING_ERROR); try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1720,11 +1719,11 @@ public class Tethering { Log.e(TAG, "Error in setDnsForwarders"); notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR); try { - mNMService.stopTethering(); - } catch (Exception e) { } + mNetd.tetherStop(); + } catch (RemoteException | ServiceSpecificException e) { } try { - mNMService.setIpForwardingEnabled(false); - } catch (Exception e) { } + mNetd.ipfwdDisableForwarding(TAG); + } catch (RemoteException | ServiceSpecificException e) { } } } @@ -1884,7 +1883,7 @@ public class Tethering { } } - void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -2065,7 +2064,7 @@ public class Tethering { mLog.log("adding TetheringInterfaceStateMachine for: " + iface); final TetherState tetherState = new TetherState( - new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService, + new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mStatsService, makeControlCallback(), mConfig.enableLegacyDhcpServer, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index 490614b03149..397ba8ada551 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -37,7 +37,6 @@ import static com.android.internal.R.string.config_mobile_hotspot_provision_app_ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; -import android.net.ConnectivityManager; import android.net.TetheringConfigurationParcel; import android.net.util.SharedLog; import android.provider.Settings; @@ -179,8 +178,8 @@ public class TetheringConfiguration { pw.print("chooseUpstreamAutomatically: "); pw.println(chooseUpstreamAutomatically); - dumpStringArray(pw, "preferredUpstreamIfaceTypes", - preferredUpstreamNames(preferredUpstreamIfaceTypes)); + pw.print("legacyPreredUpstreamIfaceTypes: "); + pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes))); dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges); dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS); @@ -205,7 +204,7 @@ public class TetheringConfiguration { sj.add(String.format("isDunRequired:%s", isDunRequired)); sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically)); sj.add(String.format("preferredUpstreamIfaceTypes:%s", - makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes)))); + toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); @@ -234,21 +233,6 @@ public class TetheringConfiguration { return sj.toString(); } - private static String[] preferredUpstreamNames(Collection<Integer> upstreamTypes) { - String[] upstreamNames = null; - - if (upstreamTypes != null) { - upstreamNames = new String[upstreamTypes.size()]; - int i = 0; - for (Integer netType : upstreamTypes) { - upstreamNames[i] = ConnectivityManager.getNetworkTypeName(netType); - i++; - } - } - - return upstreamNames; - } - /** Check whether dun is required. */ public static boolean checkDunRequired(Context ctx) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); @@ -388,6 +372,15 @@ public class TetheringConfiguration { return false; } + private static int[] toIntArray(Collection<Integer> values) { + final int[] result = new int[values.size()]; + int index = 0; + for (Integer value : values) { + result[index++] = value; + } + return result; + } + /** * Convert this TetheringConfiguration to a TetheringConfigurationParcel. */ @@ -400,12 +393,7 @@ public class TetheringConfiguration { parcel.isDunRequired = isDunRequired; parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically; - int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()]; - int index = 0; - for (Integer type : preferredUpstreamIfaceTypes) { - preferredTypes[index++] = type; - } - parcel.preferredUpstreamIfaceTypes = preferredTypes; + parcel.preferredUpstreamIfaceTypes = toIntArray(preferredUpstreamIfaceTypes); parcel.legacyDhcpRanges = legacyDhcpRanges; parcel.defaultIPv4DNS = defaultIPv4DNS; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java index 6334c20c2acc..d5cdd8a004dc 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java @@ -22,14 +22,17 @@ import android.net.NetworkCapabilities; import android.net.RouteInfo; import android.net.util.InterfaceSet; -import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; /** * @hide */ public final class TetheringInterfaceUtils { + private static final InetAddress IN6ADDR_ANY = getByAddress( + new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + private static final InetAddress INADDR_ANY = getByAddress(new byte[] {0, 0, 0, 0}); + /** * Get upstream interfaces for tethering based on default routes for IPv4/IPv6. * @return null if there is no usable interface, or a set of at least one interface otherwise. @@ -40,7 +43,7 @@ public final class TetheringInterfaceUtils { } final LinkProperties lp = ns.linkProperties; - final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY); + final String if4 = getInterfaceForDestination(lp, INADDR_ANY); final String if6 = getIPv6Interface(ns); return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6); @@ -76,7 +79,7 @@ public final class TetheringInterfaceUtils { && ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); return canTether - ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY) + ? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY) : null; } @@ -86,4 +89,12 @@ public final class TetheringInterfaceUtils { : null; return (ri != null) ? ri.getInterface() : null; } + + private static InetAddress getByAddress(final byte[] addr) { + try { + return InetAddress.getByAddress(null, addr); + } catch (UnknownHostException e) { + throw new AssertionError("illegal address length" + addr.length); + } + } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index 775484eabfa3..e4e4a090603d 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -26,11 +26,11 @@ import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.net.IIntResultListener; import android.net.INetworkStackConnector; import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; @@ -307,9 +307,15 @@ public class TetheringService extends Service { mDeps = new TetheringDependencies() { @Override public NetworkRequest getDefaultNetworkRequest() { - ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - return cm.getDefaultRequest(); + // TODO: b/147280869, add a proper system API to replace this. + final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + return trackDefaultRequest; } @Override diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index 22150f623a35..fe3f51700df9 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -19,7 +19,6 @@ package com.android.server.connectivity.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_NONE; -import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -35,7 +34,6 @@ import android.net.NetworkRequest; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.Handler; -import android.os.Process; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -130,15 +128,15 @@ public class UpstreamNetworkMonitor { */ public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest, EntitlementManager entitle) { - // This is not really a "request", just a way of tracking the system default network. - // It's guaranteed not to actually bring up any networks because it's the same request - // as the ConnectivityService default request, and thus shares fate with it. We can't - // use registerDefaultNetworkCallback because it will not track the system default - // network if there is a VPN that applies to our UID. + + // defaultNetworkRequest is not really a "request", just a way of tracking the system + // default network. It's guaranteed not to actually bring up any networks because it's + // the should be the same request as the ConnectivityService default request, and thus + // shares fate with it. We can't use registerDefaultNetworkCallback because it will not + // track the system default network if there is a VPN that applies to our UID. if (mDefaultNetworkCallback == null) { - final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); - cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); + cm().requestNetwork(defaultNetworkRequest, mDefaultNetworkCallback, mHandler); } if (mEntitlementMgr == null) { mEntitlementMgr = entitle; @@ -239,7 +237,7 @@ public class UpstreamNetworkMonitor { final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType( mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted()); - mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type)); + mLog.log("preferred upstream type: " + typeStatePair.type); switch (typeStatePair.type) { case TYPE_MOBILE_DUN: @@ -514,16 +512,13 @@ public class UpstreamNetworkMonitor { try { nc = ConnectivityManager.networkCapabilitiesForType(type); } catch (IllegalArgumentException iae) { - Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " - + ConnectivityManager.getNetworkTypeName(type)); + Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type); continue; } if (!isCellularUpstreamPermitted && isCellular(nc)) { continue; } - nc.setSingleUid(Process.myUid()); - for (UpstreamNetworkState value : netStates) { if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) { continue; diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt index 64fdebd92726..921fbed373b0 100644 --- a/packages/Tethering/tests/unit/jarjar-rules.txt +++ b/packages/Tethering/tests/unit/jarjar-rules.txt @@ -7,5 +7,6 @@ rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering. rule com.android.internal.util.Preconditions* com.android.networkstack.tethering.util.Preconditions@1 rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1 rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 +rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index fd2f708aea30..65a0ac13a84b 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -16,13 +16,14 @@ package android.net.ip; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHERING_WIFI_P2P; -import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; +import static android.net.INetd.IF_STATE_UP; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_WIFI_P2P; +import static android.net.TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.ip.IpServer.STATE_AVAILABLE; import static android.net.ip.IpServer.STATE_LOCAL_ONLY; @@ -52,7 +53,7 @@ import static org.mockito.Mockito.when; import android.net.INetd; import android.net.INetworkStatsService; -import android.net.InterfaceConfiguration; +import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -64,7 +65,6 @@ import android.net.dhcp.IDhcpServerCallbacks; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; -import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.test.TestLooper; import android.text.TextUtils; @@ -89,6 +89,8 @@ public class IpServerTest { private static final String IFACE_NAME = "testnet1"; private static final String UPSTREAM_IFACE = "upstream0"; private static final String UPSTREAM_IFACE2 = "upstream1"; + private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; + private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( @@ -96,11 +98,9 @@ public class IpServerTest { private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; - @Mock private INetworkManagementService mNMService; @Mock private INetd mNetd; @Mock private INetworkStatsService mStatsService; @Mock private IpServer.Callback mCallback; - @Mock private InterfaceConfiguration mInterfaceConfiguration; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @Mock private RouterAdvertisementDaemon mRaDaemon; @@ -112,6 +112,7 @@ public class IpServerTest { private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); private IpServer mIpServer; + private InterfaceConfigurationParcel mInterfaceConfiguration; private void initStateMachine(int interfaceType) throws Exception { initStateMachine(interfaceType, false /* usingLegacyDhcp */); @@ -131,17 +132,20 @@ public class IpServerTest { }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); - when(mDependencies.getNetdService()).thenReturn(mNetd); - + mInterfaceConfiguration = new InterfaceConfigurationParcel(); + mInterfaceConfiguration.flags = new String[0]; + if (interfaceType == TETHERING_BLUETOOTH) { + mInterfaceConfiguration.ipv4Addr = BLUETOOTH_IFACE_ADDR; + mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH; + } mIpServer = new IpServer( - IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, - mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies); + IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mStatsService, + mCallback, usingLegacyDhcp, mDependencies); mIpServer.start(); // Starting the state machine always puts us in a consistent state and notifies // the rest of the world that we've changed from an unknown to available state. mLooper.dispatchAll(); - reset(mNMService, mStatsService, mCallback); - when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); + reset(mNetd, mStatsService, mCallback); when(mRaDaemon.start()).thenReturn(true); } @@ -158,8 +162,7 @@ public class IpServerTest { if (upstreamIface != null) { dispatchTetherConnectionChanged(upstreamIface); } - reset(mNMService, mStatsService, mCallback); - when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); + reset(mNetd, mStatsService, mCallback); } @Before public void setUp() throws Exception { @@ -169,15 +172,14 @@ public class IpServerTest { @Test public void startsOutAvailable() { - mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), - TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback, - false /* usingLegacyDhcp */, mDependencies); + mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, + mNetd, mStatsService, mCallback, false /* usingLegacyDhcp */, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mCallback, mNMService, mStatsService); + verifyNoMoreInteractions(mCallback, mNetd, mStatsService); } @Test @@ -196,7 +198,7 @@ public class IpServerTest { // None of these commands should trigger us to request action from // the rest of the system. dispatchCommand(command); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } } @@ -208,7 +210,7 @@ public class IpServerTest { verify(mCallback).updateInterfaceState( mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -216,13 +218,17 @@ public class IpServerTest { initStateMachine(TETHERING_BLUETOOTH); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + // One for ipv4 route, one for ipv6 link local route. + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -230,14 +236,16 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, null); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback); - inOrder.verify(mNMService).untetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mNetd, mStatsService, mCallback); + inOrder.verify(mNetd).tetherApplyDnsInterfaces(); + inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME); + inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -245,16 +253,19 @@ public class IpServerTest { initStateMachine(TETHERING_USB); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); - inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> + IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -262,16 +273,19 @@ public class IpServerTest { initStateMachine(TETHERING_WIFI_P2P); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); - InOrder inOrder = inOrder(mCallback, mNMService); - inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); - inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); - inOrder.verify(mNMService).tetherInterface(IFACE_NAME); + InOrder inOrder = inOrder(mCallback, mNetd); + inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> + IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); + inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -281,10 +295,10 @@ public class IpServerTest { // Telling the state machine about its upstream interface triggers // a little more configuration. dispatchTetherConnectionChanged(UPSTREAM_IFACE); - InOrder inOrder = inOrder(mNMService); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + InOrder inOrder = inOrder(mNetd); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -292,49 +306,49 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); + InOrder inOrder = inOrder(mNetd, mStatsService); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test public void handlesChangingUpstreamNatFailure() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); + doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); + InOrder inOrder = inOrder(mNetd, mStatsService); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @Test public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding( + doThrow(RemoteException.class).when(mNetd).ipfwdAddInterfaceForward( IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNMService, mStatsService); + InOrder inOrder = inOrder(mNetd, mStatsService); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @Test @@ -342,17 +356,19 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback); + InOrder inOrder = inOrder(mNetd, mStatsService, mCallback); inOrder.verify(mStatsService).forceUpdate(); - inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); - inOrder.verify(mNMService).untetherInterface(IFACE_NAME); + inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); + inOrder.verify(mNetd).tetherApplyDnsInterfaces(); + inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME); + inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); inOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } @Test @@ -361,13 +377,14 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_USB, null); if (shouldThrow) { - doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); + doThrow(RemoteException.class).when(mNetd).tetherInterfaceRemove(IFACE_NAME); } dispatchCommand(IpServer.CMD_INTERFACE_DOWN); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig( - IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + // Currently IpServer interfaceSetCfg twice to stop IPv4. One just set interface down + // Another one is set IPv4 to 0.0.0.0/0 as clearng ipv4 address. + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -380,12 +397,15 @@ public class IpServerTest { public void usbShouldBeTornDownOnTetherError() throws Exception { initStateMachine(TETHERING_USB); - doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); + doThrow(RemoteException.class).when(mNetd).tetherInterfaceAdd(IFACE_NAME); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig( - IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + usbTeardownOrder.verify(mNetd).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); + usbTeardownOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); + + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -397,11 +417,13 @@ public class IpServerTest { public void shouldTearDownUsbOnUpstreamError() throws Exception { initTetheredStateMachine(TETHERING_USB, null); - doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); + doThrow(RemoteException.class).when(mNetd).tetherAddForward(anyString(), anyString()); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback); - usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); - usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); + InOrder usbTeardownOrder = inOrder(mNetd, mCallback); + usbTeardownOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE); + + usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg( + argThat(cfg -> IFACE_NAME.equals(cfg.ifName))); usbTeardownOrder.verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR); usbTeardownOrder.verify(mCallback).updateLinkProperties( @@ -413,11 +435,11 @@ public class IpServerTest { public void ignoresDuplicateUpstreamNotifications() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); for (int i = 0; i < 5; i++) { dispatchTetherConnectionChanged(UPSTREAM_IFACE); - verifyNoMoreInteractions(mNMService, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mStatsService, mCallback); } } @@ -525,4 +547,12 @@ public class IpServerTest { // never see an empty interface name in any LinkProperties update. assertFalse(TextUtils.isEmpty(lp.getInterfaceName())); } + + private boolean assertContainsFlag(String[] flags, String match) { + for (String flag : flags) { + if (flag.equals(match)) return true; + } + fail("Missing flag: " + match); + return false; + } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 99cf9e90d912..66eba9ae3b7a 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -16,12 +16,12 @@ package com.android.server.connectivity.tethering; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 04b2eb411c9d..7af48a89d87c 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -19,16 +19,15 @@ package com.android.server.connectivity.tethering; 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.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY; -import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER; -import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; -import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; +import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; +import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -50,7 +49,6 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -74,14 +72,13 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; import android.net.InetAddresses; -import android.net.InterfaceConfiguration; +import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.TetherStatesParcel; @@ -147,6 +144,7 @@ public class TetheringTest { private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_WLAN_IFNAME = "test_wlan0"; private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; + private static final String TETHERING_NAME = "Tethering"; private static final int DHCPSERVER_START_TIMEOUT_MS = 1000; @@ -185,6 +183,7 @@ public class TetheringTest { private BroadcastReceiver mBroadcastReceiver; private Tethering mTethering; private PhoneStateListener mPhoneStateListener; + private InterfaceConfigurationParcel mInterfaceConfiguration; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -248,11 +247,6 @@ public class TetheringTest { } @Override - public INetd getNetdService() { - return mNetd; - } - - @Override public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb) { new Thread(() -> { @@ -429,11 +423,11 @@ public class TetheringTest { .thenReturn(new int[0]); when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) .thenReturn(false); - when(mNMService.listInterfaces()) + when(mNetd.interfaceGetList()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME}); - when(mNMService.getInterfaceConfig(anyString())) - .thenReturn(new InterfaceConfiguration()); + mInterfaceConfiguration = new InterfaceConfigurationParcel(); + mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) .thenReturn(true); @@ -495,15 +489,12 @@ public class TetheringTest { p2pInfo.groupFormed = isGroupFormed; p2pInfo.isGroupOwner = isGroupOwner; - NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null); - WifiP2pGroup group = new WifiP2pGroup(); group.setIsGroupOwner(isGroupOwner); group.setInterface(ifname); final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo); - intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo); intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group); mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL, P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST); @@ -523,10 +514,11 @@ public class TetheringTest { } private void verifyInterfaceServingModeStarted(String ifname) throws Exception { - verify(mNMService, times(1)).getInterfaceConfig(ifname); - verify(mNMService, times(1)) - .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).tetherInterface(ifname); + verify(mNetd, times(1)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherInterfaceAdd(ifname); + verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, ifname); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(ifname), + anyString(), anyString()); } private void verifyTetheringBroadcast(String ifname, String whichExtra) { @@ -558,7 +550,7 @@ public class TetheringTest { verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); } - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); } @@ -581,14 +573,14 @@ public class TetheringTest { prepareUsbTethering(upstreamState); // This should produce no activity of any kind. - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Pretend we then receive USB configured broadcast. sendUsbBroadcast(true, true, true); mLooper.dispatchAll(); // Now we should see the start of tethering mechanics (in this case: // tetherMatchingInterfaces() which starts by fetching all interfaces). - verify(mNMService, times(1)).listInterfaces(); + verify(mNetd, times(1)).interfaceGetList(); // UpstreamNetworkMonitor should receive selected upstream verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any()); @@ -618,9 +610,9 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verifyNoMoreInteractions(mNetd); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -638,16 +630,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + // interfaceSetCfg() called once for enabling and twice disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mWifiManager, times(3)).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. @@ -684,8 +676,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull()); @@ -708,8 +700,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -721,8 +713,8 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mRouterAdvertisementDaemon, times(1)).start(); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); @@ -736,12 +728,11 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobile464xlatUpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, - TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -754,9 +745,9 @@ public class TetheringTest { UpstreamNetworkState upstreamState = buildMobileIPv6UpstreamState(); runUsbTethering(upstreamState); - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // Then 464xlat comes up upstreamState = buildMobile464xlatUpstreamState(); @@ -772,12 +763,11 @@ public class TetheringTest { mLooper.dispatchAll(); // Forwarding is added for 464xlat - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, - TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); // Forwarding was not re-added for v6 (still times(1)) - verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).tetherAddForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); + verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // DHCP not restarted on downstream (still times(1)) verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); } @@ -820,7 +810,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -833,7 +823,7 @@ public class TetheringTest { verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); } @@ -847,7 +837,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -858,9 +848,11 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME), + anyString(), anyString()); + verifyNoMoreInteractions(mNetd); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -878,8 +870,8 @@ public class TetheringTest { ///// // We do not currently emulate any upstream being found. // - // This is why there are no calls to verify mNMService.enableNat() or - // mNMService.startInterfaceForwarding(). + // This is why there are no calls to verify mNetd.tetherAddForward() or + // mNetd.ipfwdAddInterfaceForward(). ///// // Emulate pressing the WiFi tethering button. @@ -887,7 +879,7 @@ public class TetheringTest { mLooper.dispatchAll(); verify(mWifiManager, times(1)).stopSoftAp(); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, when tethering mode // is being torn down. @@ -895,16 +887,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, atLeastOnce()) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + // interfaceSetCfg() called once for enabling and twice for disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mWifiManager, times(3)).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); verifyNoMoreInteractions(mWifiManager); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. @@ -915,14 +907,14 @@ public class TetheringTest { @Test public void failureEnablingIpForwarding() throws Exception { when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true); - doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true); + doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME); // Emulate pressing the WiFi tethering button. mTethering.startTethering(TETHERING_WIFI, null, false); mLooper.dispatchAll(); verify(mWifiManager, times(1)).startTetheredHotspot(null); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Emulate externally-visible WifiManager effects, causing the // per-interface state machine to start up, and telling us that @@ -931,15 +923,15 @@ public class TetheringTest { sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mLooper.dispatchAll(); - // We verify get/set called thrice here: twice for setup (on NMService) and once during - // teardown (on Netd) because all events happen over the course of the single + // We verify get/set called three times here: twice for setup and once during + // teardown because all events happen over the course of the single // dispatchAll() above. Note that once the IpServer IPv4 address config // code is refactored the two calls during shutdown will revert to one. - verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class)); - verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName))); - verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME); + verify(mNetd, times(3)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName))); + verify(mNetd, times(1)).tetherInterfaceAdd(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkAddInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); + verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_WLAN_IFNAME), + anyString(), anyString()); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED); verify(mWifiManager).updateInterfaceIpState( @@ -949,18 +941,20 @@ public class TetheringTest { assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER); // This is called, but will throw. - verify(mNMService, times(1)).setIpForwardingEnabled(true); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); // This never gets called because of the exception thrown above. - verify(mNMService, times(0)).startTethering(any(String[].class)); + verify(mNetd, times(0)).tetherStartWithConfiguration(any()); // When the master state machine transitions to an error state it tells // downstream interfaces, which causes us to tell Wi-Fi about the error // so it can take down AP mode. - verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_WLAN_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_WLAN_IFNAME); verify(mWifiManager).updateInterfaceIpState( TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR); verifyNoMoreInteractions(mWifiManager); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); } private void runUserRestrictionsChange( @@ -1232,9 +1226,9 @@ public class TetheringTest { verifyInterfaceServingModeStarted(TEST_P2P_IFNAME); verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER); - verify(mNMService, times(1)).setIpForwardingEnabled(true); - verify(mNMService, times(1)).startTethering(any(String[].class)); - verifyNoMoreInteractions(mNMService); + verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, times(1)).tetherStartWithConfiguration(any()); + verifyNoMoreInteractions(mNetd); verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // This will be called twice, one is on entering IpServer.STATE_AVAILABLE, @@ -1249,16 +1243,16 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME); - // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4. - verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, times(2)) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, times(1)).stopTethering(); - verify(mNMService, times(1)).setIpForwardingEnabled(false); + verify(mNetd, times(1)).tetherApplyDnsInterfaces(); + verify(mNetd, times(1)).tetherInterfaceRemove(TEST_P2P_IFNAME); + verify(mNetd, times(1)).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + // interfaceSetCfg() called once for enabling and twice for disabling IPv4. + verify(mNetd, times(3)).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, times(1)).tetherStop(); + verify(mNetd, times(1)).ipfwdDisableForwarding(TETHERING_NAME); verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream(); verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any()); - verifyNoMoreInteractions(mNMService); + verifyNoMoreInteractions(mNetd); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); @@ -1272,12 +1266,11 @@ public class TetheringTest { sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).setIpForwardingEnabled(true); - verify(mNMService, never()).startTethering(any(String[].class)); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME); + verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, never()).tetherStartWithConfiguration(any()); // Emulate externally-visible WifiP2pManager effects, when wifi p2p group // is being removed. @@ -1285,13 +1278,13 @@ public class TetheringTest { mTethering.interfaceRemoved(TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).stopTethering(); - verify(mNMService, never()).setIpForwardingEnabled(false); - verifyNoMoreInteractions(mNMService); + verify(mNetd, never()).tetherApplyDnsInterfaces(); + verify(mNetd, never()).tetherInterfaceRemove(TEST_P2P_IFNAME); + verify(mNetd, never()).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherStop(); + verify(mNetd, never()).ipfwdDisableForwarding(TETHERING_NAME); + verifyNoMoreInteractions(mNetd); // Asking for the last error after the per-interface state machine // has been reaped yields an unknown interface error. assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); @@ -1321,12 +1314,11 @@ public class TetheringTest { sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME); mLooper.dispatchAll(); - verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME); - verify(mNMService, never()) - .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class)); - verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME); - verify(mNMService, never()).setIpForwardingEnabled(true); - verify(mNMService, never()).startTethering(any(String[].class)); + verify(mNetd, never()).interfaceSetCfg(any(InterfaceConfigurationParcel.class)); + verify(mNetd, never()).tetherInterfaceAdd(TEST_P2P_IFNAME); + verify(mNetd, never()).networkAddInterface(INetd.LOCAL_NET_ID, TEST_P2P_IFNAME); + verify(mNetd, never()).ipfwdEnableForwarding(TETHERING_NAME); + verify(mNetd, never()).tetherStartWithConfiguration(any()); assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME)); } @Test diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java index b7e05d9c984c..7b5514b8a0d1 100644 --- a/rs/java/android/renderscript/BaseObj.java +++ b/rs/java/android/renderscript/BaseObj.java @@ -16,8 +16,10 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import dalvik.system.CloseGuard; + import java.util.concurrent.locks.ReentrantReadWriteLock; /** diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java index b8eb3a1d7a40..0941907d35f8 100644 --- a/rs/java/android/renderscript/Element.java +++ b/rs/java/android/renderscript/Element.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * <p>An Element represents one item within an {@link diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java index 9a6b0bcd4544..7cc2825ae565 100644 --- a/rs/java/android/renderscript/FileA3D.java +++ b/rs/java/android/renderscript/FileA3D.java @@ -16,13 +16,13 @@ package android.renderscript; -import java.io.File; -import java.io.InputStream; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.content.res.Resources; +import java.io.File; +import java.io.InputStream; + /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java index 583350e91795..df9d8019f28d 100644 --- a/rs/java/android/renderscript/Font.java +++ b/rs/java/android/renderscript/Font.java @@ -16,17 +16,16 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.os.Environment; + import java.io.File; import java.io.InputStream; import java.util.HashMap; import java.util.Map; -import android.os.Environment; - -import android.annotation.UnsupportedAppUsage; -import android.content.res.AssetManager; -import android.content.res.Resources; - /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java index 026c9fbd7d5e..a9469c979494 100644 --- a/rs/java/android/renderscript/Matrix4f.java +++ b/rs/java/android/renderscript/Matrix4f.java @@ -16,8 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java index 5321dcb957dc..826225a70d86 100644 --- a/rs/java/android/renderscript/Mesh.java +++ b/rs/java/android/renderscript/Mesh.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.Vector; /** diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java index e28d646f5f1c..ff072183e927 100644 --- a/rs/java/android/renderscript/Program.java +++ b/rs/java/android/renderscript/Program.java @@ -17,14 +17,14 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.Resources; +import android.util.Log; + import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import android.annotation.UnsupportedAppUsage; -import android.content.res.Resources; -import android.util.Log; - /** * @hide diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java index 3dde9b6d6400..880531207b4d 100644 --- a/rs/java/android/renderscript/ProgramFragment.java +++ b/rs/java/android/renderscript/ProgramFragment.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java index d05d41da8b6f..c741ce6e77ed 100644 --- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java +++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java index 33000acb4eb0..a21696c82161 100644 --- a/rs/java/android/renderscript/ProgramRaster.java +++ b/rs/java/android/renderscript/ProgramRaster.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java index 622fe21be47a..7e61347ee218 100644 --- a/rs/java/android/renderscript/ProgramStore.java +++ b/rs/java/android/renderscript/ProgramStore.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java index 83d9ea7be645..9257234de42c 100644 --- a/rs/java/android/renderscript/ProgramVertex.java +++ b/rs/java/android/renderscript/ProgramVertex.java @@ -38,7 +38,7 @@ **/ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java index 579d3bb507e8..03c2eaf91242 100644 --- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java +++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java index 561373cef625..6bdde387b334 100644 --- a/rs/java/android/renderscript/RSSurfaceView.java +++ b/rs/java/android/renderscript/RSSurfaceView.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.view.SurfaceHolder; diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 5b79d514fcc6..39efe731ce8a 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java index 1797bef4be8d..862d032d6987 100644 --- a/rs/java/android/renderscript/RenderScriptCacheDir.java +++ b/rs/java/android/renderscript/RenderScriptCacheDir.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.File; /** diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java index 6fac83e8c4a8..dafaf367364d 100644 --- a/rs/java/android/renderscript/RenderScriptGL.java +++ b/rs/java/android/renderscript/RenderScriptGL.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.SurfaceTexture; import android.view.Surface; diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java index 9ad9aea9d7aa..d1d3a7642382 100644 --- a/rs/java/android/renderscript/Script.java +++ b/rs/java/android/renderscript/Script.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.SparseArray; /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 4515be8f4a9f..c2e32d332f50 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -92,6 +92,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkMonitorManager; import android.net.NetworkPolicyManager; +import android.net.NetworkProvider; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkScore; @@ -219,6 +220,7 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicInteger; /** * @hide @@ -595,6 +597,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // sequence number of NetworkRequests private int mNextNetworkRequestId = 1; + // Sequence number for NetworkProvider IDs. + private final AtomicInteger mNextNetworkProviderId = new AtomicInteger( + NetworkProvider.FIRST_PROVIDER_ID); + // NetworkRequest activity String log entries. private static final int MAX_NETWORK_REQUEST_LOGS = 20; private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS); @@ -4911,31 +4917,69 @@ public class ConnectivityService extends IConnectivityManager.Stub public final String name; public final Messenger messenger; private final AsyncChannel mAsyncChannel; + private final IBinder.DeathRecipient mDeathRecipient; public final int factorySerialNumber; NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel, - int factorySerialNumber) { + int factorySerialNumber, IBinder.DeathRecipient deathRecipient) { this.name = name; this.messenger = messenger; - this.mAsyncChannel = asyncChannel; this.factorySerialNumber = factorySerialNumber; + mAsyncChannel = asyncChannel; + mDeathRecipient = deathRecipient; + + if ((mAsyncChannel == null) == (mDeathRecipient == null)) { + throw new AssertionError("Must pass exactly one of asyncChannel or deathRecipient"); + } + } + + boolean isLegacyNetworkFactory() { + return mAsyncChannel != null; + } + + void sendMessageToNetworkProvider(int what, int arg1, int arg2, Object obj) { + try { + messenger.send(Message.obtain(null /* handler */, what, arg1, arg2, obj)); + } catch (RemoteException e) { + // Remote process died. Ignore; the death recipient will remove this + // NetworkFactoryInfo from mNetworkFactoryInfos. + } } void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) { - mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, - servingSerialNumber, request); + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, + servingSerialNumber, request); + } else { + sendMessageToNetworkProvider(NetworkProvider.CMD_REQUEST_NETWORK, score, + servingSerialNumber, request); + } } void cancelRequest(NetworkRequest request) { - mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request); + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request); + } else { + sendMessageToNetworkProvider(NetworkProvider.CMD_CANCEL_REQUEST, 0, 0, request); + } } void connect(Context context, Handler handler) { - mAsyncChannel.connect(context, handler, messenger); + if (isLegacyNetworkFactory()) { + mAsyncChannel.connect(context, handler, messenger); + } else { + try { + messenger.getBinder().linkToDeath(mDeathRecipient, 0); + } catch (RemoteException e) { + mDeathRecipient.binderDied(); + } + } } void completeConnection() { - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + if (isLegacyNetworkFactory()) { + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + } } } @@ -5306,6 +5350,11 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); } + /** Returns the next Network provider ID. */ + public final int nextNetworkProviderId() { + return mNextNetworkProviderId.getAndIncrement(); + } + @Override public void releaseNetworkRequest(NetworkRequest networkRequest) { ensureNetworkRequestHasType(networkRequest); @@ -5317,23 +5366,51 @@ public class ConnectivityService extends IConnectivityManager.Stub public int registerNetworkFactory(Messenger messenger, String name) { enforceNetworkFactoryPermission(); NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(), - NetworkFactory.SerialNumber.nextSerialNumber()); + nextNetworkProviderId(), null /* deathRecipient */); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); return nfi.factorySerialNumber; } private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { + if (mNetworkFactoryInfos.containsKey(nfi.messenger)) { + // Avoid creating duplicates. even if an app makes a direct AIDL call. + // This will never happen if an app calls ConnectivityManager#registerNetworkProvider, + // as that will throw if a duplicate provider is registered. + Slog.e(TAG, "Attempt to register existing NetworkFactoryInfo " + + mNetworkFactoryInfos.get(nfi.messenger).name); + return; + } + if (DBG) log("Got NetworkFactory Messenger for " + nfi.name); mNetworkFactoryInfos.put(nfi.messenger, nfi); nfi.connect(mContext, mTrackerHandler); + if (!nfi.isLegacyNetworkFactory()) { + // Legacy NetworkFactories get their requests when their AsyncChannel connects. + sendAllRequestsToFactory(nfi); + } } @Override - public void unregisterNetworkFactory(Messenger messenger) { + public int registerNetworkProvider(Messenger messenger, String name) { + enforceNetworkFactoryPermission(); + NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, + null /* asyncChannel */, nextNetworkProviderId(), + () -> unregisterNetworkProvider(messenger)); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); + return nfi.factorySerialNumber; + } + + @Override + public void unregisterNetworkProvider(Messenger messenger) { enforceNetworkFactoryPermission(); mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger)); } + @Override + public void unregisterNetworkFactory(Messenger messenger) { + unregisterNetworkProvider(messenger); + } + private void handleUnregisterNetworkFactory(Messenger messenger) { NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger); if (nfi == null) { @@ -5343,6 +5420,12 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("unregisterNetworkFactory for " + nfi.name); } + @Override + public void declareNetworkRequestUnfulfillable(NetworkRequest request) { + enforceNetworkFactoryPermission(); + mHandler.post(() -> handleReleaseNetworkRequest(request, Binder.getCallingUid(), true)); + } + // NOTE: Accessed on multiple threads, must be synchronized on itself. @GuardedBy("mNetworkForNetId") private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>(); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1f736502ae42..05d83606b2d0 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -58,10 +58,12 @@ import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkUtils; import android.net.RouteInfo; -import android.net.TetherConfigParcel; import android.net.TetherStatsParcel; import android.net.UidRange; import android.net.UidRangeParcel; +import android.net.shared.NetdUtils; +import android.net.shared.RouteUtils; +import android.net.shared.RouteUtils.ModifyOperation; import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; @@ -898,48 +900,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addRoute(int netId, RouteInfo route) { - modifyRoute(MODIFY_OPERATION_ADD, netId, route); + NetworkStack.checkNetworkStackPermission(mContext); + RouteUtils.modifyRoute(mNetdService, ModifyOperation.ADD, netId, route); } @Override public void removeRoute(int netId, RouteInfo route) { - modifyRoute(MODIFY_OPERATION_REMOVE, netId, route); - } - - private void modifyRoute(boolean add, int netId, RouteInfo route) { NetworkStack.checkNetworkStackPermission(mContext); - - final String ifName = route.getInterface(); - final String dst = route.getDestination().toString(); - final String nextHop; - - switch (route.getType()) { - case RouteInfo.RTN_UNICAST: - if (route.hasGateway()) { - nextHop = route.getGateway().getHostAddress(); - } else { - nextHop = INetd.NEXTHOP_NONE; - } - break; - case RouteInfo.RTN_UNREACHABLE: - nextHop = INetd.NEXTHOP_UNREACHABLE; - break; - case RouteInfo.RTN_THROW: - nextHop = INetd.NEXTHOP_THROW; - break; - default: - nextHop = INetd.NEXTHOP_NONE; - break; - } - try { - if (add) { - mNetdService.networkAddRoute(netId, ifName, dst, nextHop); - } else { - mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop); - } - } catch (RemoteException | ServiceSpecificException e) { - throw new IllegalStateException(e); - } + RouteUtils.modifyRoute(mNetdService, ModifyOperation.REMOVE, netId, route); } private ArrayList<String> readRouteList(String filename) { @@ -1023,12 +991,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) { NetworkStack.checkNetworkStackPermission(mContext); - // an odd number of addrs will fail try { - final TetherConfigParcel config = new TetherConfigParcel(); - config.usingLegacyDnsProxy = usingLegacyDnsProxy; - config.dhcpRanges = dhcpRange; - mNetdService.tetherStartWithConfiguration(config); + NetdUtils.tetherStart(mNetdService, usingLegacyDnsProxy, dhcpRange); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } @@ -1060,26 +1024,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub { public void tetherInterface(String iface) { NetworkStack.checkNetworkStackPermission(mContext); try { - mNetdService.tetherInterfaceAdd(iface); + final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress(); + final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength()); + NetdUtils.tetherInterface(mNetdService, iface, dest); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); } - List<RouteInfo> routes = new ArrayList<>(); - // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it - // suitable to use as a route destination. - routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface)); - addInterfaceToLocalNetwork(iface, routes); } @Override public void untetherInterface(String iface) { NetworkStack.checkNetworkStackPermission(mContext); try { - mNetdService.tetherInterfaceRemove(iface); + NetdUtils.untetherInterface(mNetdService, iface); } catch (RemoteException | ServiceSpecificException e) { throw new IllegalStateException(e); - } finally { - removeInterfaceFromLocalNetwork(iface); } } @@ -2122,16 +2081,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) { modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, iface); - - for (RouteInfo route : routes) { - if (!route.isDefaultRoute()) { - modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, route); - } - } - - // IPv6 link local should be activated always. - modifyRoute(MODIFY_OPERATION_ADD, INetd.LOCAL_NET_ID, - new RouteInfo(new IpPrefix("fe80::/64"), null, iface)); + // modifyInterfaceInNetwork already check calling permission. + RouteUtils.addRoutesToLocalNetwork(mNetdService, iface, routes); } @Override @@ -2141,17 +2092,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) { - int failures = 0; - - for (RouteInfo route : routes) { - try { - modifyRoute(MODIFY_OPERATION_REMOVE, INetd.LOCAL_NET_ID, route); - } catch (IllegalStateException e) { - failures++; - } - } - - return failures; + NetworkStack.checkNetworkStackPermission(mContext); + return RouteUtils.removeRoutesFromLocalNetwork(mNetdService, routes); } @Override diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 3d455ee1cf19..db542145a750 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.ACCESS_MTP; import static android.Manifest.permission.INSTALL_PACKAGES; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; @@ -111,6 +112,7 @@ import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import android.provider.DeviceConfig; +import android.provider.Downloads; import android.provider.MediaStore; import android.provider.Settings; import android.sysprop.VoldProperties; @@ -367,6 +369,8 @@ class StorageManagerService extends IStorageManager.Stub private volatile int mMediaStoreAuthorityAppId = -1; + private volatile int mDownloadsAuthorityAppId = -1; + private volatile int mCurrentUserId = UserHandle.USER_SYSTEM; private final Installer mInstaller; @@ -1788,6 +1792,15 @@ class StorageManagerService extends IStorageManager.Stub mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid); } + provider = mPmInternal.resolveContentProvider( + Downloads.Impl.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + UserHandle.getUserId(UserHandle.USER_SYSTEM)); + + if (provider != null) { + mDownloadsAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid); + } + try { mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback); mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback); @@ -3881,6 +3894,19 @@ class StorageManagerService extends IStorageManager.Stub return Zygote.MOUNT_EXTERNAL_PASS_THROUGH; } + if (mIsFuseEnabled && mDownloadsAuthorityAppId == UserHandle.getAppId(uid)) { + // DownloadManager can write in app-private directories on behalf of apps; + // give it write access to Android/ + return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + } + + final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) == + PERMISSION_GRANTED; + if (mIsFuseEnabled && hasMtp) { + // The process hosting the MTP server should be able to write in Android/ + return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE; + } + // Determine if caller is holding runtime permission final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0, uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE); diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 2091c2a0c694..9ffe89c61a44 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -1059,8 +1059,8 @@ final class UiModeManagerService extends SystemService { if (Sandman.shouldStartDockApp(getContext(), homeIntent)) { try { int result = ActivityTaskManager.getService().startActivityWithConfig( - null, null, homeIntent, null, null, null, 0, 0, - mConfiguration, null, UserHandle.USER_CURRENT); + null, getContext().getBasePackageName(), homeIntent, null, null, null, + 0, 0, mConfiguration, null, UserHandle.USER_CURRENT); if (ActivityManager.isStartResultSuccessful(result)) { dockAppStarted = true; } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 454941ccdb03..a60b09fda2e8 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -39,8 +39,10 @@ import android.system.StructRlimit; import android.util.EventLog; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.util.StatsLog; +import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.ZygoteConnectionConstants; import com.android.server.am.ActivityManagerService; import com.android.server.wm.SurfaceAnimationThread; @@ -606,13 +608,18 @@ public class Watchdog extends Thread { pids.add(Process.myPid()); if (mPhonePid > 0) pids.add(mPhonePid); + long anrTime = SystemClock.uptimeMillis(); + ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false); final File stack = ActivityManagerService.dumpStackTraces( - pids, null, null, getInterestingNativePids()); + pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids()); // Give some extra time to make sure the stack traces get written. // The system's been hanging for a minute, another second or two won't hurt much. SystemClock.sleep(5000); + processCpuTracker.update(); + String cpuInfo = processCpuTracker.printCurrentState(anrTime); + // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log doSysRq('w'); doSysRq('l'); @@ -627,7 +634,7 @@ public class Watchdog extends Thread { if (mActivity != null) { mActivity.addErrorToDropBox( "watchdog", null, "system_server", null, null, null, - subject, null, stack, null); + subject, cpuInfo, stack, null); } StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject); } diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 4b48ef917744..143474bd5c94 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -413,6 +413,11 @@ public class AdbDebuggingManager { case MESSAGE_ADB_CLEAR: { Slog.d(TAG, "Received a request to clear the adb authorizations"); mConnectedKeys.clear(); + // If the key store has not yet been instantiated then do so now; this avoids + // the unnecessary creation of the key store when adb is not enabled. + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } mAdbKeyStore.deleteKeyStore(); cancelJobToUpdateAdbKeyStore(); break; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index a1e1f29016c2..b9f2e76c6ecb 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -103,6 +103,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.MemInfoReader; import com.android.server.LocalServices; import com.android.server.ServiceThread; +import com.android.server.SystemConfig; import com.android.server.Watchdog; import com.android.server.compat.PlatformCompat; import com.android.server.pm.dex.DexManager; @@ -357,6 +358,8 @@ public final class ProcessList { private boolean mAppDataIsolationEnabled = false; + private ArrayList<String> mAppDataIsolationWhitelistedApps; + /** * Temporary to avoid allocations. Protected by main lock. */ @@ -645,6 +648,9 @@ public final class ProcessList { // want some apps enabled while some apps disabled mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); + mAppDataIsolationWhitelistedApps = new ArrayList<>( + SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); + if (sKillHandler == null) { sKillThread = new ServiceThread(TAG + ":kill", @@ -1555,20 +1561,27 @@ public final class ProcessList { } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } - + int numGids = 3; + if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER + || mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) { + numGids++; + } /* * Add shared application and profile GIDs so applications can share some * resources like shared libraries and access user-wide resources */ if (ArrayUtils.isEmpty(permGids)) { - gids = new int[3]; + gids = new int[numGids]; } else { - gids = new int[permGids.length + 3]; - System.arraycopy(permGids, 0, gids, 3, permGids.length); + gids = new int[permGids.length + numGids]; + System.arraycopy(permGids, 0, gids, numGids, permGids.length); } gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid)); gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid)); gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid)); + if (numGids > 3) { + gids[3] = Process.SDCARD_RW_GID; + } // Replace any invalid GIDs if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2]; @@ -1905,6 +1918,16 @@ public final class ProcessList { result.put(packageName, Pair.create(volumeUuid, inode)); } } + if (mAppDataIsolationWhitelistedApps != null) { + for (String packageName : mAppDataIsolationWhitelistedApps) { + String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid(); + long inode = pmInt.getCeDataInode(packageName, userId); + if (inode != 0) { + result.put(packageName, Pair.create(volumeUuid, inode)); + } + } + } + return result; } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index ad728c18dd59..8498dcb32eb1 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -237,15 +237,15 @@ public class DisplayModeDirector { lowestConsideredPriority++; } - int defaultModeId = defaultMode.getModeId(); + int baseModeId = defaultMode.getModeId(); if (availableModes.length > 0) { - defaultModeId = availableModes[0]; + baseModeId = availableModes[0]; } // filterModes function is going to filter the modes based on the voting system. If // the application requests a given mode with preferredModeId function, it will be - // stored as defaultModeId. + // stored as baseModeId. return new DesiredDisplayModeSpecs( - defaultModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate)); + baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate)); } } @@ -526,7 +526,7 @@ public class DisplayModeDirector { } /** - * Information about the desired display mode to be set by the system. Includes the default + * Information about the desired display mode to be set by the system. Includes the base * mode ID and refresh rate range. * * We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the @@ -535,10 +535,10 @@ public class DisplayModeDirector { */ public static final class DesiredDisplayModeSpecs { /** - * Default mode ID. This is what system defaults to for all other settings, or + * Base mode ID. This is what system defaults to for all other settings, or * if the refresh rate range is not available. */ - public int defaultModeId; + public int baseModeId; /** * The refresh rate range. */ @@ -548,9 +548,8 @@ public class DisplayModeDirector { refreshRateRange = new RefreshRateRange(); } - public DesiredDisplayModeSpecs( - int defaultModeId, @NonNull RefreshRateRange refreshRateRange) { - this.defaultModeId = defaultModeId; + public DesiredDisplayModeSpecs(int baseModeId, @NonNull RefreshRateRange refreshRateRange) { + this.baseModeId = baseModeId; this.refreshRateRange = refreshRateRange; } @@ -559,7 +558,7 @@ public class DisplayModeDirector { */ @Override public String toString() { - return String.format("defaultModeId=%d min=%.0f max=%.0f", defaultModeId, + return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId, refreshRateRange.min, refreshRateRange.max); } /** @@ -577,7 +576,7 @@ public class DisplayModeDirector { DesiredDisplayModeSpecs desiredDisplayModeSpecs = (DesiredDisplayModeSpecs) other; - if (defaultModeId != desiredDisplayModeSpecs.defaultModeId) { + if (baseModeId != desiredDisplayModeSpecs.baseModeId) { return false; } if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) { @@ -588,14 +587,14 @@ public class DisplayModeDirector { @Override public int hashCode() { - return Objects.hash(defaultModeId, refreshRateRange); + return Objects.hash(baseModeId, refreshRateRange); } /** * Copy values from the other object. */ public void copyFrom(DesiredDisplayModeSpecs other) { - defaultModeId = other.defaultModeId; + baseModeId = other.baseModeId; refreshRateRange.min = other.refreshRateRange.min; refreshRateRange.max = other.refreshRateRange.max; } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index cf94d4695497..fb8a4193286b 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -272,14 +272,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { // Check whether surface flinger spontaneously changed display config specs out from // under us. If so, schedule a traversal to reapply our display config specs. - if (mDisplayModeSpecs.defaultModeId != 0) { - int activeDefaultMode = + if (mDisplayModeSpecs.baseModeId != 0) { + int activeBaseMode = findMatchingModeIdLocked(physicalDisplayConfigSpecs.defaultConfig); // If we can't map the defaultConfig index to a mode, then the physical display // configs must have changed, and the code below for handling changes to the // list of available modes will take care of updating display config specs. - if (activeDefaultMode != 0) { - if (mDisplayModeSpecs.defaultModeId != activeDefaultMode + if (activeBaseMode != 0) { + if (mDisplayModeSpecs.baseModeId != activeBaseMode || mDisplayModeSpecs.refreshRateRange.min != physicalDisplayConfigSpecs.minRefreshRate || mDisplayModeSpecs.refreshRateRange.max @@ -312,14 +312,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { mDefaultModeId = activeRecord.mMode.getModeId(); } - // Determine whether the display mode specs' default mode is still there. - if (mSupportedModes.indexOfKey(mDisplayModeSpecs.defaultModeId) < 0) { - if (mDisplayModeSpecs.defaultModeId != 0) { + // Determine whether the display mode specs' base mode is still there. + if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) { + if (mDisplayModeSpecs.baseModeId != 0) { Slog.w(TAG, - "DisplayModeSpecs default mode no longer available, using currently" - + " active mode as default."); + "DisplayModeSpecs base mode no longer available, using currently" + + " active mode."); } - mDisplayModeSpecs.defaultModeId = activeRecord.mMode.getModeId(); + mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId(); mDisplayModeSpecsInvalid = true; } @@ -648,13 +648,13 @@ final class LocalDisplayAdapter extends DisplayAdapter { @Override public void setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) { - if (displayModeSpecs.defaultModeId == 0) { + if (displayModeSpecs.baseModeId == 0) { // Bail if the caller is requesting a null mode. We'll get called again shortly with // a valid mode. return; } - int defaultPhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.defaultModeId); - if (defaultPhysIndex < 0) { + int basePhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.baseModeId); + if (basePhysIndex < 0) { // When a display is hotplugged, it's possible for a mode to be removed that was // previously valid. Because of the way display changes are propagated through the // framework, and the caching of the display mode specs in LogicalDisplay, it's @@ -662,8 +662,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { // mode. This should only happen in extremely rare cases. A followup call will // contain a valid mode id. Slog.w(TAG, - "Ignoring request for invalid default mode id " - + displayModeSpecs.defaultModeId); + "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId); updateDeviceInfoLocked(); return; } @@ -673,7 +672,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { getHandler().sendMessage(PooledLambda.obtainMessage( LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this, getDisplayTokenLocked(), - new SurfaceControl.DesiredDisplayConfigSpecs(defaultPhysIndex, + new SurfaceControl.DesiredDisplayConfigSpecs(basePhysIndex, mDisplayModeSpecs.refreshRateRange.min, mDisplayModeSpecs.refreshRateRange.max))); } diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index b6255d15795e..c8e5f6c8f53b 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -317,7 +317,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { @Override public void setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) { - final int id = displayModeSpecs.defaultModeId; + final int id = displayModeSpecs.baseModeId; int index = -1; if (id == 0) { // Use the default. diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index ae6d63adc7e7..90358ca1f133 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -83,11 +83,11 @@ import android.view.ViewConfiguration; import android.widget.Toast; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; -import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.DisplayThread; import com.android.server.LocalServices; @@ -186,6 +186,9 @@ public class InputManagerService extends IInputManager.Stub // The associations of input devices to displays by port. Maps from input device port (String) // to display id (int). Currently only accessed by InputReader. private final Map<String, Integer> mStaticAssociations; + private final Object mAssociationsLock = new Object(); + @GuardedBy("mAssociationLock") + private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>(); private static native long nativeInit(InputManagerService service, Context context, MessageQueue messageQueue); @@ -240,6 +243,7 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon); private static native void nativeSetPointerCapture(long ptr, boolean detached); private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId); + private static native void nativeNotifyPortAssociationsChanged(long ptr); // Input event injection constants defined in InputDispatcher.h. private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; @@ -1723,6 +1727,49 @@ public class InputManagerService extends IInputManager.Stub nativeSetCustomPointerIcon(mPtr, icon); } + /** + * Add a runtime association between the input port and the display port. This overrides any + * static associations. + * @param inputPort The port of the input device. + * @param displayPort The physical port of the associated display. + */ + @Override // Binder call + public void addPortAssociation(@NonNull String inputPort, int displayPort) { + if (!checkCallingPermission( + android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT, + "addPortAssociation()")) { + throw new SecurityException( + "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission"); + } + + Objects.requireNonNull(inputPort); + synchronized (mAssociationsLock) { + mRuntimeAssociations.put(inputPort, displayPort); + } + nativeNotifyPortAssociationsChanged(mPtr); + } + + /** + * Remove the runtime association between the input port and the display port. Any existing + * static association for the cleared input port will be restored. + * @param inputPort The port of the input device to be cleared. + */ + @Override // Binder call + public void removePortAssociation(@NonNull String inputPort) { + if (!checkCallingPermission( + android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT, + "clearPortAssociations()")) { + throw new SecurityException( + "Requires ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT permission"); + } + + Objects.requireNonNull(inputPort); + synchronized (mAssociationsLock) { + mRuntimeAssociations.remove(inputPort); + } + nativeNotifyPortAssociationsChanged(mPtr); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -1743,6 +1790,16 @@ public class InputManagerService extends IInputManager.Stub pw.println(" display: " + v); }); } + + synchronized (mAssociationsLock) { + if (!mRuntimeAssociations.isEmpty()) { + pw.println("Runtime Associations:"); + mRuntimeAssociations.forEach((k, v) -> { + pw.print(" port: " + k); + pw.println(" display: " + v); + }); + } + } } private boolean checkCallingPermission(String permission, String func) { @@ -1766,6 +1823,7 @@ public class InputManagerService extends IInputManager.Stub @Override public void monitor() { synchronized (mInputFilterLock) { } + synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */} nativeMonitor(mPtr); } @@ -1930,7 +1988,7 @@ public class InputManagerService extends IInputManager.Stub * @return Flattened list */ private static List<String> flatten(@NonNull Map<String, Integer> map) { - List<String> list = new ArrayList<>(map.size() * 2); + final List<String> list = new ArrayList<>(map.size() * 2); map.forEach((k, v)-> { list.add(k); list.add(v.toString()); @@ -1943,11 +2001,11 @@ public class InputManagerService extends IInputManager.Stub * directory. */ private static Map<String, Integer> loadStaticInputPortAssociations() { - File baseDir = Environment.getVendorDirectory(); - File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH); + final File baseDir = Environment.getVendorDirectory(); + final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH); try { - InputStream stream = new FileInputStream(confFile); + final InputStream stream = new FileInputStream(confFile); return ConfigurationProcessor.processInputPortAssociations(stream); } catch (FileNotFoundException e) { // Most of the time, file will not exist, which is expected. @@ -1960,7 +2018,14 @@ public class InputManagerService extends IInputManager.Stub // Native callback private String[] getInputPortAssociations() { - List<String> associationList = flatten(mStaticAssociations); + final Map<String, Integer> associations = new HashMap<>(mStaticAssociations); + + // merge the runtime associations. + synchronized (mAssociationsLock) { + associations.putAll(mRuntimeAssociations); + } + + final List<String> associationList = flatten(associations); return associationList.toArray(new String[0]); } diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 55c4e21dd830..9ca302edd204 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -46,7 +46,7 @@ abstract class MediaRoute2Provider { } public abstract void requestCreateSession(String packageName, String routeId, - String controlCategory, long requestId); + String routeType, long requestId); public abstract void releaseSession(int sessionId); public abstract void selectRoute(int sessionId, String routeId); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java index 28bb034b33f7..5cc2b16e073a 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -76,10 +76,10 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv } @Override - public void requestCreateSession(String packageName, String routeId, String controlCategory, + public void requestCreateSession(String packageName, String routeId, String routeType, long requestId) { if (mConnectionReady) { - mActiveConnection.requestCreateSession(packageName, routeId, controlCategory, + mActiveConnection.requestCreateSession(packageName, routeId, routeType, requestId); updateBinding(); } @@ -345,11 +345,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv mClient.dispose(); } - public void requestCreateSession(String packageName, String routeId, String controlCategory, + public void requestCreateSession(String packageName, String routeId, String routeType, long requestId) { try { mProvider.requestCreateSession(packageName, routeId, - controlCategory, requestId); + routeType, requestId); } catch (RemoteException ex) { Slog.e(TAG, "Failed to deliver request to create a session.", ex); } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index a5ffbb8f60e4..b48243279d9e 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -28,6 +28,7 @@ import android.media.IMediaRouter2Client; import android.media.IMediaRouter2Manager; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; +import android.media.RouteDiscoveryRequest; import android.media.RouteSessionInfo; import android.os.Binder; import android.os.Bundle; @@ -174,18 +175,18 @@ class MediaRouter2ServiceImpl { } public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route, - String controlCategory, int requestId) { + String routeType, int requestId) { Objects.requireNonNull(client, "client must not be null"); Objects.requireNonNull(route, "route must not be null"); - if (TextUtils.isEmpty(controlCategory)) { - throw new IllegalArgumentException("controlCategory must not be empty"); + if (TextUtils.isEmpty(routeType)) { + throw new IllegalArgumentException("routeType must not be empty"); } final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - requestCreateSessionLocked(client, route, controlCategory, requestId); + requestCreateSessionLocked(client, route, routeType, requestId); } } finally { Binder.restoreCallingIdentity(token); @@ -267,16 +268,16 @@ class MediaRouter2ServiceImpl { } } - public void setControlCategories(@NonNull IMediaRouter2Client client, - @NonNull List<String> categories) { + public void setDiscoveryRequest2(@NonNull IMediaRouter2Client client, + @NonNull RouteDiscoveryRequest request) { Objects.requireNonNull(client, "client must not be null"); - Objects.requireNonNull(categories, "categories must not be null"); + Objects.requireNonNull(request, "request must not be null"); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { Client2Record clientRecord = mAllClientRecords.get(client.asBinder()); - setControlCategoriesLocked(clientRecord, categories); + setDiscoveryRequestLocked(clientRecord, request); } } finally { Binder.restoreCallingIdentity(token); @@ -434,7 +435,7 @@ class MediaRouter2ServiceImpl { } private void requestCreateSessionLocked(@NonNull IMediaRouter2Client client, - @NonNull MediaRoute2Info route, @NonNull String controlCategory, long requestId) { + @NonNull MediaRoute2Info route, @NonNull String routeType, long requestId) { final IBinder binder = client.asBinder(); final Client2Record clientRecord = mAllClientRecords.get(binder); @@ -447,7 +448,7 @@ class MediaRouter2ServiceImpl { clientRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, clientRecord.mUserRecord.mHandler, - clientRecord, route, controlCategory, requestId)); + clientRecord, route, routeType, requestId)); } } @@ -502,13 +503,14 @@ class MediaRouter2ServiceImpl { } } - private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) { + private void setDiscoveryRequestLocked(Client2Record clientRecord, + RouteDiscoveryRequest discoveryRequest) { if (clientRecord != null) { - if (clientRecord.mControlCategories.equals(categories)) { + if (clientRecord.mDiscoveryRequest.equals(discoveryRequest)) { return; } - clientRecord.mControlCategories = categories; + clientRecord.mDiscoveryRequest = discoveryRequest; clientRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::updateClientUsage, clientRecord.mUserRecord.mHandler, clientRecord)); @@ -607,7 +609,7 @@ class MediaRouter2ServiceImpl { if (clientRecord != null && managerRecord.mTrusted) { //TODO: select category properly requestCreateSessionLocked(clientRecord.mClient, route, - route.getSupportedCategories().get(0), uniqueRequestId); + route.getRouteTypes().get(0), uniqueRequestId); } } } @@ -725,7 +727,7 @@ class MediaRouter2ServiceImpl { public final boolean mTrusted; public final int mClientId; - public List<String> mControlCategories; + public RouteDiscoveryRequest mDiscoveryRequest; public boolean mIsManagerSelecting; public MediaRoute2Info mSelectingRoute; public MediaRoute2Info mSelectedRoute; @@ -735,7 +737,7 @@ class MediaRouter2ServiceImpl { mUserRecord = userRecord; mPackageName = packageName; mSelectRouteSequenceNumbers = new ArrayList<>(); - mControlCategories = Collections.emptyList(); + mDiscoveryRequest = RouteDiscoveryRequest.EMPTY; mClient = client; mUid = uid; mPid = pid; @@ -961,7 +963,7 @@ class MediaRouter2ServiceImpl { } private void requestCreateSessionOnHandler(Client2Record clientRecord, - MediaRoute2Info route, String controlCategory, long requestId) { + MediaRoute2Info route, String routeType, long requestId) { final MediaRoute2Provider provider = findProvider(route.getProviderId()); if (provider == null) { @@ -971,20 +973,20 @@ class MediaRouter2ServiceImpl { return; } - if (!route.getSupportedCategories().contains(controlCategory)) { + if (!route.getRouteTypes().contains(routeType)) { Slog.w(TAG, "Ignoring session creation request since the given route=" + route - + " doesn't support the given category=" + controlCategory); + + " doesn't support the given type=" + routeType); notifySessionCreationFailed(clientRecord, toClientRequestId(requestId)); return; } // TODO: Apply timeout for each request (How many seconds should we wait?) SessionCreationRequest request = new SessionCreationRequest( - clientRecord, route, controlCategory, requestId); + clientRecord, route, routeType, requestId); mSessionCreationRequests.add(request); provider.requestCreateSession(clientRecord.mPackageName, route.getOriginalId(), - controlCategory, requestId); + routeType, requestId); } private void selectRouteOnHandler(@NonNull Client2Record clientRecord, @@ -1144,12 +1146,12 @@ class MediaRouter2ServiceImpl { } String originalRouteId = matchingRequest.mRoute.getId(); - String originalCategory = matchingRequest.mControlCategory; + String originalCategory = matchingRequest.mRouteType; Client2Record client2Record = matchingRequest.mClientRecord; if (!sessionInfo.getSelectedRoutes().contains(originalRouteId) || !TextUtils.equals(originalCategory, - sessionInfo.getControlCategory())) { + sessionInfo.getRouteType())) { Slog.w(TAG, "Created session doesn't match the original request." + " originalRouteId=" + originalRouteId + ", originalCategory=" + originalCategory + ", requestId=" + requestId @@ -1404,8 +1406,8 @@ class MediaRouter2ServiceImpl { try { manager.notifyRouteSelected(clientRecord.mPackageName, clientRecord.mSelectedRoute); - manager.notifyControlCategoriesChanged(clientRecord.mPackageName, - clientRecord.mControlCategories); + manager.notifyRouteTypesChanged(clientRecord.mPackageName, + clientRecord.mDiscoveryRequest.getRouteTypes()); } catch (RemoteException ex) { Slog.w(TAG, "Failed to update client usage. Manager probably died.", ex); } @@ -1424,15 +1426,15 @@ class MediaRouter2ServiceImpl { final class SessionCreationRequest { public final Client2Record mClientRecord; public final MediaRoute2Info mRoute; - public final String mControlCategory; + public final String mRouteType; public final long mRequestId; SessionCreationRequest(@NonNull Client2Record clientRecord, @NonNull MediaRoute2Info route, - @NonNull String controlCategory, long requestId) { + @NonNull String routeType, long requestId) { mClientRecord = clientRecord; mRoute = route; - mControlCategory = controlCategory; + mRouteType = routeType; mRequestId = requestId; } } diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index d77f43b4435d..c76555cf15cf 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -39,6 +39,7 @@ import android.media.MediaRouter; import android.media.MediaRouterClientState; import android.media.RemoteDisplayState; import android.media.RemoteDisplayState.RemoteDisplayInfo; +import android.media.RouteDiscoveryRequest; import android.media.RouteSessionInfo; import android.os.Binder; import android.os.Handler; @@ -459,8 +460,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route, - String controlCategory, int requestId) { - mService2.requestCreateSession(client, route, controlCategory, requestId); + String routeType, int requestId) { + mService2.requestCreateSession(client, route, routeType, requestId); } // Binder call @@ -519,8 +520,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub } // Binder call @Override - public void setControlCategories(IMediaRouter2Client client, List<String> categories) { - mService2.setControlCategories(client, categories); + public void setDiscoveryRequest2(IMediaRouter2Client client, RouteDiscoveryRequest request) { + mService2.setDiscoveryRequest2(client, request); } // Binder call diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java new file mode 100644 index 000000000000..f3241ee44569 --- /dev/null +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -0,0 +1,179 @@ +/* + * Copyright 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.server.media; + +import android.media.MediaController2; +import android.media.Session2CommandGroup; +import android.media.Session2Token; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.Looper; +import android.os.ResultReceiver; +import android.os.UserHandle; +import android.util.Log; +import android.view.KeyEvent; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; + +/** + * Keeps the record of {@link Session2Token} helps to send command to the corresponding session. + */ +// TODO(jaewan): Do not call service method directly -- introduce listener instead. +public class MediaSession2Record implements MediaSessionRecordImpl { + private static final String TAG = "MediaSession2Record"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private final Session2Token mSessionToken; + @GuardedBy("mLock") + private final HandlerExecutor mHandlerExecutor; + @GuardedBy("mLock") + private final MediaController2 mController; + @GuardedBy("mLock") + private final MediaSessionService mService; + @GuardedBy("mLock") + private boolean mIsConnected; + + public MediaSession2Record(Session2Token sessionToken, MediaSessionService service, + Looper handlerLooper) { + mSessionToken = sessionToken; + mService = service; + mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper)); + mController = new MediaController2.Builder(service.getContext(), sessionToken) + .setControllerCallback(mHandlerExecutor, new Controller2Callback()) + .build(); + } + + @Override + public String getPackageName() { + return mSessionToken.getPackageName(); + } + + public Session2Token getSession2Token() { + return mSessionToken; + } + + @Override + public int getUid() { + return mSessionToken.getUid(); + } + + @Override + public int getUserId() { + return UserHandle.getUserId(mSessionToken.getUid()); + } + + @Override + public boolean isSystemPriority() { + // System priority session is currently only allowed for telephony, and it's OK to stick to + // the media1 API at this moment. + return false; + } + + @Override + public void adjustVolume(String packageName, String opPackageName, int pid, int uid, + boolean asSystemService, int direction, int flags, boolean useSuggested) { + // TODO(jaewan): Add API to adjust volume. + } + + @Override + public boolean isActive() { + synchronized (mLock) { + return mIsConnected; + } + } + + @Override + public boolean checkPlaybackActiveState(boolean expected) { + synchronized (mLock) { + return mIsConnected && mController.isPlaybackActive() == expected; + } + } + + @Override + public boolean isPlaybackTypeLocal() { + // TODO(jaewan): Implement -- need API to know whether the playback is remote or local. + return true; + } + + @Override + public void close() { + synchronized (mLock) { + // Call close regardless of the mIsAvailable. This may be called when it's not yet + // connected. + mController.close(); + } + } + + @Override + public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, + KeyEvent ke, int sequenceId, ResultReceiver cb) { + // TODO(jaewan): Implement. + return false; + } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "token=" + mSessionToken); + pw.println(prefix + "controller=" + mController); + + final String indent = prefix + " "; + pw.println(indent + "playbackActive=" + mController.isPlaybackActive()); + } + + @Override + public String toString() { + // TODO(jaewan): Also add getId(). + return getPackageName() + " (userId=" + getUserId() + ")"; + } + + private class Controller2Callback extends MediaController2.ControllerCallback { + @Override + public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) { + if (DEBUG) { + Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands); + } + synchronized (mLock) { + mIsConnected = true; + } + mService.onSessionActiveStateChanged(MediaSession2Record.this); + } + + @Override + public void onDisconnected(MediaController2 controller) { + if (DEBUG) { + Log.d(TAG, "disconnected from " + mSessionToken); + } + synchronized (mLock) { + mIsConnected = false; + } + mService.onSessionDied(MediaSession2Record.this); + } + + @Override + public void onPlaybackActiveChanged(MediaController2 controller, boolean playbackActive) { + if (DEBUG) { + Log.d(TAG, "playback active changed, " + mSessionToken + ", active=" + + playbackActive); + } + mService.onSessionPlaybackStateChanged(MediaSession2Record.this, playbackActive); + } + } +} diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index aa24ed26023a..df115d0f2773 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -56,13 +56,15 @@ import com.android.server.LocalServices; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * This is the system implementation of a Session. Apps will interact with the * MediaSession wrapper class instead. */ -public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable { +// TODO(jaewan): Do not call service method directly -- introduce listener instead. +public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl { private static final String TAG = "MediaSessionRecord"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -72,6 +74,24 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable */ private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000; + /** + * These are states that usually indicate the user took an action and should + * bump priority regardless of the old state. + */ + private static final List<Integer> ALWAYS_PRIORITY_STATES = Arrays.asList( + PlaybackState.STATE_FAST_FORWARDING, + PlaybackState.STATE_REWINDING, + PlaybackState.STATE_SKIPPING_TO_PREVIOUS, + PlaybackState.STATE_SKIPPING_TO_NEXT); + /** + * These are states that usually indicate the user took an action if they + * were entered from a non-priority state. + */ + private static final List<Integer> TRANSITION_PRIORITY_STATES = Arrays.asList( + PlaybackState.STATE_BUFFERING, + PlaybackState.STATE_CONNECTING, + PlaybackState.STATE_PLAYING); + private final MessageHandler mHandler; private final int mOwnerPid; @@ -170,6 +190,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * * @return Info that identifies this session. */ + @Override public String getPackageName() { return mPackageName; } @@ -188,6 +209,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * * @return The UID for this session. */ + @Override public int getUid() { return mOwnerUid; } @@ -197,6 +219,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * * @return The user id for this session. */ + @Override public int getUserId() { return mUserId; } @@ -207,6 +230,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * * @return True if this is a system priority session, false otherwise */ + @Override public boolean isSystemPriority() { return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0; } @@ -220,7 +244,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * @param opPackageName The op package that made the original volume request. * @param pid The pid that made the original volume request. * @param uid The uid that made the original volume request. - * @param caller caller binder. can be {@code null} if it's from the volume key. * @param asSystemService {@code true} if the event sent to the session as if it was come from * the system service instead of the app process. This helps sessions to distinguish * between the key injection by the app and key events from the hardware devices. @@ -318,9 +341,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable /** * Check if this session has been set to active by the app. + * <p> + * It's not used to prioritize sessions for dispatching media keys since API 26, but still used + * to filter session list in MediaSessionManager#getActiveSessions(). * * @return True if the session is active, false otherwise. */ + @Override public boolean isActive() { return mIsActive && !mDestroyed; } @@ -333,6 +360,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * @param expected True if playback is expected to be active. false otherwise. * @return True if the session's playback matches with the expectation. false otherwise. */ + @Override public boolean checkPlaybackActiveState(boolean expected) { if (mPlaybackState == null) { return false; @@ -345,13 +373,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * * @return {@code true} if the playback is local. */ - public boolean isPlaybackLocal() { + @Override + public boolean isPlaybackTypeLocal() { return mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL; } @Override public void binderDied() { - mService.sessionDied(this); + mService.onSessionDied(this); } /** @@ -383,7 +412,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable * @param sequenceId (optional) sequence id. Use this only when a wake lock is needed. * @param cb (optional) result receiver to receive callback. Use this only when a wake lock is * needed. - * @return {@code true} if the attempt to send media button was successfuly. + * @return {@code true} if the attempt to send media button was successfully. * {@code false} otherwise. */ public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, @@ -392,6 +421,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable cb); } + @Override public void dump(PrintWriter pw, String prefix) { pw.println(prefix + mTag + " " + this); @@ -712,7 +742,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable public void destroySession() throws RemoteException { final long token = Binder.clearCallingIdentity(); try { - mService.destroySession(MediaSessionRecord.this); + mService.onSessionDied(MediaSessionRecord.this); } finally { Binder.restoreCallingIdentity(token); } @@ -734,7 +764,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable mIsActive = active; final long token = Binder.clearCallingIdentity(); try { - mService.updateSession(MediaSessionRecord.this); + mService.onSessionActiveStateChanged(MediaSessionRecord.this); } finally { Binder.restoreCallingIdentity(token); } @@ -801,12 +831,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, AutoCloseable ? PlaybackState.STATE_NONE : mPlaybackState.getState(); int newState = state == null ? PlaybackState.STATE_NONE : state.getState(); + boolean shouldUpdatePriority = ALWAYS_PRIORITY_STATES.contains(newState) + || (!TRANSITION_PRIORITY_STATES.contains(oldState) + && TRANSITION_PRIORITY_STATES.contains(newState)); synchronized (mLock) { mPlaybackState = state; } final long token = Binder.clearCallingIdentity(); try { - mService.onSessionPlaystateChanged(MediaSessionRecord.this, oldState, newState); + mService.onSessionPlaybackStateChanged( + MediaSessionRecord.this, shouldUpdatePriority); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java new file mode 100644 index 000000000000..2cde89a7a6f6 --- /dev/null +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -0,0 +1,143 @@ +/* + * Copyright 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.server.media; + +import android.media.AudioManager; +import android.os.ResultReceiver; +import android.view.KeyEvent; + +import java.io.PrintWriter; + +/** + * Common interfaces between {@link MediaSessionRecord} and {@link MediaSession2Record}. + */ +public interface MediaSessionRecordImpl extends AutoCloseable { + + /** + * Get the info for this session. + * + * @return Info that identifies this session. + */ + String getPackageName(); + + /** + * Get the UID this session was created for. + * + * @return The UID for this session. + */ + int getUid(); + + /** + * Get the user id this session was created for. + * + * @return The user id for this session. + */ + int getUserId(); + + /** + * Check if this session has system priorty and should receive media buttons + * before any other sessions. + * + * @return True if this is a system priority session, false otherwise + */ + boolean isSystemPriority(); + + /** + * Send a volume adjustment to the session owner. Direction must be one of + * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE}, + * {@link AudioManager#ADJUST_SAME}. + * + * @param packageName The package that made the original volume request. + * @param opPackageName The op package that made the original volume request. + * @param pid The pid that made the original volume request. + * @param uid The uid that made the original volume request. + * @param asSystemService {@code true} if the event sent to the session as if it was come from + * the system service instead of the app process. This helps sessions to distinguish + * between the key injection by the app and key events from the hardware devices. + * Should be used only when the volume key events aren't handled by foreground + * activity. {@code false} otherwise to tell session about the real caller. + * @param direction The direction to adjust volume in. + * @param flags Any of the flags from {@link AudioManager}. + * @param useSuggested True to use adjustSuggestedStreamVolume instead of + */ + void adjustVolume(String packageName, String opPackageName, int pid, int uid, + boolean asSystemService, int direction, int flags, boolean useSuggested); + + /** + * Check if this session has been set to active by the app. (i.e. ready to receive command and + * getters are available). + * + * @return True if the session is active, false otherwise. + */ + // TODO(jaewan): Find better naming, or remove this from the MediaSessionRecordImpl. + boolean isActive(); + + /** + * Check if the session's playback active state matches with the expectation. This always return + * {@code false} if the playback state is unknown (e.g. {@code null}), where we cannot know the + * actual playback state associated with the session. + * + * @param expected True if playback is expected to be active. false otherwise. + * @return True if the session's playback matches with the expectation. false otherwise. + */ + boolean checkPlaybackActiveState(boolean expected); + + /** + * Check whether the playback type is local or remote. + * <p> + * <ul> + * <li>Local: volume changes the stream volume because playback happens on this device.</li> + * <li>Remote: volume is sent to the apps callback because playback happens on the remote + * device and we cannot know how to control the volume of it.</li> + * </ul> + * + * @return {@code true} if the playback is local. {@code false} if the playback is remote. + */ + boolean isPlaybackTypeLocal(); + + /** + * Sends media button. + * + * @param packageName caller package name + * @param pid caller pid + * @param uid caller uid + * @param asSystemService {@code true} if the event sent to the session as if it was come from + * the system service instead of the app process. + * @param ke key events + * @param sequenceId (optional) sequence id. Use this only when a wake lock is needed. + * @param cb (optional) result receiver to receive callback. Use this only when a wake lock is + * needed. + * @return {@code true} if the attempt to send media button was successfully. + * {@code false} otherwise. + */ + boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, + KeyEvent ke, int sequenceId, ResultReceiver cb); + + /** + * Dumps internal state + * + * @param pw print writer + * @param prefix prefix + */ + void dump(PrintWriter pw, String prefix); + + /** + * Override {@link AutoCloseable#close} to tell not to throw exception. + */ + @Override + void close(); +} diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 0f059dba5274..f71fb582e3ed 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -40,10 +40,7 @@ import android.media.AudioManager; import android.media.AudioManagerInternal; import android.media.AudioPlaybackConfiguration; import android.media.AudioSystem; -import android.media.IAudioService; import android.media.IRemoteVolumeController; -import android.media.MediaController2; -import android.media.Session2CommandGroup; import android.media.Session2Token; import android.media.session.IActiveSessionsListener; import android.media.session.IOnMediaKeyEventDispatchedListener; @@ -61,7 +58,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Message; import android.os.PowerManager; @@ -123,11 +119,6 @@ public class MediaSessionService extends SystemService implements Monitor { @GuardedBy("mLock") private final ArrayList<SessionsListenerRecord> mSessionsListeners = new ArrayList<SessionsListenerRecord>(); - // Map user id as index to list of Session2Tokens - // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in - // one place. - @GuardedBy("mLock") - private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>(); @GuardedBy("mLock") private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords = new ArrayList<>(); @@ -189,16 +180,11 @@ public class MediaSessionService extends SystemService implements Monitor { updateUser(); } - private IAudioService getAudioService() { - IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); - return IAudioService.Stub.asInterface(b); - } - private boolean isGlobalPriorityActiveLocked() { return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive(); } - void updateSession(MediaSessionRecord record) { + void onSessionActiveStateChanged(MediaSessionRecordImpl record) { synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(record.getUserId()); if (user == null) { @@ -215,12 +201,14 @@ public class MediaSessionService extends SystemService implements Monitor { Log.w(TAG, "Unknown session updated. Ignoring."); return; } - user.mPriorityStack.onSessionStateChange(record); + user.mPriorityStack.onSessionActiveStateChanged(record); } - mHandler.postSessionsChanged(record.getUserId()); + + mHandler.postSessionsChanged(record); } } + // Currently only media1 can become global priority session. void setGlobalPrioritySession(MediaSessionRecord record) { synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(record.getUserId()); @@ -266,11 +254,13 @@ public class MediaSessionService extends SystemService implements Monitor { List<Session2Token> getSession2TokensLocked(int userId) { List<Session2Token> list = new ArrayList<>(); if (userId == USER_ALL) { - for (int i = 0; i < mSession2TokensPerUser.size(); i++) { - list.addAll(mSession2TokensPerUser.valueAt(i)); + int size = mUserRecords.size(); + for (int i = 0; i < size; i++) { + list.addAll(mUserRecords.valueAt(i).mPriorityStack.getSession2Tokens(userId)); } } else { - list.addAll(mSession2TokensPerUser.get(userId)); + FullUserRecord user = getFullUserRecordLocked(userId); + list.addAll(user.mPriorityStack.getSession2Tokens(userId)); } return list; } @@ -297,14 +287,15 @@ public class MediaSessionService extends SystemService implements Monitor { } } - void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) { + void onSessionPlaybackStateChanged(MediaSessionRecordImpl record, + boolean shouldUpdatePriority) { synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(record.getUserId()); if (user == null || !user.mPriorityStack.contains(record)) { Log.d(TAG, "Unknown session changed playback state. Ignoring."); return; } - user.mPriorityStack.onPlaystateChanged(record, oldState, newState); + user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority); } } @@ -347,7 +338,6 @@ public class MediaSessionService extends SystemService implements Monitor { user.destroySessionsForUserLocked(userId); } } - mSession2TokensPerUser.remove(userId); updateUser(); } } @@ -366,13 +356,7 @@ public class MediaSessionService extends SystemService implements Monitor { } } - void sessionDied(MediaSessionRecord session) { - synchronized (mLock) { - destroySessionLocked(session); - } - } - - void destroySession(MediaSessionRecord session) { + void onSessionDied(MediaSessionRecordImpl session) { synchronized (mLock) { destroySessionLocked(session); } @@ -393,9 +377,6 @@ public class MediaSessionService extends SystemService implements Monitor { mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id)); } } - if (mSession2TokensPerUser.get(userInfo.id) == null) { - mSession2TokensPerUser.put(userInfo.id, new ArrayList<>()); - } } } // Ensure that the current full user exists. @@ -405,9 +386,6 @@ public class MediaSessionService extends SystemService implements Monitor { Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId); mCurrentFullUserRecord = new FullUserRecord(currentFullUserId); mUserRecords.put(currentFullUserId, mCurrentFullUserRecord); - if (mSession2TokensPerUser.get(currentFullUserId) == null) { - mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>()); - } } mFullUserIds.put(currentFullUserId, currentFullUserId); } @@ -444,7 +422,7 @@ public class MediaSessionService extends SystemService implements Monitor { * 5. We need to unlink to death from the cb binder * 6. We need to tell the session to do any final cleanup (onDestroy) */ - private void destroySessionLocked(MediaSessionRecord session) { + private void destroySessionLocked(MediaSessionRecordImpl session) { if (DEBUG) { Log.d(TAG, "Destroying " + session); } @@ -461,7 +439,7 @@ public class MediaSessionService extends SystemService implements Monitor { } session.close(); - mHandler.postSessionsChanged(session.getUserId()); + mHandler.postSessionsChanged(session); } private void enforcePackageName(String packageName, int uid) { @@ -541,15 +519,6 @@ public class MediaSessionService extends SystemService implements Monitor { return false; } - private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId, - String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) - throws RemoteException { - synchronized (mLock) { - return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, - tag, sessionInfo); - } - } - /* * When a session is created the following things need to happen. * 1. Its callback binder needs a link to death @@ -557,29 +526,31 @@ public class MediaSessionService extends SystemService implements Monitor { * 3. It needs to be added to the priority stack. * 4. It needs to be added to the relevant user record. */ - private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId, + private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId, String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) { - FullUserRecord user = getFullUserRecordLocked(userId); - if (user == null) { - Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName); - throw new RuntimeException("Session request from invalid user."); - } + synchronized (mLock) { + FullUserRecord user = getFullUserRecordLocked(userId); + if (user == null) { + Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName); + throw new RuntimeException("Session request from invalid user."); + } - final MediaSessionRecord session; - try { - session = new MediaSessionRecord(callerPid, callerUid, userId, - callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper()); - } catch (RemoteException e) { - throw new RuntimeException("Media Session owner died prematurely.", e); - } + final MediaSessionRecord session; + try { + session = new MediaSessionRecord(callerPid, callerUid, userId, + callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper()); + } catch (RemoteException e) { + throw new RuntimeException("Media Session owner died prematurely.", e); + } - user.mPriorityStack.addSession(session); - mHandler.postSessionsChanged(userId); + user.mPriorityStack.addSession(session); + mHandler.postSessionsChanged(session); - if (DEBUG) { - Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag); + if (DEBUG) { + Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag); + } + return session; } - return session; } private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) { @@ -600,16 +571,16 @@ public class MediaSessionService extends SystemService implements Monitor { return -1; } - private void pushSessionsChanged(int userId) { + private void pushSession1Changed(int userId) { synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(userId); if (user == null) { - Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId); + Log.w(TAG, "pushSession1ChangedOnHandler failed. No user with id=" + userId); return; } List<MediaSessionRecord> records = getActiveSessionsLocked(userId); int size = records.size(); - ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>(); + ArrayList<MediaSession.Token> tokens = new ArrayList<>(); for (int i = 0; i < size; i++) { tokens.add(records.get(i).getSessionToken()); } @@ -629,6 +600,27 @@ public class MediaSessionService extends SystemService implements Monitor { } } + void pushSession2Changed(int userId) { + synchronized (mLock) { + List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL); + List<Session2Token> session2Tokens = getSession2TokensLocked(userId); + + for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) { + Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i); + try { + if (listenerRecord.userId == USER_ALL) { + listenerRecord.listener.onSession2TokensChanged(allSession2Tokens); + } else if (listenerRecord.userId == userId) { + listenerRecord.listener.onSession2TokensChanged(session2Tokens); + } + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e); + mSession2TokensListenerRecords.remove(i); + } + } + } + } + private void pushRemoteVolumeUpdateLocked(int userId) { FullUserRecord user = getFullUserRecordLocked(userId); if (user == null) { @@ -638,8 +630,13 @@ public class MediaSessionService extends SystemService implements Monitor { synchronized (mLock) { int size = mRemoteVolumeControllers.beginBroadcast(); - MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId); - MediaSession.Token token = record == null ? null : record.getSessionToken(); + MediaSessionRecordImpl record = user.mPriorityStack.getDefaultRemoteSession(userId); + if (record instanceof MediaSession2Record) { + // TODO(jaewan): Implement + return; + } + MediaSession.Token token = record == null + ? null : ((MediaSessionRecord) record).getSessionToken(); for (int i = size - 1; i >= 0; i--) { try { @@ -653,34 +650,15 @@ public class MediaSessionService extends SystemService implements Monitor { } } - void pushSession2TokensChangedLocked(int userId) { - List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL); - List<Session2Token> session2Tokens = getSession2TokensLocked(userId); - - for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) { - Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i); - try { - if (listenerRecord.userId == USER_ALL) { - listenerRecord.listener.onSession2TokensChanged(allSession2Tokens); - } else if (listenerRecord.userId == userId) { - listenerRecord.listener.onSession2TokensChanged(session2Tokens); - } - } catch (RemoteException e) { - Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e); - mSession2TokensListenerRecords.remove(i); - } - } - } - /** * Called when the media button receiver for the {@code record} is changed. * * @param record the media session whose media button receiver is updated. */ - public void onMediaButtonReceiverChanged(MediaSessionRecord record) { + public void onMediaButtonReceiverChanged(MediaSessionRecordImpl record) { synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(record.getUserId()); - MediaSessionRecord mediaButtonSession = + MediaSessionRecordImpl mediaButtonSession = user.mPriorityStack.getMediaButtonSession(); if (record == mediaButtonSession) { user.rememberMediaButtonReceiverLocked(mediaButtonSession); @@ -868,39 +846,34 @@ public class MediaSessionService extends SystemService implements Monitor { pw.println(indent + "Restored MediaButtonReceiverComponentType: " + mRestoredMediaButtonReceiverComponentType); mPriorityStack.dump(pw, indent); - pw.println(indent + "Session2Tokens:"); - for (int i = 0; i < mSession2TokensPerUser.size(); i++) { - List<Session2Token> list = mSession2TokensPerUser.valueAt(i); - if (list == null || list.size() == 0) { - continue; - } - for (Session2Token token : list) { - pw.println(indent + " " + token); - } - } } @Override - public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession, - MediaSessionRecord newMediaButtonSession) { + public void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession, + MediaSessionRecordImpl newMediaButtonSession) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Media button session is changed to " + newMediaButtonSession); } synchronized (mLock) { if (oldMediaButtonSession != null) { - mHandler.postSessionsChanged(oldMediaButtonSession.getUserId()); + mHandler.postSessionsChanged(oldMediaButtonSession); } if (newMediaButtonSession != null) { rememberMediaButtonReceiverLocked(newMediaButtonSession); - mHandler.postSessionsChanged(newMediaButtonSession.getUserId()); + mHandler.postSessionsChanged(newMediaButtonSession); } pushAddressedPlayerChangedLocked(); } } // Remember media button receiver and keep it in the persistent storage. - public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) { - PendingIntent receiver = record.getMediaButtonReceiver(); + public void rememberMediaButtonReceiverLocked(MediaSessionRecordImpl record) { + if (record instanceof MediaSession2Record) { + // TODO(jaewan): Implement + return; + } + MediaSessionRecord sessionRecord = (MediaSessionRecord) record; + PendingIntent receiver = sessionRecord.getMediaButtonReceiver(); mLastMediaButtonReceiver = receiver; mRestoredMediaButtonReceiver = null; mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID; @@ -925,10 +898,15 @@ public class MediaSessionService extends SystemService implements Monitor { private void pushAddressedPlayerChangedLocked( IOnMediaKeyEventSessionChangedListener callback) { try { - MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked(); + MediaSessionRecordImpl mediaButtonSession = getMediaButtonSessionLocked(); if (mediaButtonSession != null) { - callback.onMediaKeyEventSessionChanged(mediaButtonSession.getPackageName(), - mediaButtonSession.getSessionToken()); + if (mediaButtonSession instanceof MediaSessionRecord) { + MediaSessionRecord session1 = (MediaSessionRecord) mediaButtonSession; + callback.onMediaKeyEventSessionChanged(session1.getPackageName(), + session1.getSessionToken()); + } else { + // TODO(jaewan): Implement + } } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) { callback.onMediaKeyEventSessionChanged( mCurrentFullUserRecord.mLastMediaButtonReceiver @@ -951,7 +929,7 @@ public class MediaSessionService extends SystemService implements Monitor { } } - private MediaSessionRecord getMediaButtonSessionLocked() { + private MediaSessionRecordImpl getMediaButtonSessionLocked() { return isGlobalPriorityActiveLocked() ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession(); } @@ -1132,14 +1110,13 @@ public class MediaSessionService extends SystemService implements Monitor { throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid + " but actually=" + sessionToken.getUid()); } - Controller2Callback callback = new Controller2Callback(sessionToken); - // Note: It's safe not to keep controller here because it wouldn't be GC'ed until - // it's closed. - // TODO: Keep controller as well for better readability - // because the GC behavior isn't straightforward. - MediaController2 controller = new MediaController2.Builder(mContext, sessionToken) - .setControllerCallback(new HandlerExecutor(mHandler), callback) - .build(); + MediaSession2Record record = new MediaSession2Record( + sessionToken, MediaSessionService.this, mHandler.getLooper()); + synchronized (mLock) { + FullUserRecord user = getFullUserRecordLocked(record.getUserId()); + user.mPriorityStack.addSession(record); + } + // Do not immediately notify changes -- do so when framework can dispatch command } finally { Binder.restoreCallingIdentity(token); } @@ -1180,7 +1157,8 @@ public class MediaSessionService extends SystemService implements Monitor { null /* optional packageName */); List<Session2Token> result; synchronized (mLock) { - result = getSession2TokensLocked(resolvedUserId); + FullUserRecord user = getFullUserRecordLocked(userId); + result = user.mPriorityStack.getSession2Tokens(resolvedUserId); } return new ParceledListSlice(result); } finally { @@ -2018,7 +1996,7 @@ public class MediaSessionService extends SystemService implements Monitor { private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid, int uid, boolean asSystemService, int suggestedStream, int direction, int flags) { - MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession + MediaSessionRecordImpl session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession(); boolean preferSuggestedStream = false; @@ -2109,7 +2087,13 @@ public class MediaSessionService extends SystemService implements Monitor { private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid, boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) { - MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked(); + if (mCurrentFullUserRecord.getMediaButtonSessionLocked() + instanceof MediaSession2Record) { + // TODO(jaewan): Implement + return; + } + MediaSessionRecord session = + (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked(); if (session != null) { if (DEBUG_KEY_EVENT) { Log.d(TAG, "Sending " + keyEvent + " to " + session); @@ -2389,15 +2373,19 @@ public class MediaSessionService extends SystemService implements Monitor { } final class MessageHandler extends Handler { - private static final int MSG_SESSIONS_CHANGED = 1; - private static final int MSG_VOLUME_INITIAL_DOWN = 2; + private static final int MSG_SESSIONS_1_CHANGED = 1; + private static final int MSG_SESSIONS_2_CHANGED = 2; + private static final int MSG_VOLUME_INITIAL_DOWN = 3; private final SparseArray<Integer> mIntegerCache = new SparseArray<>(); @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_SESSIONS_CHANGED: - pushSessionsChanged((int) msg.obj); + case MSG_SESSIONS_1_CHANGED: + pushSession1Changed((int) msg.obj); + break; + case MSG_SESSIONS_2_CHANGED: + pushSession2Changed((int) msg.obj); break; case MSG_VOLUME_INITIAL_DOWN: synchronized (mLock) { @@ -2412,41 +2400,19 @@ public class MediaSessionService extends SystemService implements Monitor { } } - public void postSessionsChanged(int userId) { + public void postSessionsChanged(MediaSessionRecordImpl record) { // Use object instead of the arguments when posting message to remove pending requests. - Integer userIdInteger = mIntegerCache.get(userId); + Integer userIdInteger = mIntegerCache.get(record.getUserId()); if (userIdInteger == null) { - userIdInteger = Integer.valueOf(userId); - mIntegerCache.put(userId, userIdInteger); + userIdInteger = Integer.valueOf(record.getUserId()); + mIntegerCache.put(record.getUserId(), userIdInteger); } - removeMessages(MSG_SESSIONS_CHANGED, userIdInteger); - obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget(); - } - } - private class Controller2Callback extends MediaController2.ControllerCallback { - private final Session2Token mToken; - - Controller2Callback(Session2Token token) { - mToken = token; - } - - @Override - public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) { - synchronized (mLock) { - int userId = UserHandle.getUserId(mToken.getUid()); - mSession2TokensPerUser.get(userId).add(mToken); - pushSession2TokensChangedLocked(userId); - } - } - - @Override - public void onDisconnected(MediaController2 controller) { - synchronized (mLock) { - int userId = UserHandle.getUserId(mToken.getUid()); - mSession2TokensPerUser.get(userId).remove(mToken); - pushSession2TokensChangedLocked(userId); - } + int msg = (record instanceof MediaSessionRecord) + ? MSG_SESSIONS_1_CHANGED : MSG_SESSIONS_2_CHANGED; + removeMessages(msg, userIdInteger); + obtainMessage(msg, userIdInteger).sendToTarget(); } } + } diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index 732563f6e05e..7bb7cf4b74ad 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -16,8 +16,8 @@ package com.android.server.media; +import android.media.Session2Token; import android.media.session.MediaSession; -import android.media.session.PlaybackState; import android.os.Debug; import android.os.UserHandle; import android.util.IntArray; @@ -45,51 +45,30 @@ class MediaSessionStack { /** * Called when the media button session is changed. */ - void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession, - MediaSessionRecord newMediaButtonSession); + void onMediaButtonSessionChanged(MediaSessionRecordImpl oldMediaButtonSession, + MediaSessionRecordImpl newMediaButtonSession); } /** - * These are states that usually indicate the user took an action and should - * bump priority regardless of the old state. + * Sorted list of the media sessions */ - private static final int[] ALWAYS_PRIORITY_STATES = { - PlaybackState.STATE_FAST_FORWARDING, - PlaybackState.STATE_REWINDING, - PlaybackState.STATE_SKIPPING_TO_PREVIOUS, - PlaybackState.STATE_SKIPPING_TO_NEXT }; - /** - * These are states that usually indicate the user took an action if they - * were entered from a non-priority state. - */ - private static final int[] TRANSITION_PRIORITY_STATES = { - PlaybackState.STATE_BUFFERING, - PlaybackState.STATE_CONNECTING, - PlaybackState.STATE_PLAYING }; - - /** - * Sorted list of the media sessions. - * The session of which PlaybackState is changed to ALWAYS_PRIORITY_STATES or - * TRANSITION_PRIORITY_STATES comes first. - * @see #shouldUpdatePriority - */ - private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>(); + private final List<MediaSessionRecordImpl> mSessions = new ArrayList<>(); private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener; /** * The media button session which receives media key events. - * It could be null if the previous media buttion session is released. + * It could be null if the previous media button session is released. */ - private MediaSessionRecord mMediaButtonSession; + private MediaSessionRecordImpl mMediaButtonSession; - private MediaSessionRecord mCachedVolumeDefault; + private MediaSessionRecordImpl mCachedVolumeDefault; /** * Cache the result of the {@link #getActiveSessions} per user. */ - private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists = + private final SparseArray<List<MediaSessionRecord>> mCachedActiveLists = new SparseArray<>(); MediaSessionStack(AudioPlayerStateMonitor monitor, OnMediaButtonSessionChangedListener listener) { @@ -102,7 +81,7 @@ class MediaSessionStack { * * @param record The record to add. */ - public void addSession(MediaSessionRecord record) { + public void addSession(MediaSessionRecordImpl record) { mSessions.add(record); clearCache(record.getUserId()); @@ -117,7 +96,7 @@ class MediaSessionStack { * * @param record The record to remove. */ - public void removeSession(MediaSessionRecord record) { + public void removeSession(MediaSessionRecordImpl record) { mSessions.remove(record); if (mMediaButtonSession == record) { // When the media button session is removed, nullify the media button session and do not @@ -131,7 +110,7 @@ class MediaSessionStack { /** * Return if the record exists in the priority tracker. */ - public boolean contains(MediaSessionRecord record) { + public boolean contains(MediaSessionRecordImpl record) { return mSessions.contains(record); } @@ -142,9 +121,12 @@ class MediaSessionStack { * @return the MediaSessionRecord. Can be {@code null} if the session is gone meanwhile. */ public MediaSessionRecord getMediaSessionRecord(MediaSession.Token sessionToken) { - for (MediaSessionRecord record : mSessions) { - if (Objects.equals(record.getSessionToken(), sessionToken)) { - return record; + for (MediaSessionRecordImpl record : mSessions) { + if (record instanceof MediaSessionRecord) { + MediaSessionRecord session1 = (MediaSessionRecord) record; + if (Objects.equals(session1.getSessionToken(), sessionToken)) { + return session1; + } } } return null; @@ -154,15 +136,15 @@ class MediaSessionStack { * Notify the priority tracker that a session's playback state changed. * * @param record The record that changed. - * @param oldState Its old playback state. - * @param newState Its new playback state. + * @param shouldUpdatePriority {@code true} if the record needs to prioritized */ - public void onPlaystateChanged(MediaSessionRecord record, int oldState, int newState) { - if (shouldUpdatePriority(oldState, newState)) { + public void onPlaybackStateChanged( + MediaSessionRecordImpl record, boolean shouldUpdatePriority) { + if (shouldUpdatePriority) { mSessions.remove(record); mSessions.add(0, record); clearCache(record.getUserId()); - } else if (!MediaSession.isActiveState(newState)) { + } else if (record.checkPlaybackActiveState(false)) { // Just clear the volume cache when a state goes inactive mCachedVolumeDefault = null; } @@ -172,7 +154,7 @@ class MediaSessionStack { // In that case, we pick the media session whose PlaybackState matches // the audio playback configuration. if (mMediaButtonSession != null && mMediaButtonSession.getUid() == record.getUid()) { - MediaSessionRecord newMediaButtonSession = + MediaSessionRecordImpl newMediaButtonSession = findMediaButtonSession(mMediaButtonSession.getUid()); if (newMediaButtonSession != mMediaButtonSession) { updateMediaButtonSession(newMediaButtonSession); @@ -185,7 +167,7 @@ class MediaSessionStack { * * @param record The record that changed. */ - public void onSessionStateChange(MediaSessionRecord record) { + public void onSessionActiveStateChanged(MediaSessionRecordImpl record) { // For now just clear the cache. Eventually we'll selectively clear // depending on what changed. clearCache(record.getUserId()); @@ -203,7 +185,7 @@ class MediaSessionStack { } IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); for (int i = 0; i < audioPlaybackUids.size(); i++) { - MediaSessionRecord mediaButtonSession = + MediaSessionRecordImpl mediaButtonSession = findMediaButtonSession(audioPlaybackUids.get(i)); if (mediaButtonSession != null) { // Found the media button session. @@ -225,9 +207,9 @@ class MediaSessionStack { * @return The media button session. Returns {@code null} if the app doesn't have a media * session. */ - private MediaSessionRecord findMediaButtonSession(int uid) { - MediaSessionRecord mediaButtonSession = null; - for (MediaSessionRecord session : mSessions) { + private MediaSessionRecordImpl findMediaButtonSession(int uid) { + MediaSessionRecordImpl mediaButtonSession = null; + for (MediaSessionRecordImpl session : mSessions) { if (uid == session.getUid()) { if (session.checkPlaybackActiveState( mAudioPlayerStateMonitor.isPlaybackActive(session.getUid()))) { @@ -253,8 +235,8 @@ class MediaSessionStack { * for all users in this {@link MediaSessionStack}. * @return All the active sessions in priority order. */ - public ArrayList<MediaSessionRecord> getActiveSessions(int userId) { - ArrayList<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId); + public List<MediaSessionRecord> getActiveSessions(int userId) { + List<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId); if (cachedActiveList == null) { cachedActiveList = getPriorityList(true, userId); mCachedActiveLists.put(userId, cachedActiveList); @@ -263,26 +245,46 @@ class MediaSessionStack { } /** + * Gets the session2 tokens. + * + * @param userId The user to check. It can be {@link UserHandle#USER_ALL} to get all session2 + * tokens for all users in this {@link MediaSessionStack}. + * @return All session2 tokens. + */ + public List<Session2Token> getSession2Tokens(int userId) { + ArrayList<Session2Token> session2Records = new ArrayList<>(); + for (MediaSessionRecordImpl record : mSessions) { + if ((userId == UserHandle.USER_ALL || record.getUserId() == userId) + && record.isActive() + && record instanceof MediaSession2Record) { + MediaSession2Record session2 = (MediaSession2Record) record; + session2Records.add(session2.getSession2Token()); + } + } + return session2Records; + } + + /** * Get the media button session which receives the media button events. * * @return The media button session or null. */ - public MediaSessionRecord getMediaButtonSession() { + public MediaSessionRecordImpl getMediaButtonSession() { return mMediaButtonSession; } - private void updateMediaButtonSession(MediaSessionRecord newMediaButtonSession) { - MediaSessionRecord oldMediaButtonSession = mMediaButtonSession; + private void updateMediaButtonSession(MediaSessionRecordImpl newMediaButtonSession) { + MediaSessionRecordImpl oldMediaButtonSession = mMediaButtonSession; mMediaButtonSession = newMediaButtonSession; mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged( oldMediaButtonSession, newMediaButtonSession); } - public MediaSessionRecord getDefaultVolumeSession() { + public MediaSessionRecordImpl getDefaultVolumeSession() { if (mCachedVolumeDefault != null) { return mCachedVolumeDefault; } - ArrayList<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL); + List<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL); int size = records.size(); for (int i = 0; i < size; i++) { MediaSessionRecord record = records.get(i); @@ -294,13 +296,13 @@ class MediaSessionStack { return null; } - public MediaSessionRecord getDefaultRemoteSession(int userId) { - ArrayList<MediaSessionRecord> records = getPriorityList(true, userId); + public MediaSessionRecordImpl getDefaultRemoteSession(int userId) { + List<MediaSessionRecord> records = getPriorityList(true, userId); int size = records.size(); for (int i = 0; i < size; i++) { MediaSessionRecord record = records.get(i); - if (!record.isPlaybackLocal()) { + if (!record.isPlaybackTypeLocal()) { return record; } } @@ -308,16 +310,11 @@ class MediaSessionStack { } public void dump(PrintWriter pw, String prefix) { - ArrayList<MediaSessionRecord> sortedSessions = getPriorityList(false, - UserHandle.USER_ALL); - int count = sortedSessions.size(); pw.println(prefix + "Media button session is " + mMediaButtonSession); - pw.println(prefix + "Sessions Stack - have " + count + " sessions:"); + pw.println(prefix + "Sessions Stack - have " + mSessions.size() + " sessions:"); String indent = prefix + " "; - for (int i = 0; i < count; i++) { - MediaSessionRecord record = sortedSessions.get(i); + for (MediaSessionRecordImpl record : mSessions) { record.dump(pw, indent); - pw.println(); } } @@ -335,17 +332,19 @@ class MediaSessionStack { * will return sessions for all users. * @return The priority sorted list of sessions. */ - public ArrayList<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) { - ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); + public List<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) { + List<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); int lastPlaybackActiveIndex = 0; int lastActiveIndex = 0; - int size = mSessions.size(); - for (int i = 0; i < size; i++) { - final MediaSessionRecord session = mSessions.get(i); + for (MediaSessionRecordImpl record : mSessions) { + if (!(record instanceof MediaSessionRecord)) { + continue; + } + final MediaSessionRecord session = (MediaSessionRecord) record; - if (userId != UserHandle.USER_ALL && userId != session.getUserId()) { - // Filter out sessions for the wrong user + if ((userId != UserHandle.USER_ALL && userId != session.getUserId())) { + // Filter out sessions for the wrong user or session2. continue; } @@ -369,26 +368,6 @@ class MediaSessionStack { return result; } - private boolean shouldUpdatePriority(int oldState, int newState) { - if (containsState(newState, ALWAYS_PRIORITY_STATES)) { - return true; - } - if (!containsState(oldState, TRANSITION_PRIORITY_STATES) - && containsState(newState, TRANSITION_PRIORITY_STATES)) { - return true; - } - return false; - } - - private boolean containsState(int state, int[] states) { - for (int i = 0; i < states.length; i++) { - if (states[i] == state) { - return true; - } - } - return false; - } - private void clearCache(int userId) { mCachedVolumeDefault = null; mCachedActiveLists.remove(userId); diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 53027655390b..daf603012391 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -91,7 +91,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } @Override - public void requestCreateSession(String packageName, String routeId, String controlCategory, + public void requestCreateSession(String packageName, String routeId, String routeType, long requestId) { // Do nothing } @@ -141,8 +141,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) - .addSupportedCategory(CATEGORY_LIVE_AUDIO) - .addSupportedCategory(CATEGORY_LIVE_VIDEO) + .addRouteType(CATEGORY_LIVE_AUDIO) + .addRouteType(CATEGORY_LIVE_VIDEO) .build(); AudioRoutesInfo newAudioRoutes = null; @@ -181,8 +181,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) - .addSupportedCategory(CATEGORY_LIVE_AUDIO) - .addSupportedCategory(CATEGORY_LIVE_VIDEO) + .addRouteType(CATEGORY_LIVE_AUDIO) + .addRouteType(CATEGORY_LIVE_VIDEO) .build(); if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { @@ -193,7 +193,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mCurAudioRoutesInfo.bluetoothName) .setDescription(mContext.getResources().getText( R.string.bluetooth_a2dp_audio_route_name).toString()) - .addSupportedCategory(CATEGORY_LIVE_AUDIO) + .addRouteType(CATEGORY_LIVE_AUDIO) .build(); } else { mBluetoothA2dpRoute = null; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3ca1803262e7..22b01bee6c6a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addValues(entry); + stats.addEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ec8a8e7c4c1a..7a6f29764f09 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.IFACE_VT; import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; @@ -211,7 +212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Virtual network interface for video telephony. This is for VT data usage counting purpose. */ - public static final String VT_INTERFACE = "vt_data0"; + // TODO: Remove this after no one is using it. + public static final String VT_INTERFACE = NetworkStats.IFACE_VT; /** * Settings that can be changed externally. @@ -712,7 +714,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; @@ -1179,8 +1181,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */); - findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } if (isMobile) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 426cd01d3d0b..4dcdf7ea0ecc 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -140,6 +140,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -209,6 +210,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; private static final int[] EMPTY_CHILD_SESSION_ARRAY = {}; + private static final String SYSTEM_DATA_LOADER_PACKAGE = "android"; + // TODO: enforce INSTALL_ALLOW_TEST // TODO: enforce INSTALL_ALLOW_DOWNGRADE @@ -555,6 +558,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.dataLoaderParams); } } + + if (isStreamingInstallation() + && this.params.dataLoaderParams.getComponentName().getPackageName() + == SYSTEM_DATA_LOADER_PACKAGE) { + assertShellOrSystemCalling("System data loaders"); + } } public SessionInfo generateInfo() { @@ -770,6 +779,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private void assertShellOrSystemCalling(String operation) { + switch (Binder.getCallingUid()) { + case android.os.Process.SHELL_UID: + case android.os.Process.ROOT_UID: + case android.os.Process.SYSTEM_UID: + break; + default: + throw new SecurityException(operation + " only supported from shell or system"); + } + } + private void assertCanWrite(boolean reverseMode) { if (isDataLoaderInstallation()) { throw new IllegalStateException( @@ -780,15 +800,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertPreparedAndNotSealedLocked("assertCanWrite"); } if (reverseMode) { - switch (Binder.getCallingUid()) { - case android.os.Process.SHELL_UID: - case android.os.Process.ROOT_UID: - case android.os.Process.SYSTEM_UID: - break; - default: - throw new SecurityException( - "Reverse mode only supported from shell or system"); - } + assertShellOrSystemCalling("Reverse mode"); } } @@ -1025,13 +1037,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mHandler.obtainMessage(MSG_COMMIT).sendToTarget(); } - private class FileSystemConnector extends IPackageInstallerSessionFileSystemConnector.Stub { + private final class FileSystemConnector extends + IPackageInstallerSessionFileSystemConnector.Stub { + final Set<String> mAddedFiles; + + FileSystemConnector(List<InstallationFile> addedFiles) { + mAddedFiles = addedFiles.stream().map(file -> file.getName()).collect( + Collectors.toSet()); + } + @Override public void writeData(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) { if (incomingFd == null) { throw new IllegalArgumentException("incomingFd can't be null"); } + if (!mAddedFiles.contains(name)) { + throw new SecurityException("File name is not in the list of added files."); + } try { doWriteInternal(name, offsetBytes, lengthBytes, incomingFd); } catch (IOException e) { @@ -2467,8 +2490,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - FileSystemConnector connector = new FileSystemConnector(); - List<InstallationFile> addedFiles = mFiles.stream().filter( file -> sAddedFilter.accept(new File(file.name))).map( file -> new InstallationFile( @@ -2480,6 +2501,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect( Collectors.toList()); + final FileSystemConnector connector = new FileSystemConnector(addedFiles); + DataLoaderManager dataLoaderManager = mContext.getSystemService(DataLoaderManager.class); if (dataLoaderManager == null) { throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, @@ -2515,11 +2538,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } }; - final DataLoaderParams params = this.params.dataLoaderParams; - final FileSystemControlParcel control = new FileSystemControlParcel(); control.callback = connector; + final DataLoaderParams params = this.params.dataLoaderParams; + Bundle dataLoaderParams = new Bundle(); dataLoaderParams.putParcelable("componentName", params.getComponentName()); dataLoaderParams.putParcelable("control", control); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 10e2780863d8..5adab378bb73 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -34,7 +34,6 @@ import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; -import android.content.pm.DataLoaderParams; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstaller; @@ -137,10 +136,6 @@ class PackageManagerShellCommand extends ShellCommand { private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/"; private static final int DEFAULT_WAIT_MS = 60 * 1000; - private static final String DATA_LOADER_PACKAGE = "android"; - private static final String DATA_LOADER_CLASS = - "com.android.server.pm.PackageManagerShellCommandDataLoader"; - final IPackageManager mInterface; final IPermissionManager mPermissionManager; final private WeakHashMap<String, Resources> mResourceCache = @@ -164,7 +159,7 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); try { - switch(cmd) { + switch (cmd) { case "path": return runPath(); case "dump": @@ -1163,9 +1158,8 @@ class PackageManagerShellCommand extends ShellCommand { private int runStreamingInstall() throws RemoteException { final InstallParams params = makeInstallParams(); if (params.sessionParams.dataLoaderParams == null) { - final DataLoaderParams dataLoaderParams = DataLoaderParams.forStreaming( - new ComponentName(DATA_LOADER_PACKAGE, DATA_LOADER_CLASS), ""); - params.sessionParams.setDataLoaderParams(dataLoaderParams); + params.sessionParams.setDataLoaderParams( + PackageManagerShellCommandDataLoader.getDataLoaderParams(this)); } return doRunInstall(params); } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java index 1ee9ab8927bb..a814cb8942e2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java @@ -17,18 +17,22 @@ package com.android.server.pm; import android.annotation.NonNull; +import android.content.ComponentName; import android.content.pm.DataLoaderParams; import android.content.pm.InstallationFile; import android.os.ParcelFileDescriptor; +import android.os.ShellCommand; import android.service.dataloader.DataLoaderService; import android.text.TextUtils; import android.util.Slog; +import android.util.SparseArray; import libcore.io.IoUtils; -import java.io.File; import java.io.IOException; +import java.lang.ref.WeakReference; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.Collection; /** @@ -37,41 +41,109 @@ import java.util.Collection; public class PackageManagerShellCommandDataLoader extends DataLoaderService { public static final String TAG = "PackageManagerShellCommandDataLoader"; + private static final String PACKAGE = "android"; + private static final String CLASS = PackageManagerShellCommandDataLoader.class.getName(); + + static final SecureRandom sRandom = new SecureRandom(); + static final SparseArray<WeakReference<ShellCommand>> sShellCommands = new SparseArray<>(); + + private static final char ARGS_DELIM = '&'; + private static final String SHELL_COMMAND_ID_PREFIX = "shellCommandId="; + private static final int INVALID_SHELL_COMMAND_ID = -1; + private static final int TOO_MANY_PENDING_SHELL_COMMANDS = 10; + + private static final String STDIN_PATH = "-"; + + static DataLoaderParams getDataLoaderParams(ShellCommand shellCommand) { + int commandId; + synchronized (sShellCommands) { + // Clean up old references. + for (int i = sShellCommands.size() - 1; i >= 0; i--) { + WeakReference<ShellCommand> oldRef = sShellCommands.valueAt(i); + if (oldRef.get() == null) { + sShellCommands.removeAt(i); + } + } + + // Sanity check. + if (sShellCommands.size() > TOO_MANY_PENDING_SHELL_COMMANDS) { + Slog.e(TAG, "Too many pending shell commands: " + sShellCommands.size()); + } + + // Generate new id and put ref to the array. + do { + commandId = sRandom.nextInt(Integer.MAX_VALUE - 1) + 1; + } while (sShellCommands.contains(commandId)); + + sShellCommands.put(commandId, new WeakReference<>(shellCommand)); + } + + final String args = SHELL_COMMAND_ID_PREFIX + commandId; + return DataLoaderParams.forStreaming(new ComponentName(PACKAGE, CLASS), args); + } + + private static int extractShellCommandId(String args) { + int sessionIdIdx = args.indexOf(SHELL_COMMAND_ID_PREFIX); + if (sessionIdIdx < 0) { + Slog.e(TAG, "Missing shell command id param."); + return INVALID_SHELL_COMMAND_ID; + } + sessionIdIdx += SHELL_COMMAND_ID_PREFIX.length(); + int delimIdx = args.indexOf(ARGS_DELIM, sessionIdIdx); + try { + if (delimIdx < 0) { + return Integer.parseInt(args.substring(sessionIdIdx)); + } else { + return Integer.parseInt(args.substring(sessionIdIdx, delimIdx)); + } + } catch (NumberFormatException e) { + Slog.e(TAG, "Incorrect shell command id format.", e); + return INVALID_SHELL_COMMAND_ID; + } + } + static class DataLoader implements DataLoaderService.DataLoader { - private ParcelFileDescriptor mInFd = null; + private DataLoaderParams mParams = null; private FileSystemConnector mConnector = null; - private static final String STDIN_PATH = "-"; - @Override public boolean onCreate(@NonNull DataLoaderParams dataLoaderParams, @NonNull FileSystemConnector connector) { + mParams = dataLoaderParams; mConnector = connector; return true; } + @Override public boolean onPrepareImage(Collection<InstallationFile> addedFiles, Collection<String> removedFiles) { + final int commandId = extractShellCommandId(mParams.getArguments()); + if (commandId == INVALID_SHELL_COMMAND_ID) { + return false; + } + + final WeakReference<ShellCommand> shellCommandRef; + synchronized (sShellCommands) { + shellCommandRef = sShellCommands.get(commandId, null); + } + final ShellCommand shellCommand = + shellCommandRef != null ? shellCommandRef.get() : null; + if (shellCommand == null) { + Slog.e(TAG, "Missing shell command."); + return false; + } try { for (InstallationFile fileInfo : addedFiles) { String filePath = new String(fileInfo.getMetadata(), StandardCharsets.UTF_8); if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) { - // TODO(b/146080380): add support for STDIN installations. - if (mInFd == null) { - Slog.e(TAG, "Invalid stdin file descriptor."); - return false; - } - ParcelFileDescriptor inFd = ParcelFileDescriptor.dup( - mInFd.getFileDescriptor()); + final ParcelFileDescriptor inFd = ParcelFileDescriptor.dup( + shellCommand.getInFileDescriptor()); mConnector.writeData(fileInfo.getName(), 0, fileInfo.getSize(), inFd); } else { - File localFile = new File(filePath); ParcelFileDescriptor incomingFd = null; try { - // TODO(b/146080380): open files via callback into shell command. - incomingFd = ParcelFileDescriptor.open(localFile, - ParcelFileDescriptor.MODE_READ_ONLY); - mConnector.writeData(fileInfo.getName(), 0, localFile.length(), + incomingFd = shellCommand.openFileForSystem(filePath, "r"); + mConnector.writeData(fileInfo.getName(), 0, incomingFd.getStatSize(), incomingFd); } finally { IoUtils.closeQuietly(incomingFd); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 956962ef9f29..ea83adba4d8a 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5192,7 +5192,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Intent dock = createHomeDockIntent(); if (dock != null) { int result = ActivityTaskManager.getService() - .startActivityAsUser(null, null, dock, + .startActivityAsUser(null, mContext.getBasePackageName(), dock, dock.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, ActivityManager.START_FLAG_ONLY_IF_NEEDED, @@ -5203,7 +5203,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } int result = ActivityTaskManager.getService() - .startActivityAsUser(null, null, mHomeIntent, + .startActivityAsUser(null, mContext.getBasePackageName(), mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), null, null, 0, ActivityManager.START_FLAG_ONLY_IF_NEEDED, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e281712f743a..26d76a8d6e28 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -243,9 +243,9 @@ import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.PauseActivityItem; import android.app.servertransaction.PipModeChangeItem; import android.app.servertransaction.ResumeActivityItem; +import android.app.servertransaction.StartActivityItem; import android.app.servertransaction.StopActivityItem; import android.app.servertransaction.TopResumedActivityChangeItem; -import android.app.servertransaction.WindowVisibilityItem; import android.app.usage.UsageEvents.Event; import android.content.ComponentName; import android.content.Intent; @@ -4497,7 +4497,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A sleeping = false; app.postPendingUiCleanMsg(true); if (reportToClient) { - makeClientVisible(); + mClientVisibilityDeferred = false; + makeActiveIfNeeded(starting); } else { mClientVisibilityDeferred = true; } @@ -4511,23 +4512,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A handleAlreadyVisible(); } - /** Send visibility change message to the client and pause if needed. */ - void makeClientVisible() { - mClientVisibilityDeferred = false; - try { - mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - WindowVisibilityItem.obtain(true /* showWindow */)); - makeActiveIfNeeded(null /* activeActivity*/); - if (isState(STOPPING, STOPPED)) { - // Set state to STARTED in order to have consistent state with client while - // making an non-active activity visible from stopped. - setState(STARTED, "makeClientVisible"); - } - } catch (Exception e) { - Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e); - } - } - void makeInvisible() { if (!mVisibleRequested) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this); @@ -4556,14 +4540,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A switch (getState()) { case STOPPING: case STOPPED: - if (attachedToProcess()) { - if (DEBUG_VISIBILITY) { - Slog.v(TAG_VISIBILITY, "Scheduling invisibility: " + this); - } - mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), - appToken, WindowVisibilityItem.obtain(false /* showWindow */)); - } - // Reset the flag indicating that an app can enter picture-in-picture once the // activity is hidden supportsEnterPipOnTaskSwitch = false; @@ -4595,17 +4571,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean makeActiveIfNeeded(ActivityRecord activeActivity) { if (shouldResumeActivity(activeActivity)) { if (DEBUG_VISIBILITY) { - Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this); + Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this); } return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */, null /* options */); } else if (shouldPauseActivity(activeActivity)) { if (DEBUG_VISIBILITY) { - Slog.v("TAG_VISIBILITY", "Pause visible activity, " + this); + Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this); } // An activity must be in the {@link PAUSING} state for the system to validate // the move to {@link PAUSED}. - setState(PAUSING, "makeVisibleIfNeeded"); + setState(PAUSING, "makeActiveIfNeeded"); try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, PauseActivityItem.obtain(finishing, false /* userLeaving */, @@ -4613,6 +4589,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } catch (Exception e) { Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); } + } else if (shouldStartActivity()) { + if (DEBUG_VISIBILITY) { + Slog.v(TAG_VISIBILITY, "Start visible activity, " + this); + } + setState(STARTED, "makeActiveIfNeeded"); + try { + mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, + StartActivityItem.obtain()); + } catch (Exception e) { + Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e); + } } return false; } @@ -4656,6 +4643,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** + * Check if activity should be moved to STARTED state. + * NOTE: This will not check if activity should be made paused or resumed first, so it must only + * be called after checking with {@link #shouldResumeActivity(ActivityRecord)} + * and {@link #shouldPauseActivity(ActivityRecord)}. + */ + private boolean shouldStartActivity() { + return mVisibleRequested && isState(STOPPED); + } + + /** * Check if activity is eligible to be made active (resumed of paused). The activity: * - should be paused, stopped or stopping * - should not be the currently active one or launching behind other tasks @@ -4890,16 +4887,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } setState(STOPPING, "stopIfPossible"); if (DEBUG_VISIBILITY) { - Slog.v(TAG_VISIBILITY, "Stopping visibleRequested=" - + mVisibleRequested + " for " + this); - } - if (!mVisibleRequested) { - setVisibility(false); + Slog.v(TAG_VISIBILITY, "Stopping:" + this); } EventLogTags.writeWmStopActivity( mUserId, System.identityHashCode(this), shortComponentName); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - StopActivityItem.obtain(mVisibleRequested, configChangeFlags)); + StopActivityItem.obtain(configChangeFlags)); + if (stack.shouldSleepOrShutDownActivities()) { setSleeping(true); } @@ -7201,7 +7195,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // {@link ActivityTaskManagerService.activityStopped}). try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, - StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */)); + StopActivityItem.obtain(0 /* configChanges */)); } catch (RemoteException e) { Slog.w(TAG, "Exception thrown during restart " + this, e); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 76c0e4eeecae..474c5c960eb0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -7203,7 +7203,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER); if (mController != null) { final long token = proto.start(CONTROLLER); - proto.write(CONTROLLER, mController.toString()); + proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, + mController.toString()); proto.write(IS_A_MONKEY, mControllerIsAMonkey); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index 55f5e289377e..c09834f2b3c1 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -79,12 +79,13 @@ class EnsureActivitiesVisibleHelper { final PooledConsumer f = PooledLambda.obtainConsumer( EnsureActivitiesVisibleHelper::setActivityVisibilityState, this, - PooledLambda.__(ActivityRecord.class), resumeTopActivity); + PooledLambda.__(ActivityRecord.class), starting, resumeTopActivity); mContiner.forAllActivities(f); f.recycle(); } - private void setActivityVisibilityState(ActivityRecord r, final boolean resumeTopActivity) { + private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting, + final boolean resumeTopActivity) { final boolean isTop = r == mTop; if (mAboveTop && !isTop) { return; @@ -129,7 +130,8 @@ class EnsureActivitiesVisibleHelper { "Skipping: already visible at " + r); if (r.mClientVisibilityDeferred && mNotifyClients) { - r.makeClientVisible(); + r.makeActiveIfNeeded(r.mClientVisibilityDeferred ? null : starting); + r.mClientVisibilityDeferred = false; } r.handleAlreadyVisible(); diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 7b40f609aaf1..a13383d3991e 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -70,6 +70,9 @@ class InsetsSourceProvider { */ private boolean mServerVisible; + private boolean mSeamlessRotating; + private long mFinishSeamlessRotateFrameNumber = -1; + private final boolean mControllable; InsetsSourceProvider(InsetsSource source, InsetsStateController stateController, @@ -170,7 +173,9 @@ class InsetsSourceProvider { updateSourceFrame(); if (mControl != null) { final Rect frame = mWin.getWindowFrames().mFrame; - if (mControl.setSurfacePosition(frame.left, frame.top)) { + if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) { + // The leash has been stale, we need to create a new one for the client. + updateControlForTarget(mControlTarget, true /* force */); mStateController.notifyControlChanged(mControlTarget); } } @@ -189,6 +194,11 @@ class InsetsSourceProvider { } void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) { + if (mSeamlessRotating) { + // We are un-rotating the window against the display rotation. We don't want the target + // to control the window for now. + return; + } if (mWin == null) { mControlTarget = target; return; @@ -203,13 +213,41 @@ class InsetsSourceProvider { } mAdapter = new ControlAdapter(); setClientVisible(InsetsState.getDefaultVisibility(mSource.getType())); - mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter, - !mClientVisible /* hidden */); + final Transaction t = mDisplayContent.getPendingTransaction(); + mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */); + final SurfaceControl leash = mAdapter.mCapturedLeash; + final long frameNumber = mFinishSeamlessRotateFrameNumber; + mFinishSeamlessRotateFrameNumber = -1; + if (frameNumber >= 0 && mWin.mHasSurface && leash != null) { + // We just finished the seamless rotation. We don't want to change the position or the + // window crop of the surface controls (including the leash) until the client finishes + // drawing the new frame of the new orientation. Although we cannot defer the reparent + // operation, it is fine, because reparent won't cause any visual effect. + final SurfaceControl barrier = mWin.mWinAnimator.mSurfaceController.mSurfaceControl; + t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber); + t.deferTransactionUntil(leash, barrier, frameNumber); + } mControlTarget = target; - mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash, + mControl = new InsetsSourceControl(mSource.getType(), leash, new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top)); } + void startSeamlessRotation() { + if (!mSeamlessRotating) { + mSeamlessRotating = true; + + // This will revoke the leash and clear the control target. + mWin.cancelAnimation(); + } + } + + void finishSeamlessRotation(boolean timeout) { + if (mSeamlessRotating) { + mSeamlessRotating = false; + mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber(); + } + } + boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) { if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) { return false; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 720493f4a466..b2234d17984e 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -203,7 +203,7 @@ class InsetsStateController { if (target == previous) { return; } - final InsetsSourceProvider provider = getSourceProvider(type); + final InsetsSourceProvider provider = mProviders.get(type); if (provider == null) { return; } @@ -211,6 +211,7 @@ class InsetsStateController { return; } provider.updateControlForTarget(target, false /* force */); + target = provider.getControlTarget(); if (previous != null) { removeFromControlMaps(previous, type, false /* fake */); mPendingControlChanged.add(previous); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 976730ec4337..5286a6e32958 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -322,12 +322,16 @@ class SurfaceAnimator { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash"); final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash() .setParent(mAnimatable.getAnimationLeashParent()) + .setHidden(hidden) .setName(surface + " - animation-leash"); final SurfaceControl leash = builder.build(); t.setWindowCrop(leash, width, height); + + // TODO: rely on builder.setHidden(hidden) instead of show and setAlpha when b/138459974 is + // fixed. t.show(leash); - // TODO: change this back to use show instead of alpha when b/138459974 is fixed. t.setAlpha(leash, hidden ? 0 : 1); + t.reparent(surface, leash); return leash; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 96bc8e963b38..ba40f623ea66 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -688,6 +688,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } if (mForceSeamlesslyRotate || requested) { + if (mControllableInsetProvider != null) { + mControllableInsetProvider.startSeamlessRotation(); + } mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo()); mPendingSeamlessRotate.unrotate(transaction, this); getDisplayContent().getDisplayRotation().markForSeamlessRotation(this, @@ -702,6 +705,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mPendingSeamlessRotate = null; getDisplayContent().getDisplayRotation().markForSeamlessRotation(this, false /* seamlesslyRotated */); + if (mControllableInsetProvider != null) { + mControllableInsetProvider.finishSeamlessRotation(timeout); + } } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 2e8e5e7b706a..c0891d739788 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1757,6 +1757,12 @@ static jboolean nativeCanDispatchToDisplay(JNIEnv* env, jclass /* clazz */, jlon return im->getInputManager()->getReader()->canDispatchToDisplay(deviceId, displayId); } +static void nativeNotifyPortAssociationsChanged(JNIEnv* env, jclass /* clazz */, jlong ptr) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + im->getInputManager()->getReader()->requestRefreshConfiguration( + InputReaderConfiguration::CHANGE_DISPLAY_INFO); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -1842,6 +1848,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeSetCustomPointerIcon }, { "nativeCanDispatchToDisplay", "(JII)Z", (void*) nativeCanDispatchToDisplay }, + { "nativeNotifyPortAssociationsChanged", "(J)V", + (void*) nativeNotifyPortAssociationsChanged }, }; #define FIND_CLASS(var, className) \ diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java index d4182f3d31e2..5a1ad8655ab0 100644 --- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java @@ -672,6 +672,30 @@ public final class AdbDebuggingManagerTest { connectionTime2, mKeyStore.getLastConnectionTime(TEST_KEY_2)); } + @Test + public void testClearAuthorizationsBeforeAdbEnabled() throws Exception { + // The adb key store is not instantiated until adb is enabled; however if the user attempts + // to clear the adb authorizations when adb is disabled after a boot a NullPointerException + // was thrown as deleteKeyStore is invoked against the key store. This test ensures the + // key store can be successfully cleared when adb is disabled. + mHandler = mManager.new AdbDebuggingHandler(FgThread.get().getLooper()); + + clearKeyStore(); + } + + @Test + public void testClearAuthorizationsDeletesKeyFiles() throws Exception { + mAdbKeyFile.createNewFile(); + mAdbKeyXmlFile.createNewFile(); + + clearKeyStore(); + + assertFalse("The adb key file should have been deleted after revocation of the grants", + mAdbKeyFile.exists()); + assertFalse("The adb xml key file should have been deleted after revocation of the grants", + mAdbKeyXmlFile.exists()); + } + /** * Runs an adb test with the provided configuration. * diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index ebca240819e8..25d077823a3f 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -78,7 +78,7 @@ public class DisplayModeDirectorTest { int displayId = 0; // With no votes present, DisplayModeDirector should allow any refresh rate. - assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/60, + assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/60, new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY)), createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs( displayId)); @@ -105,7 +105,7 @@ public class DisplayModeDirectorTest { director.injectVotesByDisplay(votesByDisplay); assertEquals( new DisplayModeDirector.DesiredDisplayModeSpecs( - /*defaultModeId=*/minFps + i, + /*baseModeId=*/minFps + i, new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i)), director.getDesiredDisplayModeSpecs(displayId)); } @@ -126,7 +126,7 @@ public class DisplayModeDirectorTest { votes.put(DisplayModeDirector.Vote.MIN_PRIORITY, DisplayModeDirector.Vote.forRefreshRates(70, 80)); director.injectVotesByDisplay(votesByDisplay); - assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*defaultModeId=*/70, + assertEquals(new DisplayModeDirector.DesiredDisplayModeSpecs(/*baseModeId=*/70, new DisplayModeDirector.RefreshRateRange(70, 80)), director.getDesiredDisplayModeSpecs(displayId)); } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 28e6830515f0..c7dbad83e384 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -1273,11 +1273,11 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); @@ -1301,9 +1301,9 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addValues(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0); - stats.addValues(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 73b2f6b2dc37..a3e94599cad3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -521,11 +521,12 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test - public void testShouldPauseWhenMakeClientVisible() { + public void testShouldStartWhenMakeClientActive() { ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); topActivity.setOccludesParent(false); mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); - mActivity.makeClientVisible(); + mActivity.setVisibility(true); + mActivity.makeActiveIfNeeded(null /* activeActivity */); assertEquals(STARTED, mActivity.getState()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java index 574517a00f6f..71390dbbe4a3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java @@ -40,7 +40,7 @@ import org.mockito.MockitoAnnotations; * Tests for the {@link ActivityStack} class. * * Build/Install/Run: - * atest FrameworksServicesTests:AnimatingActivityRegistryTest + * atest WmTests:AnimatingActivityRegistryTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 1311889d5605..f6213bd94ddd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -42,7 +42,7 @@ import org.junit.runner.RunWith; /** * Build/Install/Run: - * atest FrameworksServicesTests:AppTransitionControllerTest + * atest WmTests:AppTransitionControllerTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java index 0ad0f95f64c1..1dda535cfb95 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -60,7 +60,7 @@ import org.junit.runner.RunWith; * appropriately. * * Build/Install/Run: - * atest FrameworksServicesTests:BoundsAnimationControllerTests + * atest WmTests:BoundsAnimationControllerTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index 0aa6961d20b3..e8f7849ef96a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -40,7 +40,7 @@ import org.junit.runner.RunWith; /** * Build/Install/Run: - * atest FrameworksServicesTests:DimmerTests + * atest WmTests:DimmerTests */ @Presubmit @RunWith(WindowTestRunner.class) diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 112479b3b9a0..1a575962b961 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -61,7 +61,7 @@ import org.mockito.MockitoAnnotations; /** * Build/Install/Run: - * atest FrameworksServicesTests:RemoteAnimationControllerTest + * atest WmTests:RemoteAnimationControllerTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index e0112809b22b..bac2bcae30de 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -60,7 +60,7 @@ import java.util.concurrent.CountDownLatch; * Test class for {@link SurfaceAnimationRunner}. * * Build/Install/Run: - * atest FrameworksServicesTests:SurfaceAnimationRunnerTest + * atest WmTests:SurfaceAnimationRunnerTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java index 0274b7d788ff..e71247173930 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java @@ -38,7 +38,7 @@ import org.mockito.MockitoAnnotations; * Test class for {@link TaskSnapshotCache}. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskSnapshotCacheTest + * atest WmTests:TaskSnapshotCacheTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java index 8fe0cdbbd872..2e485dd1bec3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -53,7 +53,7 @@ import org.mockito.Mockito; * Test class for {@link TaskSnapshotController}. * * Build/Install/Run: - * * atest FrameworksServicesTests:TaskSnapshotControllerTest + * * atest WmTests:TaskSnapshotControllerTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index b5a5790a3a8c..eb8eb98fd484 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -47,7 +47,7 @@ import java.util.function.Predicate; * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader} * * Build/Install/Run: - * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest + * atest WmTests:TaskSnapshotPersisterLoaderTest */ @MediumTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index 2d418ffffcf6..ed87f3a0c604 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -53,7 +53,7 @@ import org.junit.runner.RunWith; * Test class for {@link TaskSnapshotSurface}. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskSnapshotSurfaceTest + * atest WmTests:TaskSnapshotSurfaceTest */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java index 8936aadd5f92..3c0dd1e897f5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java @@ -39,7 +39,7 @@ import java.util.function.Consumer; * Tests for {@link WindowContainer#forAllWindows} and various implementations. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowContainerTraversalTests + * atest WmTests:WindowContainerTraversalTests */ @SmallTest @Presubmit diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index e081ca374808..7e248f854dcf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -92,7 +92,7 @@ import java.util.List; * Tests for the {@link WindowState} class. * * Build/Install/Run: - * atest FrameworksServicesTests:WindowStateTests + * atest WmTests:WindowStateTests */ @SmallTest @Presubmit diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java index 8b8c86be7b0a..ea641f866b98 100644 --- a/telecomm/java/android/telecom/AudioState.java +++ b/telecomm/java/android/telecom/AudioState.java @@ -19,7 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 86ad795b9ea2..a8852a849604 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -20,12 +20,11 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.ParcelFileDescriptor; import com.android.internal.telecom.IVideoProvider; diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index a5d25e2ce4bb..fb6f99405759 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -17,7 +17,7 @@ package android.telecom; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -41,8 +41,8 @@ import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder; - import com.android.internal.annotations.VisibleForTesting; + import java.util.Locale; diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 8808339b1664..f205ec64f49b 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -21,9 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Notification; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.hardware.camera2.CameraManager; import android.net.Uri; diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 7d4ee7686512..4f6a9d6450f8 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.Uri; import android.os.Build; diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index a234bb0af8fa..be4e2f4c65e1 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -16,22 +16,21 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.telecom.Call.Details.CallDirection; +import com.android.internal.telecom.IVideoProvider; + import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.android.internal.telecom.IVideoProvider; - /** * Information about a call that is used between InCallService and Telecom. * @hide diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index 61a639a1a235..a427ed612b31 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -17,8 +17,8 @@ package android.telecom; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index eb568e04ebf3..e1bcb5fbdf00 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -18,7 +18,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Build; import android.os.Parcel; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index af3c55abf00c..9cf4803966c6 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -26,7 +26,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index 4a1aa0a8ffa4..109e7f829f2e 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Handler; diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java index 64e6ca3416e3..4197f3cfc6c3 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -19,7 +19,6 @@ package android.telecom; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java index 5fb4e90b9666..22cbdaa0f133 100644 --- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Build; import android.telephony.Rlog; diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java index 19f52b0ef429..3aa8bbf607d1 100644 --- a/telephony/common/com/android/internal/telephony/SmsConstants.java +++ b/telephony/common/com/android/internal/telephony/SmsConstants.java @@ -15,7 +15,7 @@ */ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * SMS Constants and must be the same as the corresponding diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java index 6c357ccdd03d..8450a9018634 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -19,7 +19,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java index c7a985160730..2382f657c9ee 100644 --- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java +++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java index abd4065c754a..d0fb51180c1d 100644 --- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java +++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 5baddef99efa..4d5713259a0f 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -24,7 +24,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.PersistableBundle; diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 2ecdfce92825..49f425acead6 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -18,7 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 15c91752badf..bc4655069dba 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -18,7 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 5b12aed3e51b..66feb7bac25d 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -2044,4 +2044,27 @@ public class ServiceState implements Parcelable { public boolean isIwlanPreferred() { return mIsIwlanPreferred; } + /** + * @return {@code true}Returns True whenever the modem is searching for service. + * To check both CS and PS domain + */ + + public boolean isSearching() { + NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + if (psRegState != null && psRegState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) { + return true; + } + + NetworkRegistrationInfo csRegState = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + if (csRegState != null && csRegState.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING) { + return true; + } + return false; + } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 88501a726ee1..321753bc1776 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -983,6 +983,23 @@ public class SubscriptionManager { */ public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { if (listener == null) return; + addOnSubscriptionsChangedListener(listener.mExecutor, listener); + } + + /** + * Register for changes to the list of active {@link SubscriptionInfo} records or to the + * individual records themselves. When a change occurs the onSubscriptionsChanged method of + * the listener will be invoked immediately if there has been a notification. The + * onSubscriptionChanged method will also be triggered once initially when calling this + * function. + * + * @param listener an instance of {@link OnSubscriptionsChangedListener} with + * onSubscriptionsChanged overridden. + * @param executor the executor that will execute callbacks. + */ + public void addOnSubscriptionsChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnSubscriptionsChangedListener listener) { String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>"; if (DBG) { logd("register OnSubscriptionsChangedListener pkgName=" + pkgName @@ -994,7 +1011,7 @@ public class SubscriptionManager { mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { telephonyRegistryManager.addOnSubscriptionsChangedListener(listener, - listener.mExecutor); + executor); } } diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index c16a0f446651..33d77d288e15 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -64,15 +64,15 @@ public class NetworkStatsTest { @Test public void testFindIndex() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12); assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, @@ -94,21 +94,21 @@ public class NetworkStatsTest { @Test public void testFindIndexHinted() { final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12); // verify that we correctly find across regardless of hinting @@ -143,27 +143,27 @@ public class NetworkStatsTest { assertEquals(0, stats.size()); assertEquals(4, stats.internalSize()); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5); assertEquals(4, stats.size()); assertEquals(4, stats.internalSize()); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11); assertEquals(9, stats.size()); @@ -193,8 +193,8 @@ public class NetworkStatsTest { public void testCombineExisting() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 10); - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); + stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); + stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1); @@ -215,12 +215,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalData() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats result = after.subtract(before); @@ -234,12 +234,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); final NetworkStats result = after.subtract(before); @@ -253,13 +253,13 @@ public class NetworkStatsTest { @Test public void testSubtractNewRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) + .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); final NetworkStats result = after.subtract(before); @@ -275,11 +275,11 @@ public class NetworkStatsTest { @Test public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); + .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); final NetworkStats after = new NetworkStats(TEST_START, 1) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); final NetworkStats result = after.subtract(before); @@ -293,40 +293,40 @@ public class NetworkStatsTest { @Test public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); assertEquals(384L, iface.getTotalBytes()); final NetworkStats uidSet = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidSet.getTotalBytes()); final NetworkStats uidTag = new NetworkStats(TEST_START, 6) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); final NetworkStats uidMetered = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidMetered.getTotalBytes()); final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidRoaming.getTotalBytes()); } @@ -343,11 +343,11 @@ public class NetworkStatsTest { @Test public void testGroupedByIfaceAll() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -361,19 +361,19 @@ public class NetworkStatsTest { @Test public void testGroupedByIface() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -390,19 +390,19 @@ public class NetworkStatsTest { @Test public void testAddAllValues() { final NetworkStats first = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); final NetworkStats second = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); first.combineAllValues(second); @@ -421,19 +421,19 @@ public class NetworkStatsTest { @Test public void testGetTotal() { final NetworkStats stats = new NetworkStats(TEST_START, 7) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L); assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L); @@ -459,7 +459,7 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Test 1 item stats. - before.addValues(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); + before.addEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); after = before.clone(); after.removeUids(new int[0]); assertEquals(1, after.size()); @@ -469,12 +469,12 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Append remaining test items. - before.addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); + before.addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) + .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) + .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); assertEquals(7, before.size()); // Test remove with empty uid list. @@ -505,12 +505,12 @@ public class NetworkStatsTest { @Test public void testClone() throws Exception { final NetworkStats original = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // make clone and mutate original final NetworkStats clone = original.clone(); - original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); + original.addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); assertEquals(3, original.size()); assertEquals(2, clone.size()); @@ -523,8 +523,8 @@ public class NetworkStatsTest { public void testAddWhenEmpty() throws Exception { final NetworkStats red = new NetworkStats(TEST_START, -1); final NetworkStats blue = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // We're mostly checking that we don't crash red.combineAllValues(blue); @@ -537,39 +537,39 @@ public class NetworkStatsTest { final String underlyingIface = "wlan0"; final int testTag1 = 8888; NetworkStats delta = new NetworkStats(TEST_START, 17) - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L) - .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L) - // VPN package also uses some traffic through unprotected network. - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L) - .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - // Tag entries - .addValues(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L) - .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L) - // Irrelevant entries - .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L) - // Underlying Iface entries - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L) - .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */, - 299L /* smaller than sum(tun0) */, 0L) - .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); - - delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface}); + .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L) + .addEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + .addEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L) + .addEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L) + // VPN package also uses some traffic through unprotected network. + .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L) + .addEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + // Tag entries + .addEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L) + .addEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L) + // Irrelevant entries + .addEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L) + // Underlying Iface entries + .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L) + .addEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */, + 299L /* smaller than sum(tun0) */, 0L) + .addEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); + + delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. @@ -634,21 +634,21 @@ public class NetworkStatsTest { final String tunIface = "tun0"; final String underlyingIface = "wlan0"; NetworkStats delta = new NetworkStats(TEST_START, 9) - // 2 different apps sent/receive data via tun0. - .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L) - .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L) - // VPN package resends data through the tunnel (with exaggerated overhead) - .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L) - // 1 app already has some traffic on the underlying interface, the other doesn't yet - .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L) - // Traffic through the underlying interface via the vpn app. - // This test should redistribute this data correctly. - .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); + // 2 different apps sent/receive data via tun0. + .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L) + .addEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L) + // VPN package resends data through the tunnel (with exaggerated overhead) + .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L) + // 1 app already has some traffic on the underlying interface, the other doesn't yet + .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L) + // Traffic through the underlying interface via the vpn app. + // This test should redistribute this data correctly. + .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(9, delta.size()); @@ -697,9 +697,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL); assertEquals(3, stats.size()); @@ -724,9 +724,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(testUid, INTERFACES_ALL, TAG_ALL); assertEquals(2, stats.size()); @@ -755,10 +755,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3) - .addValues(entry4); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3) + .addEntry(entry4); stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL); assertEquals(3, stats.size()); @@ -778,8 +778,8 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2); + .addEntry(entry1) + .addEntry(entry2); stats.filter(UID_ALL, new String[] { }, TAG_ALL); assertEquals(0, stats.size()); @@ -802,9 +802,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, testTag); assertEquals(2, stats.size()); @@ -831,10 +831,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3) - .addValues(entry4); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3) + .addEntry(entry4); stats.filterDebugEntries(); @@ -891,14 +891,14 @@ public class NetworkStatsTest { 0 /* operations */); final NetworkStats statsXt = new NetworkStats(TEST_START, 3) - .addValues(appEntry) - .addValues(xtRootUidEntry) - .addValues(otherEntry); + .addEntry(appEntry) + .addEntry(xtRootUidEntry) + .addEntry(otherEntry); final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3) - .addValues(appEntry) - .addValues(ebpfRootUidEntry) - .addValues(otherEntry); + .addEntry(appEntry) + .addEntry(ebpfRootUidEntry) + .addEntry(otherEntry); statsXt.apply464xlatAdjustments(stackedIface, false); statsEbpf.apply464xlatAdjustments(stackedIface, true); @@ -945,8 +945,8 @@ public class NetworkStatsTest { 0 /* operations */); NetworkStats stats = new NetworkStats(TEST_START, 2) - .addValues(firstEntry) - .addValues(secondEntry); + .addEntry(firstEntry) + .addEntry(secondEntry); // Empty map: no adjustment stats.apply464xlatAdjustments(new ArrayMap<>(), false); diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java index c0f9dc14869f..f0e5774a5dea 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java @@ -326,14 +326,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -359,14 +359,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -391,14 +391,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -424,14 +424,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 4d42a612030d..6de068e48a38 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -298,11 +298,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); mService.setUidForeground(UID_RED, false); mService.incrementOperationCount(UID_RED, 0xFAAD, 4); mService.setUidForeground(UID_RED, true); @@ -407,9 +407,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 10); forcePollAndWaitForIdle(); @@ -429,9 +429,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -443,10 +443,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -480,10 +480,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) + .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -501,10 +501,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) + .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); final Intent intent = new Intent(ACTION_UID_REMOVED); intent.putExtra(EXTRA_UID, UID_BLUE); mServiceContext.sendBroadcast(intent); @@ -536,8 +536,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 5); forcePollAndWaitForIdle(); @@ -552,8 +552,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -564,10 +564,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 5); forcePollAndWaitForIdle(); @@ -591,9 +591,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -608,9 +608,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); forcePollAndWaitForIdle(); // first verify entire history present @@ -654,9 +654,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3)); + .addEntry(entry1) + .addEntry(entry2) + .addEntry(entry3)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL); @@ -704,11 +704,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { .thenReturn(augmentedIfaceFilter); when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL))) .thenReturn(new NetworkStats(getElapsedRealtime(), 1) - .addValues(uidStats)); + .addEntry(uidStats)); when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)) .thenReturn(new NetworkStats(getElapsedRealtime(), 2) - .addValues(tetheredStats1) - .addValues(tetheredStats2)); + .addEntry(tetheredStats1) + .addEntry(tetheredStats2)); NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); @@ -745,8 +745,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -760,10 +760,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) + .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); mService.setUidForeground(UID_RED, true); mService.incrementOperationCount(UID_RED, 0xFAAD, 1); @@ -804,9 +804,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer. // We layer them on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); @@ -843,9 +843,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it // on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); forcePollAndWaitForIdle(); @@ -885,10 +885,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // Traffic for UID_RED. final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); + .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); // All tethering traffic, both hardware and software. final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, + .addEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); expectNetworkStatsSummary(ifaceStats, tetherStatsHardware); |