diff options
93 files changed, 2884 insertions, 1027 deletions
diff --git a/Android.bp b/Android.bp index 36c2fa8762a4..23168232b7a3 100644 --- a/Android.bp +++ b/Android.bp @@ -295,6 +295,7 @@ filegroup { srcs: [ // Java/AIDL sources under frameworks/base ":framework-blobstore-sources", + ":framework-connectivity-sources", // framework-connectivity is not yet a module ":framework-core-sources", ":framework-drm-sources", ":framework-graphics-sources", @@ -481,6 +482,7 @@ java_library { "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", + "android.security.apc-java", "android.system.keystore2-java", "android.system.suspend.control.internal-java", "devicepolicyprotosnano", diff --git a/core/api/current.txt b/core/api/current.txt index 8681d419f160..2e821b3080af 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -23898,7 +23898,9 @@ package android.media.tv { field public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri"; field public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri"; field public static final String COLUMN_APP_LINK_TEXT = "app_link_text"; + field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre"; field public static final String COLUMN_BROWSABLE = "browsable"; + field public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id"; field public static final String COLUMN_DESCRIPTION = "description"; field public static final String COLUMN_DISPLAY_NAME = "display_name"; field public static final String COLUMN_DISPLAY_NUMBER = "display_number"; @@ -23913,6 +23915,8 @@ package android.media.tv { field public static final String COLUMN_LOCKED = "locked"; field public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation"; field public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id"; + field public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER = "remote_control_key_preset_number"; + field public static final String COLUMN_SCRAMBLED = "scrambled"; field public static final String COLUMN_SEARCHABLE = "searchable"; field public static final String COLUMN_SERVICE_ID = "service_id"; field public static final String COLUMN_SERVICE_TYPE = "service_type"; @@ -23921,6 +23925,7 @@ package android.media.tv { field public static final String COLUMN_TYPE = "type"; field public static final String COLUMN_VERSION_NUMBER = "version_number"; field public static final String COLUMN_VIDEO_FORMAT = "video_format"; + field public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution"; field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel"; field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel"; field public static final android.net.Uri CONTENT_URI; @@ -38773,6 +38778,7 @@ package android.telecom { method public android.telecom.PhoneAccount.Builder toBuilder(); method public void writeToParcel(android.os.Parcel, int); field public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 16384; // 0x4000 + field public static final int CAPABILITY_CALL_COMPOSER = 32768; // 0x8000 field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2 field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40 field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 @@ -39030,14 +39036,19 @@ package android.telecom { field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME"; field public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE"; field public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE"; + field public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE"; field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS"; field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS"; + field public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE"; field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE"; field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP"; + field public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION"; field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT"; field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER"; field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS"; + field public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE"; field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE"; + field public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY"; field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT"; field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE"; field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE"; @@ -39053,6 +39064,8 @@ package android.telecom { field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 field public static final int PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final int PRIORITY_NORMAL = 0; // 0x0 + field public static final int PRIORITY_URGENT = 1; // 0x1 } public class VideoProfile implements android.os.Parcelable { @@ -39356,6 +39369,7 @@ package android.telephony { field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool"; field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool"; + field public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = "call_composer_picture_server_url_string"; field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array"; field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string"; field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool"; @@ -39545,6 +39559,7 @@ package android.telephony { field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool"; field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; + field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool"; field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool"; field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool"; @@ -41880,6 +41895,7 @@ package android.telephony.ims.feature { public static class MmTelFeature.MmTelCapabilities { method public final boolean isCapable(int); + field public static final int CAPABILITY_TYPE_CALL_COMPOSER = 16; // 0x10 field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 @@ -44631,7 +44647,7 @@ package android.util { field public static final java.util.regex.Pattern DOMAIN_NAME; field public static final java.util.regex.Pattern EMAIL_ADDRESS; field @Deprecated public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; - field public static final java.util.regex.Pattern IP_ADDRESS; + field @Deprecated public static final java.util.regex.Pattern IP_ADDRESS; field public static final java.util.regex.Pattern PHONE; field @Deprecated public static final java.util.regex.Pattern TOP_LEVEL_DOMAIN; field @Deprecated public static final String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index cc819fa2e078..85186dde2154 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10494,6 +10494,35 @@ package android.telephony.cdma { package android.telephony.data { + public final class ApnThrottleStatus implements android.os.Parcelable { + method public int describeContents(); + method public int getApnType(); + method public int getRetryType(); + method public int getSlotIndex(); + method public long getThrottleExpiryTimeMillis(); + method public int getThrottleType(); + method public int getTransportType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ApnThrottleStatus> CREATOR; + field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3 + field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2 + field public static final int RETRY_TYPE_NONE = 1; // 0x1 + field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2 + field public static final int THROTTLE_TYPE_NONE = 1; // 0x1 + } + + public static final class ApnThrottleStatus.Builder { + ctor public ApnThrottleStatus.Builder(); + method @NonNull public android.telephony.data.ApnThrottleStatus build(); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setApnType(int); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setNoThrottle(); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setRetryType(int); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setSlotIndex(int); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setThrottleExpiryTimeMillis(long); + method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setTransportType(int); + field public static final long NO_THROTTLE_EXPIRY_TIME = -1L; // 0xffffffffffffffffL + } + public final class DataCallResponse implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List<android.net.LinkAddress> getAddresses(); @@ -10510,7 +10539,7 @@ package android.telephony.data { method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses(); method public int getPduSessionId(); method public int getProtocolType(); - method public long getRetryIntervalMillis(); + method public long getRetryDurationMillis(); method @Deprecated public int getSuggestedRetryTime(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; @@ -10524,7 +10553,7 @@ package android.telephony.data { field public static final int LINK_STATUS_INACTIVE = 0; // 0x0 field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff field public static final int PDU_SESSION_ID_NOT_SET = 0; // 0x0 - field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff + field public static final int RETRY_DURATION_UNDEFINED = -1; // 0xffffffff } public static final class DataCallResponse.Builder { @@ -10544,7 +10573,7 @@ package android.telephony.data { method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>); method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int); method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int); - method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long); + method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long); method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int); } @@ -10611,6 +10640,7 @@ package android.telephony.data { method public abstract void close(); method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback); method public final int getSlotIndex(); + method public final void notifyApnUnthrottled(@NonNull String); method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback); method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback); @@ -10621,6 +10651,7 @@ package android.telephony.data { } public class DataServiceCallback { + method public void onApnUnthrottled(@NonNull String); method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>); method public void onDeactivateDataCallComplete(int); method public void onHandoverCancelled(int); @@ -10646,6 +10677,7 @@ package android.telephony.data { ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int); method public abstract void close(); method public final int getSlotIndex(); + method public void reportApnThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ApnThrottleStatus>); method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>); } @@ -11031,6 +11063,7 @@ package android.telephony.ims { method public boolean getCallExtraBoolean(String, boolean); method public int getCallExtraInt(String); method public int getCallExtraInt(String, int); + method @Nullable public <T extends android.os.Parcelable> T getCallExtraParcelable(@Nullable String); method public android.os.Bundle getCallExtras(); method public int getCallType(); method public static int getCallTypeFromVideoState(int); @@ -11053,6 +11086,7 @@ package android.telephony.ims { method public void setCallExtra(String, String); method public void setCallExtraBoolean(String, boolean); method public void setCallExtraInt(String, int); + method public void setCallExtraParcelable(@NonNull String, @NonNull android.os.Parcelable); method public void setCallRestrictCause(int); method public void setCallerNumberVerificationStatus(int); method public void setEmergencyCallRouting(int); @@ -11087,6 +11121,7 @@ package android.telephony.ims { field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE"; field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE"; field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech"; + field public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT"; field public static final String EXTRA_CHILD_NUMBER = "ChildNum"; field public static final String EXTRA_CNA = "cna"; field public static final String EXTRA_CNAP = "cnap"; @@ -11096,8 +11131,11 @@ package android.telephony.ims { field public static final String EXTRA_EMERGENCY_CALL = "e_call"; field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER"; field public static final String EXTRA_IS_CALL_PULL = "CallPull"; + field public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION"; field public static final String EXTRA_OI = "oi"; field public static final String EXTRA_OIR = "oir"; + field public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL"; + field public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY"; field public static final String EXTRA_REMOTE_URI = "remote_uri"; field public static final String EXTRA_USSD = "ussd"; field public static final int OIR_DEFAULT = 0; // 0x0 @@ -11105,6 +11143,8 @@ package android.telephony.ims { field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1 field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3 + field public static final int PRIORITY_NORMAL = 0; // 0x0 + field public static final int PRIORITY_URGENT = 1; // 0x1 field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2 field public static final int SERVICE_TYPE_NONE = 0; // 0x0 field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1 @@ -11126,7 +11166,9 @@ package android.telephony.ims { method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo); method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile); method public void callSessionInitiated(android.telephony.ims.ImsCallProfile); - method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo); + method @Deprecated public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo); + method public void callSessionInitiating(@NonNull android.telephony.ims.ImsCallProfile); + method public void callSessionInitiatingFailed(@NonNull android.telephony.ims.ImsReasonInfo); method public void callSessionInviteParticipantsRequestDelivered(); method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo); method @Deprecated public void callSessionMayHandover(int, int); diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java index af74b036a796..5dc6e602e5d6 100644 --- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java +++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java @@ -16,16 +16,23 @@ package android.accounts; import android.app.Activity; -import android.content.res.Resources; -import android.os.Bundle; -import android.widget.TextView; -import android.widget.LinearLayout; -import android.view.View; -import android.view.LayoutInflater; +import android.app.ActivityTaskManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + import com.android.internal.R; import java.io.IOException; @@ -42,11 +49,15 @@ public class GrantCredentialsPermissionActivity extends Activity implements View private Account mAccount; private String mAuthTokenType; private int mUid; + private int mCallingUid; private Bundle mResultBundle = null; protected LayoutInflater mInflater; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().addSystemFlags( + android.view.WindowManager.LayoutParams + .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); setContentView(R.layout.grant_credentials_permission); setTitle(R.string.grant_permissions_header_text); @@ -74,6 +85,20 @@ public class GrantCredentialsPermissionActivity extends Activity implements View return; } + try { + IBinder activityToken = getActivityToken(); + mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken); + } catch (RemoteException re) { + // Couldn't figure out caller details + Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re); + } + + if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) { + setResult(Activity.RESULT_CANCELED); + finish(); + return; + } + String accountTypeLabel; try { accountTypeLabel = getAccountLabel(mAccount); diff --git a/core/java/android/app/people/OWNERS b/core/java/android/app/people/OWNERS new file mode 100644 index 000000000000..7371a88df237 --- /dev/null +++ b/core/java/android/app/people/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 978868 + +danningc@google.com +juliacr@google.com
\ No newline at end of file diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd1eea51f8af..46be54814dc9 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -153,6 +153,7 @@ public abstract class SliceProvider extends ContentProvider { */ public static final String EXTRA_PKG = "pkg"; /** + * @Deprecated provider pkg is now being extracted in SlicePermissionActivity * @hide */ public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; diff --git a/core/java/android/content/pm/LAUNCHER_OWNERS b/core/java/android/content/pm/LAUNCHER_OWNERS new file mode 100644 index 000000000000..400836f55ceb --- /dev/null +++ b/core/java/android/content/pm/LAUNCHER_OWNERS @@ -0,0 +1,7 @@ +set noparent + +omakoto@google.com +sunnygoyal@google.com +mett@google.com +jonmiranda@google.com +pinyaoting@google.com diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS new file mode 100644 index 000000000000..3688d5a3a4c7 --- /dev/null +++ b/core/java/android/content/pm/SHORTCUT_OWNERS @@ -0,0 +1,7 @@ +set noparent + +omakoto@google.com +yamasani@google.com +sunnygoyal@google.com +mett@google.com +pinyaoting@google.com diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 6c911f68dbe2..63c58d2b2987 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2057,7 +2057,7 @@ public class Resources { } /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(trackingBug = 176190631) public DisplayAdjustments getDisplayAdjustments() { final DisplayAdjustments overrideDisplayAdjustments = mOverrideDisplayAdjustments; if (overrideDisplayAdjustments != null) { diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java index 704f31d7f773..523449497345 100644 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -623,32 +623,41 @@ public class ConnectivityDiagnosticsManager { /** @hide */ @VisibleForTesting public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) { - Binder.withCleanCallingIdentity(() -> { + final long token = Binder.clearCallingIdentity(); + try { mExecutor.execute(() -> { mCb.onConnectivityReportAvailable(report); }); - }); + } finally { + Binder.restoreCallingIdentity(token); + } } /** @hide */ @VisibleForTesting public void onDataStallSuspected(@NonNull DataStallReport report) { - Binder.withCleanCallingIdentity(() -> { + final long token = Binder.clearCallingIdentity(); + try { mExecutor.execute(() -> { mCb.onDataStallSuspected(report); }); - }); + } finally { + Binder.restoreCallingIdentity(token); + } } /** @hide */ @VisibleForTesting public void onNetworkConnectivityReported( @NonNull Network network, boolean hasConnectivity) { - Binder.withCleanCallingIdentity(() -> { + final long token = Binder.clearCallingIdentity(); + try { mExecutor.execute(() -> { mCb.onNetworkConnectivityReported(network, hasConnectivity); }); - }); + } finally { + Binder.restoreCallingIdentity(token); + } } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 540ea5c159cc..0d10e4a01aa4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -61,6 +61,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.Protocol; @@ -1832,30 +1833,42 @@ public class ConnectivityManager { mCallback = new ISocketKeepaliveCallback.Stub() { @Override public void onStarted(int slot) { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> { - mSlot = slot; - callback.onStarted(); - })); + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = slot; + callback.onStarted(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void onStopped() { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> { - mSlot = null; - callback.onStopped(); - })); + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = null; + callback.onStopped(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } mExecutor.shutdown(); } @Override public void onError(int error) { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> { - mSlot = null; - callback.onError(error); - })); + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = null; + callback.onError(error); + }); + } finally { + Binder.restoreCallingIdentity(token); + } mExecutor.shutdown(); } @@ -3119,39 +3132,6 @@ public class ConnectivityManager { } /** - * Check mobile provisioning. - * - * @param suggestedTimeOutMs, timeout in milliseconds - * - * @return time out that will be used, maybe less that suggestedTimeOutMs - * -1 if an error. - * - * {@hide} - */ - public int checkMobileProvisioning(int suggestedTimeOutMs) { - int timeOutMs = -1; - try { - timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return timeOutMs; - } - - /** - * Get the mobile provisioning url. - * {@hide} - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public String getMobileProvisioningUrl() { - try { - return mService.getMobileProvisioningUrl(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Set sign in error notification to visible or invisible * * @hide @@ -3287,9 +3267,9 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config) { - return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE); + return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE); } /** @@ -3300,10 +3280,10 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { try { - return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId); + return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 95a2f2efeb7d..b5dd9479508f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -37,6 +37,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.ResultReceiver; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; @@ -146,10 +147,6 @@ interface IConnectivityManager boolean isVpnLockdownEnabled(int userId); List<String> getVpnLockdownWhitelist(int userId); - int checkMobileProvisioning(int suggestedTimeOutMs); - - String getMobileProvisioningUrl(); - void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); void setAirplaneMode(boolean enable); @@ -164,7 +161,7 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkAgentConfig config, in int factorySerialNumber); diff --git a/core/java/android/net/NattKeepalivePacketData.aidl b/core/java/android/net/NattKeepalivePacketData.aidl new file mode 100644 index 000000000000..af644b54827c --- /dev/null +++ b/core/java/android/net/NattKeepalivePacketData.aidl @@ -0,0 +1,18 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package android.net; + +@JavaOnlyStableParcelable parcelable NattKeepalivePacketData; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 6780167fa63e..4166c2c4f244 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -29,11 +29,12 @@ import android.os.ConditionVariable; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.Messenger; +import android.os.RemoteException; import android.util.Log; +import com.android.connectivity.aidl.INetworkAgent; +import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import java.lang.annotation.Retention; @@ -94,12 +95,18 @@ public abstract class NetworkAgent { @Nullable private volatile Network mNetwork; + @Nullable + private volatile INetworkAgentRegistry mRegistry; + + private interface RegistryAction { + void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException; + } + private final Handler mHandler; - private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; private static final boolean VDBG = false; - private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); + private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>(); private volatile long mLastBwRefreshTime = 0; private static final long BW_REFRESH_MIN_WIN_MS = 500; private boolean mBandwidthUpdateScheduled = false; @@ -329,6 +336,17 @@ public abstract class NetworkAgent { */ public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; + /** + * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection. + * obj = INetworkAgentRegistry + */ + private static final int EVENT_AGENT_CONNECTED = BASE + 18; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected. + */ + private static final int EVENT_AGENT_DISCONNECTED = BASE + 19; + private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { // The subtype can be changed with (TODO) setLegacySubtype, but it starts // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description. @@ -402,36 +420,33 @@ public abstract class NetworkAgent { @Override public void handleMessage(Message msg) { switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - if (mAsyncChannel != null) { + case EVENT_AGENT_CONNECTED: { + if (mRegistry != null) { log("Received new connection while already connected!"); } else { if (VDBG) log("NetworkAgent fully connected"); - AsyncChannel ac = new AsyncChannel(); - ac.connected(null, this, msg.replyTo); - ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); synchronized (mPreConnectedQueue) { - mAsyncChannel = ac; - for (Message m : mPreConnectedQueue) { - ac.sendMessage(m); + final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj; + mRegistry = registry; + for (RegistryAction a : mPreConnectedQueue) { + try { + a.execute(registry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Communication error with registry", e); + // Fall through + } } mPreConnectedQueue.clear(); } } break; } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - if (mAsyncChannel != null) mAsyncChannel.disconnect(); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + case EVENT_AGENT_DISCONNECTED: { if (DBG) log("NetworkAgent channel lost"); // let the client know CS is done with us. onNetworkUnwanted(); synchronized (mPreConnectedQueue) { - mAsyncChannel = null; + mRegistry = null; } break; } @@ -494,15 +509,7 @@ public abstract class NetworkAgent { } case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { - ArrayList<Integer> thresholds = - ((Bundle) msg.obj).getIntegerArrayList("thresholds"); - // TODO: Change signal strength thresholds API to use an ArrayList<Integer> - // rather than convert to int[]. - int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; - for (int i = 0; i < intThresholds.length; i++) { - intThresholds[i] = thresholds.get(i); - } - onSignalStrengthThresholdsUpdated(intThresholds); + onSignalStrengthThresholdsUpdated((int[]) msg.obj); break; } case CMD_PREVENT_AUTOMATIC_RECONNECT: { @@ -541,7 +548,7 @@ public abstract class NetworkAgent { } final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context .getSystemService(Context.CONNECTIVITY_SERVICE); - mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), + mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), new NetworkInfo(mInitialConfiguration.info), mInitialConfiguration.properties, mInitialConfiguration.capabilities, mInitialConfiguration.score, mInitialConfiguration.config, providerId); @@ -550,6 +557,95 @@ public abstract class NetworkAgent { return mNetwork; } + private static class NetworkAgentBinder extends INetworkAgent.Stub { + private final Handler mHandler; + + private NetworkAgentBinder(Handler handler) { + mHandler = handler; + } + + @Override + public void onRegistered(@NonNull INetworkAgentRegistry registry) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry)); + } + + @Override + public void onDisconnected() { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED)); + } + + @Override + public void onBandwidthUpdateRequested() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE)); + } + + @Override + public void onValidationStatusChanged( + int validationStatus, @Nullable String captivePortalUrl) { + // TODO: consider using a parcelable as argument when the interface is structured + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl); + mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS, + validationStatus, 0, redirectUrlBundle)); + } + + @Override + public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED, + acceptUnvalidated ? 1 : 0, 0)); + } + + @Override + public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStopSocketKeepalive(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0)); + } + + @Override + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + mHandler.sendMessage(mHandler.obtainMessage( + CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds)); + } + + @Override + public void onPreventAutomaticReconnect() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)); + } + + @Override + public void onAddNattKeepalivePacketFilter(int slot, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onAddTcpKeepalivePacketFilter(int slot, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onRemoveKeepalivePacketFilter(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, + slot, 0)); + } + } + /** * Register this network agent with a testing harness. * @@ -559,13 +655,13 @@ public abstract class NetworkAgent { * * @hide */ - public Messenger registerForTest(final Network network) { + public INetworkAgent registerForTest(final Network network) { log("Registering NetworkAgent for test"); synchronized (mRegisterLock) { mNetwork = network; mInitialConfiguration = null; } - return new Messenger(mHandler); + return new NetworkAgentBinder(mHandler); } /** @@ -589,29 +685,17 @@ public abstract class NetworkAgent { return mNetwork; } - private void queueOrSendMessage(int what, Object obj) { - queueOrSendMessage(what, 0, 0, obj); - } - - private void queueOrSendMessage(int what, int arg1, int arg2) { - queueOrSendMessage(what, arg1, arg2, null); - } - - private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { - Message msg = Message.obtain(); - msg.what = what; - msg.arg1 = arg1; - msg.arg2 = arg2; - msg.obj = obj; - queueOrSendMessage(msg); - } - - private void queueOrSendMessage(Message msg) { + private void queueOrSendMessage(@NonNull RegistryAction action) { synchronized (mPreConnectedQueue) { - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(msg); + if (mRegistry != null) { + try { + action.execute(mRegistry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Error executing registry action", e); + // Fall through: the channel is asynchronous and does not report errors back + } } else { - mPreConnectedQueue.add(msg); + mPreConnectedQueue.add(action); } } } @@ -622,7 +706,8 @@ public abstract class NetworkAgent { */ public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { Objects.requireNonNull(linkProperties); - queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); + final LinkProperties lp = new LinkProperties(linkProperties); + queueOrSendMessage(reg -> reg.sendLinkProperties(lp)); } /** @@ -647,9 +732,7 @@ public abstract class NetworkAgent { public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) { final ArrayList<Network> underlyingArray = (underlyingNetworks != null) ? new ArrayList<>(underlyingNetworks) : null; - final Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray); - queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle); + queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray)); } /** @@ -659,7 +742,7 @@ public abstract class NetworkAgent { public void markConnected() { mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, mNetworkInfo.getExtraInfo()); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -672,7 +755,7 @@ public abstract class NetworkAgent { // When unregistering an agent nobody should use the extrainfo (or reason) any more. mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, null /* extraInfo */); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -689,7 +772,7 @@ public abstract class NetworkAgent { @Deprecated public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -711,7 +794,7 @@ public abstract class NetworkAgent { @Deprecated public void setLegacyExtraInfo(@Nullable final String extraInfo) { mNetworkInfo.setExtraInfo(extraInfo); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -720,7 +803,11 @@ public abstract class NetworkAgent { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final void sendNetworkInfo(NetworkInfo networkInfo) { - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); + queueOrSendNetworkInfo(new NetworkInfo(networkInfo)); + } + + private void queueOrSendNetworkInfo(NetworkInfo networkInfo) { + queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo)); } /** @@ -731,8 +818,8 @@ public abstract class NetworkAgent { Objects.requireNonNull(networkCapabilities); mBandwidthUpdatePending.set(false); mLastBwRefreshTime = System.currentTimeMillis(); - queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, - new NetworkCapabilities(networkCapabilities)); + final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); + queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc)); } /** @@ -744,7 +831,7 @@ public abstract class NetworkAgent { if (score < 0) { throw new IllegalArgumentException("Score must be >= 0"); } - queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0); + queueOrSendMessage(reg -> reg.sendScore(score)); } /** @@ -784,9 +871,8 @@ public abstract class NetworkAgent { * @hide should move to NetworkAgentConfig. */ public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { - queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, - explicitlySelected ? 1 : 0, - acceptUnvalidated ? 1 : 0); + queueOrSendMessage(reg -> reg.sendExplicitlySelected( + explicitlySelected, acceptUnvalidated)); } /** @@ -909,7 +995,7 @@ public abstract class NetworkAgent { */ public final void sendSocketKeepaliveEvent(int slot, @SocketKeepalive.KeepaliveEvent int event) { - queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event); + queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event)); } /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ public void onSocketKeepaliveEvent(int slot, int reason) { diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index a7dce18a4ff9..d007a9520cb5 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -187,38 +187,54 @@ public abstract class SocketKeepalive implements AutoCloseable { mCallback = new ISocketKeepaliveCallback.Stub() { @Override public void onStarted(int slot) { - Binder.withCleanCallingIdentity(() -> - mExecutor.execute(() -> { - mSlot = slot; - callback.onStarted(); - })); + final long token = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mSlot = slot; + callback.onStarted(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void onStopped() { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - mSlot = null; - callback.onStopped(); - })); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onStopped(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void onError(int error) { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - mSlot = null; - callback.onError(error); - })); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onError(error); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void onDataReceived() { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - mSlot = null; - callback.onDataReceived(); - })); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + mSlot = null; + callback.onDataReceived(); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } }; } diff --git a/core/java/android/net/TcpKeepalivePacketData.aidl b/core/java/android/net/TcpKeepalivePacketData.aidl new file mode 100644 index 000000000000..fdc7af9fed5c --- /dev/null +++ b/core/java/android/net/TcpKeepalivePacketData.aidl @@ -0,0 +1,18 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package android.net; + +@JavaOnlyStableParcelable parcelable TcpKeepalivePacketData; diff --git a/core/java/android/os/TransactionTooLargeException.java b/core/java/android/os/TransactionTooLargeException.java index 10abf26420f1..4d5b2a10f3fe 100644 --- a/core/java/android/os/TransactionTooLargeException.java +++ b/core/java/android/os/TransactionTooLargeException.java @@ -23,9 +23,11 @@ import android.os.RemoteException; * During a remote procedure call, the arguments and the return value of the call * are transferred as {@link Parcel} objects stored in the Binder transaction buffer. * If the arguments or the return value are too large to fit in the transaction buffer, - * then the call will fail and {@link TransactionTooLargeException} will be thrown. + * then the call will fail. {@link TransactionTooLargeException} is thrown as a + * heuristic when a transaction is large, and it fails, since these are the transactions + * which are most likely to overfill the transaction buffer. * </p><p> - * The Binder transaction buffer has a limited fixed size, currently 1Mb, which + * The Binder transaction buffer has a limited fixed size, currently 1MB, which * is shared by all transactions in progress for the process. Consequently this * exception can be thrown when there are many transactions in progress even when * most of the individual transactions are of moderate size. diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java index 58268e2fc914..0fe889410685 100644 --- a/core/java/android/os/image/DynamicSystemClient.java +++ b/core/java/android/os/image/DynamicSystemClient.java @@ -68,6 +68,8 @@ import java.util.concurrent.Executor; */ @SystemApi public class DynamicSystemClient { + private static final String TAG = "DynamicSystemClient"; + /** @hide */ @IntDef(prefix = { "STATUS_" }, value = { STATUS_UNKNOWN, @@ -92,8 +94,6 @@ public class DynamicSystemClient { @Retention(RetentionPolicy.SOURCE) public @interface StatusChangedCause {} - private static final String TAG = "DynSystemClient"; - /** Listener for installation status updates. */ public interface OnStatusChangedListener { /** @@ -240,7 +240,7 @@ public class DynamicSystemClient { private class DynSystemServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName className, IBinder service) { - Slog.v(TAG, "DynSystemService connected"); + Slog.v(TAG, "onServiceConnected: " + className); mService = new Messenger(service); @@ -262,7 +262,7 @@ public class DynamicSystemClient { } public void onServiceDisconnected(ComponentName className) { - Slog.v(TAG, "DynSystemService disconnected"); + Slog.v(TAG, "onServiceDisconnected: " + className); mService = null; } } diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java index 7f01cad940ec..e8e47857ecba 100644 --- a/core/java/android/os/image/DynamicSystemManager.java +++ b/core/java/android/os/image/DynamicSystemManager.java @@ -269,4 +269,16 @@ public class DynamicSystemManager { throw new RuntimeException(e.toString()); } } + + /** + * Returns the suggested scratch partition size for overlayFS. + */ + @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) + public long suggestScratchSize() { + try { + return mService.suggestScratchSize(); + } catch (RemoteException e) { + throw new RuntimeException(e.toString()); + } + } } diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index df0a69b47225..a5a40ad55853 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -125,4 +125,9 @@ interface IDynamicSystemService * valid VBMeta block to retrieve the AVB key from. */ boolean getAvbPublicKey(out AvbPublicKey dst); + + /** + * Returns the suggested scratch partition size for overlayFS. + */ + long suggestScratchSize(); } diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java index f67af85d00e3..232903724d82 100644 --- a/core/java/android/security/ConfirmationPrompt.java +++ b/core/java/android/security/ConfirmationPrompt.java @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.security.keystore.AndroidKeyStoreProvider; import android.text.TextUtils; import android.util.Log; @@ -36,15 +37,15 @@ import java.util.concurrent.Executor; * compromised. Implementing confirmation prompts with these guarantees requires dedicated * hardware-support and may not always be available. * - * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> - + * <p>Confirmation prompts are typically used with an external entity - the <i>Relying Party</i> - * in the following way. The setup steps are as follows: * <ul> * <li> Before first use, the application generates a key-pair with the * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired - * CONFIRMATION tag} set. Device attestation, - * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to - * generate a certificate chain that includes the public key (<code>Kpub</code> in the following) - * of the newly generated key. + * CONFIRMATION tag} set. AndroidKeyStore key attestation, e.g., + * {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])} + * is used to generate a certificate chain that includes the public key (<code>Kpub</code> in the + * following) of the newly generated key. * <li> The application sends <code>Kpub</code> and the certificate chain resulting from device * attestation to the <i>Relying Party</i>. * <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root @@ -78,9 +79,10 @@ import java.util.concurrent.Executor; * previously created nonce. If all checks passes, the transaction is executed. * </ul> * - * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the - * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it - * along the nonce in the <code>extraData</code> blob. + * <p>Note: It is vital to check the <code>promptText</code> because this is the only part that + * the user has approved. To avoid writing parsers for all of the possible locales, it is + * recommended that the <i>Relying Party</i> uses the same string generator as used on the device + * and performs a simple string comparison. */ public class ConfirmationPrompt { private static final String TAG = "ConfirmationPrompt"; @@ -92,6 +94,14 @@ public class ConfirmationPrompt { private Context mContext; private final KeyStore mKeyStore = KeyStore.getInstance(); + private AndroidProtectedConfirmation mProtectedConfirmation; + + private AndroidProtectedConfirmation getService() { + if (mProtectedConfirmation == null) { + mProtectedConfirmation = new AndroidProtectedConfirmation(); + } + return mProtectedConfirmation; + } private void doCallback(int responseCode, byte[] dataThatWasConfirmed, ConfirmationCallback callback) { @@ -119,6 +129,32 @@ public class ConfirmationPrompt { } } + private void doCallback2(int responseCode, byte[] dataThatWasConfirmed, + ConfirmationCallback callback) { + switch (responseCode) { + case AndroidProtectedConfirmation.ERROR_OK: + callback.onConfirmed(dataThatWasConfirmed); + break; + + case AndroidProtectedConfirmation.ERROR_CANCELED: + callback.onDismissed(); + break; + + case AndroidProtectedConfirmation.ERROR_ABORTED: + callback.onCanceled(); + break; + + case AndroidProtectedConfirmation.ERROR_SYSTEM_ERROR: + callback.onError(new Exception("System error returned by ConfirmationUI.")); + break; + + default: + callback.onError(new Exception("Unexpected responseCode=" + responseCode + + " from onConfirmtionPromptCompleted() callback.")); + break; + } + } + private final android.os.IBinder mCallbackBinder = new android.security.IConfirmationPromptCallback.Stub() { @Override @@ -144,6 +180,29 @@ public class ConfirmationPrompt { } }; + private final android.security.apc.IConfirmationCallback mConfirmationCallback = + new android.security.apc.IConfirmationCallback.Stub() { + @Override + public void onCompleted(int result, byte[] dataThatWasConfirmed) + throws android.os.RemoteException { + if (mCallback != null) { + ConfirmationCallback callback = mCallback; + Executor executor = mExecutor; + mCallback = null; + mExecutor = null; + if (executor == null) { + doCallback2(result, dataThatWasConfirmed, callback); + } else { + executor.execute(new Runnable() { + @Override public void run() { + doCallback2(result, dataThatWasConfirmed, callback); + } + }); + } + } + } + }; + /** * A builder that collects arguments, to be shown on the system-provided confirmation prompt. */ @@ -211,6 +270,9 @@ public class ConfirmationPrompt { private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1; private int getUiOptionsAsFlags() { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + return getUiOptionsAsFlags2(); + } int uiOptionsAsFlags = 0; ContentResolver contentResolver = mContext.getContentResolver(); int inversionEnabled = Settings.Secure.getInt(contentResolver, @@ -226,6 +288,22 @@ public class ConfirmationPrompt { return uiOptionsAsFlags; } + private int getUiOptionsAsFlags2() { + int uiOptionsAsFlags = 0; + ContentResolver contentResolver = mContext.getContentResolver(); + int inversionEnabled = Settings.Secure.getInt(contentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0); + if (inversionEnabled == 1) { + uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_INVERTED; + } + float fontScale = Settings.System.getFloat(contentResolver, + Settings.System.FONT_SCALE, (float) 1.0); + if (fontScale > 1.0) { + uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; + } + return uiOptionsAsFlags; + } + private static boolean isAccessibilityServiceRunning(Context context) { boolean serviceRunning = false; try { @@ -270,29 +348,53 @@ public class ConfirmationPrompt { mCallback = callback; mExecutor = executor; - int uiOptionsAsFlags = getUiOptionsAsFlags(); String locale = Locale.getDefault().toLanguageTag(); - int responseCode = mKeyStore.presentConfirmationPrompt( - mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); - switch (responseCode) { - case KeyStore.CONFIRMATIONUI_OK: - return; + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + int uiOptionsAsFlags = getUiOptionsAsFlags2(); + int responseCode = getService().presentConfirmationPrompt( + mConfirmationCallback, mPromptText.toString(), mExtraData, locale, + uiOptionsAsFlags); + switch (responseCode) { + case AndroidProtectedConfirmation.ERROR_OK: + return; + + case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING: + throw new ConfirmationAlreadyPresentingException(); + + case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED: + throw new ConfirmationNotAvailableException(); - case KeyStore.CONFIRMATIONUI_OPERATION_PENDING: - throw new ConfirmationAlreadyPresentingException(); + default: + // Unexpected error code. + Log.w(TAG, + "Unexpected responseCode=" + responseCode + + " from presentConfirmationPrompt() call."); + throw new IllegalArgumentException(); + } + } else { + int uiOptionsAsFlags = getUiOptionsAsFlags(); + int responseCode = mKeyStore.presentConfirmationPrompt( + mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); + switch (responseCode) { + case KeyStore.CONFIRMATIONUI_OK: + return; - case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED: - throw new ConfirmationNotAvailableException(); + case KeyStore.CONFIRMATIONUI_OPERATION_PENDING: + throw new ConfirmationAlreadyPresentingException(); - case KeyStore.CONFIRMATIONUI_UIERROR: - throw new IllegalArgumentException(); + case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED: + throw new ConfirmationNotAvailableException(); - default: - // Unexpected error code. - Log.w(TAG, - "Unexpected responseCode=" + responseCode - + " from presentConfirmationPrompt() call."); - throw new IllegalArgumentException(); + case KeyStore.CONFIRMATIONUI_UIERROR: + throw new IllegalArgumentException(); + + default: + // Unexpected error code. + Log.w(TAG, + "Unexpected responseCode=" + responseCode + + " from presentConfirmationPrompt() call."); + throw new IllegalArgumentException(); + } } } @@ -306,17 +408,33 @@ public class ConfirmationPrompt { * @throws IllegalStateException if no prompt is currently being presented. */ public void cancelPrompt() { - int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder); - if (responseCode == KeyStore.CONFIRMATIONUI_OK) { - return; - } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) { - throw new IllegalStateException(); + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + int responseCode = + getService().cancelConfirmationPrompt(mConfirmationCallback); + if (responseCode == AndroidProtectedConfirmation.ERROR_OK) { + return; + } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) { + throw new IllegalStateException(); + } else { + // Unexpected error code. + Log.w(TAG, + "Unexpected responseCode=" + responseCode + + " from cancelConfirmationPrompt() call."); + throw new IllegalStateException(); + } } else { - // Unexpected error code. - Log.w(TAG, - "Unexpected responseCode=" + responseCode - + " from cancelConfirmationPrompt() call."); - throw new IllegalStateException(); + int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder); + if (responseCode == KeyStore.CONFIRMATIONUI_OK) { + return; + } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) { + throw new IllegalStateException(); + } else { + // Unexpected error code. + Log.w(TAG, + "Unexpected responseCode=" + responseCode + + " from cancelConfirmationPrompt() call."); + throw new IllegalStateException(); + } } } @@ -330,6 +448,9 @@ public class ConfirmationPrompt { if (isAccessibilityServiceRunning(context)) { return false; } + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + return new AndroidProtectedConfirmation().isConfirmationPromptSupported(); + } return KeyStore.getInstance().isConfirmationPromptSupported(); } } diff --git a/core/java/android/service/timezone/OWNERS b/core/java/android/service/timezone/OWNERS new file mode 100644 index 000000000000..28aff188dbd8 --- /dev/null +++ b/core/java/android/service/timezone/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 847766 +nfuller@google.com +include /core/java/android/app/timedetector/OWNERS diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java index 7ad16ff3dc23..ece069fa0873 100644 --- a/core/java/android/util/Patterns.java +++ b/core/java/android/util/Patterns.java @@ -248,6 +248,13 @@ public class Patterns { + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))"; + + /** + * Kept for backward compatibility reasons. It does not match IPv6 addresses. + * + * @deprecated Please use {@link android.net.InetAddresses#isNumericAddress(String)} instead. + */ + @Deprecated public static final Pattern IP_ADDRESS = Pattern.compile(IP_ADDRESS_STRING); /** diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index bae6ee85c064..e66b17aa4426 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -33,6 +33,9 @@ per-file SimulatedDpad.java = file:/services/core/java/com/android/server/input/ per-file InputWindowHandle.java = file:/services/core/java/com/android/server/input/OWNERS per-file InputWindowHandle.java = file:/services/core/java/com/android/server/wm/OWNERS +# Notifications +per-file Notification*.java = file:/services/core/java/com/android/server/notification/OWNERS + # Surface per-file Surface.java = file:/graphics/java/android/graphics/OWNERS per-file Surface.java = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index 382b49e68e6f..c5a956a81d8d 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -2,3 +2,4 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Resolver* = file:/packages/SystemUI/OWNERS per-file *Chooser* = file:/packages/SystemUI/OWNERS per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS +per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java index f7fad2c5bbaa..2dd51b4459e7 100644 --- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java @@ -143,6 +143,10 @@ public abstract class KernelCpuUidTimeReader<T> { */ public void removeUid(int uid) { mLastTimes.delete(uid); + + if (mBpfTimesAvailable) { + mBpfReader.removeUidsInRange(uid, uid); + } } /** diff --git a/core/tests/coretests/src/android/app/assist/OWNERS b/core/tests/coretests/src/android/app/assist/OWNERS new file mode 100644 index 000000000000..43ad1085a28f --- /dev/null +++ b/core/tests/coretests/src/android/app/assist/OWNERS @@ -0,0 +1 @@ +file:/core/java/android/app/assist/OWNERS diff --git a/core/tests/coretests/src/android/service/notification/OWNERS b/core/tests/coretests/src/android/service/notification/OWNERS new file mode 100644 index 000000000000..1502b6071b80 --- /dev/null +++ b/core/tests/coretests/src/android/service/notification/OWNERS @@ -0,0 +1,2 @@ +include platform/frameworks/base:/services/core/java/com/android/server/notification/OWNERS + diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS index a3a3e7cfc4af..5031ff913e6d 100644 --- a/core/tests/coretests/src/android/view/OWNERS +++ b/core/tests/coretests/src/android/view/OWNERS @@ -2,3 +2,10 @@ per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com per-file VelocityTest.java = michaelwr@google.com, svv@google.com + +# WindowManager +per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS +per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS +per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS +per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS +per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 057c0120b685..a185da19e71b 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -343,6 +343,8 @@ applications that come with the platform <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <permission name="android.permission.MOVE_PACKAGE"/> + <!-- Needed for test only --> + <permission name="android.permission.NETWORK_AIRPLANE_MODE"/> <permission name="android.permission.OBSERVE_APP_USAGE"/> <permission name="android.permission.NETWORK_SCAN"/> <permission name="android.permission.PACKAGE_USAGE_STATS" /> @@ -438,6 +440,9 @@ applications that come with the platform <permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" /> <!-- Permissions required for CTS test - CtsHdmiCecHostTestCases --> <permission name="android.permission.HDMI_CEC"/> + <!-- Permission needed for CTS test - WifiManagerTest --> + <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> + <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> @@ -447,6 +452,8 @@ applications that come with the platform <privapp-permissions package="com.android.traceur"> <!-- Permissions required to receive BUGREPORT_STARTED intent --> <permission name="android.permission.DUMP"/> + <!-- Permissions required to start/stop tracing --> + <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/> <!-- Permissions required for quick settings tile --> <permission name="android.permission.STATUS_BAR"/> </privapp-permissions> diff --git a/data/keyboards/Vendor_0957_Product_0001.idc b/data/keyboards/Vendor_0957_Product_0001.idc new file mode 100644 index 000000000000..e1f4346369f3 --- /dev/null +++ b/data/keyboards/Vendor_0957_Product_0001.idc @@ -0,0 +1,23 @@ +# Copyright (C) 2021 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. + +# +# Input Device Configuration file for Google Reference RCU Remote. +# +# + +# Basic Parameters +keyboard.layout = Vendor_0957_Product_0001 +keyboard.characterMap = Vendor_0957_Product_0001 +audio.mic = 1
\ No newline at end of file diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl new file mode 100644 index 000000000000..e9f4f2880c91 --- /dev/null +++ b/data/keyboards/Vendor_0957_Product_0001.kl @@ -0,0 +1,72 @@ +# Copyright (C) 2021 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. + +# +# Key Layout file for Google Reference RCU Remote. +# + +key 116 POWER WAKE +key 217 ASSIST WAKE + +key 103 DPAD_UP +key 108 DPAD_DOWN +key 105 DPAD_LEFT +key 106 DPAD_RIGHT +key 353 DPAD_CENTER + +key 158 BACK +key 172 HOME WAKE + +key 113 VOLUME_MUTE +key 114 VOLUME_DOWN +key 115 VOLUME_UP + +key 2 1 +key 3 2 +key 4 3 +key 5 4 +key 6 5 +key 7 6 +key 8 7 +key 9 8 +key 10 9 +key 11 0 + +# custom keys +key usage 0x000c01BB TV_INPUT +key usage 0x000c022A BOOKMARK +key usage 0x000c0096 SETTINGS +key usage 0x000c0097 NOTIFICATION +key usage 0x000c008D GUIDE +key usage 0x000c0089 TV +key usage 0x000c009C CHANNEL_UP +key usage 0x000c009D CHANNEL_DOWN +key usage 0x000c00CD MEDIA_PLAY_PAUSE +key usage 0x000c00B4 MEDIA_SKIP_BACKWARD +key usage 0x000c00B3 MEDIA_SKIP_FORWARD +key usage 0x000c0226 MEDIA_STOP + +key usage 0x000c0077 BUTTON_3 WAKE #YouTube +key usage 0x000c0078 BUTTON_4 WAKE #Netflix +key usage 0x000c0079 BUTTON_6 WAKE #Disney+ +key usage 0x000c007A BUTTON_7 WAKE #HBOmax + +key usage 0x000c01BD INFO +key usage 0x000c0061 CAPTIONS +key usage 0x000c0185 TV_TELETEXT + +key usage 0x000c0069 PROG_RED +key usage 0x000c006A PROG_GREEN +key usage 0x000c006B PROG_BLUE +key usage 0x000c006C PROG_YELLOW
\ No newline at end of file diff --git a/graphics/OWNERS b/graphics/OWNERS index a6d1bc37d27d..5851cbbdf33c 100644 --- a/graphics/OWNERS +++ b/graphics/OWNERS @@ -1 +1 @@ -include /core/java/android/graphics/OWNERS +include /graphics/java/android/graphics/OWNERS
\ No newline at end of file diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 635f6c66985c..b3c33554b5aa 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -122,7 +122,7 @@ public class RippleDrawable extends LayerDrawable { private final Rect mDirtyBounds = new Rect(); /** Mirrors mLayerState with some extra information. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(trackingBug = 175939224) private RippleState mState; /** The masking layer, e.g. the layer with id R.id.mask. */ diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java new file mode 100644 index 000000000000..dfe485ac8274 --- /dev/null +++ b/keystore/java/android/security/AndroidProtectedConfirmation.java @@ -0,0 +1,118 @@ +/* + * 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.security; + +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.security.apc.IConfirmationCallback; +import android.security.apc.IProtectedConfirmation; +import android.security.apc.ResponseCode; +import android.util.Log; + +/** + * @hide + */ +public class AndroidProtectedConfirmation { + private static final String TAG = "AndroidProtectedConfirmation"; + + public static final int ERROR_OK = ResponseCode.OK; + public static final int ERROR_CANCELED = ResponseCode.CANCELLED; + public static final int ERROR_ABORTED = ResponseCode.ABORTED; + public static final int ERROR_OPERATION_PENDING = ResponseCode.OPERATION_PENDING; + public static final int ERROR_IGNORED = ResponseCode.IGNORED; + public static final int ERROR_SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR; + public static final int ERROR_UNIMPLEMENTED = ResponseCode.UNIMPLEMENTED; + + public static final int FLAG_UI_OPTION_INVERTED = + IProtectedConfirmation.FLAG_UI_OPTION_INVERTED; + public static final int FLAG_UI_OPTION_MAGNIFIED = + IProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED; + + private IProtectedConfirmation mProtectedConfirmation; + + public AndroidProtectedConfirmation() { + mProtectedConfirmation = null; + } + + private synchronized IProtectedConfirmation getService() { + if (mProtectedConfirmation == null) { + mProtectedConfirmation = IProtectedConfirmation.Stub.asInterface(ServiceManager + .getService("android.security.apc")); + } + return mProtectedConfirmation; + } + + /** + * Requests keystore call into the confirmationui HAL to display a prompt. + * + * @param listener the binder to use for callbacks. + * @param promptText the prompt to display. + * @param extraData extra data / nonce from application. + * @param locale the locale as a BCP 47 language tag. + * @param uiOptionsAsFlags the UI options to use, as flags. + * @return one of the {@code CONFIRMATIONUI_*} constants, for + * example {@code KeyStore.CONFIRMATIONUI_OK}. + */ + public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText, + byte[] extraData, String locale, int uiOptionsAsFlags) { + try { + getService().presentPrompt(listener, promptText, extraData, locale, + uiOptionsAsFlags); + return ERROR_OK; + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return ERROR_SYSTEM_ERROR; + } catch (ServiceSpecificException e) { + return e.errorCode; + } + } + + /** + * Requests keystore call into the confirmationui HAL to cancel displaying a prompt. + * + * @param listener the binder passed to the {@link #presentConfirmationPrompt} method. + * @return one of the {@code CONFIRMATIONUI_*} constants, for + * example {@code KeyStore.CONFIRMATIONUI_OK}. + */ + public int cancelConfirmationPrompt(IConfirmationCallback listener) { + try { + getService().cancelPrompt(listener); + return ERROR_OK; + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return ERROR_SYSTEM_ERROR; + } catch (ServiceSpecificException e) { + return e.errorCode; + } + } + + /** + * Requests keystore to check if the confirmationui HAL is available. + * + * @return whether the confirmationUI HAL is available. + */ + public boolean isConfirmationPromptSupported() { + try { + return getService().isSupported(); + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return false; + } + } + +} diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java index f87a3d25f90c..992454285738 100644 --- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java @@ -120,6 +120,7 @@ abstract class KeyStoreCryptoOperationUtils { return new KeyPermanentlyInvalidatedException(); case ResponseCode.LOCKED: case ResponseCode.UNINITIALIZED: + case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // TODO b/173111727 remove response codes LOCKED and UNINITIALIZED return new UserNotAuthenticatedException(); default: diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 433c6227cd5f..30a14c84b72e 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -2450,6 +2450,71 @@ public final class TvContract { */ public static final String COLUMN_GLOBAL_CONTENT_ID = "global_content_id"; + /** + * The remote control key preset number that is assigned to this channel. + * + * <p> This can be used for one-touch-tuning, tuning to the channel with + * pressing the preset button. + * + * <p> Type: INTEGER (remote control key preset number) + */ + public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER = + "remote_control_key_preset_number"; + + /** + * The flag indicating whether this TV channel is scrambled or not. + * + * <p>Use the same coding for scrambled in the underlying broadcast standard + * if {@code free_ca_mode} in SDT is defined there (e.g. ETSI EN 300 468). + * + * <p>Type: INTEGER (boolean) + */ + public static final String COLUMN_SCRAMBLED = "scrambled"; + + /** + * The typical video resolution. + * + * <p>This is primarily used to filter out channels based on video resolution + * by applications. The value is from SDT if defined there. (e.g. ETSI EN 300 468) + * The value should match one of the followings: {@link #VIDEO_RESOLUTION_SD}, + * {@link #VIDEO_RESOLUTION_HD}, {@link #VIDEO_RESOLUTION_UHD}. + * + * <p>Type: TEXT + * + */ + public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution"; + + /** + * The channel list ID of this TV channel. + * + * <p>It is used to identify the channel list constructed from broadcast SI based on the + * underlying broadcast standard or country/operator profile, if applicable. Otherwise, + * leave empty. + * + * <p>The ID can be defined by individual TV input services. For example, one may assign a + * service operator name for the service operator channel list constructed from broadcast + * SI or one may assign the {@code profile_name} of the operator_info() APDU defined in CI + * Plus 1.3 for the dedicated CICAM operator profile channel list constructed + * from CICAM NIT. + * + * <p>Type: TEXT + */ + public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id"; + + /** + * The comma-separated genre string of this TV channel. + * + * <p>Use the same language appeared in the underlying broadcast standard, if applicable. + * Otherwise, leave empty. Use + * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column. + * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the + * text stored in the column. + * + * <p>Type: TEXT + * @see Programs#COLUMN_BROADCAST_GENRE + */ + public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE; + private Channels() {} /** diff --git a/native/graphics/OWNERS b/native/graphics/OWNERS index a6d1bc37d27d..d81ea2cd538a 100644 --- a/native/graphics/OWNERS +++ b/native/graphics/OWNERS @@ -1 +1 @@ -include /core/java/android/graphics/OWNERS +include /graphics/java/android/graphics/OWNERS diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp index a26f715280a1..c8f3bd3666e4 100644 --- a/packages/Connectivity/service/Android.bp +++ b/packages/Connectivity/service/Android.bp @@ -14,8 +14,8 @@ // limitations under the License. // -cc_defaults { - name: "libservice-connectivity-defaults", +cc_library_shared { + name: "libservice-connectivity", // TODO: build against the NDK (sdk_version: "30" for example) cflags: [ "-Wall", @@ -26,6 +26,7 @@ cc_defaults { srcs: [ "jni/com_android_server_TestNetworkService.cpp", "jni/com_android_server_connectivity_Vpn.cpp", + "jni/onload.cpp", ], shared_libs: [ "libbase", @@ -35,27 +36,11 @@ cc_defaults { // addresses, and remove dependency on libnetutils. "libnetutils", ], -} - -cc_library_shared { - name: "libservice-connectivity", - defaults: ["libservice-connectivity-defaults"], - srcs: [ - "jni/onload.cpp", - ], apex_available: [ - // TODO: move this library to the tethering APEX and remove libservice-connectivity-static - // "com.android.tethering", + "com.android.tethering", ], } -// Static library linked into libservices.core until libservice-connectivity can be loaded from -// the tethering APEX instead. -cc_library_static { - name: "libservice-connectivity-static", - defaults: ["libservice-connectivity-defaults"], -} - java_library { name: "service-connectivity", srcs: [ @@ -75,5 +60,6 @@ java_library { ], apex_available: [ "//apex_available:platform", + "com.android.tethering", ], } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index a4896cb2d8dc..7f19662c6961 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -74,7 +74,7 @@ import java.util.ArrayList; public class DynamicSystemInstallationService extends Service implements InstallationAsyncTask.ProgressListener { - private static final String TAG = "DynSystemInstallationService"; + private static final String TAG = "DynamicSystemInstallationService"; // TODO (b/131866826): This is currently for test only. Will move this to System API. static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index ac73f35517d6..4ef5e2b4f090 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -20,6 +20,7 @@ import android.content.Context; import android.gsi.AvbPublicKey; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.MemoryFile; import android.os.ParcelFileDescriptor; import android.os.image.DynamicSystemManager; @@ -51,7 +52,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27; private static final List<String> UNSUPPORTED_PARTITIONS = - Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other"); + Arrays.asList( + "vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other", "scratch"); private class UnsupportedUrlException extends Exception { private UnsupportedUrlException(String message) { @@ -196,6 +198,22 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog return null; } + if (Build.IS_DEBUGGABLE) { + // If host is debuggable, then install a scratch partition so that we can do + // adb remount in the guest system. + try { + installScratch(); + } catch (IOException e) { + // Failing to install overlayFS scratch shouldn't be fatal. + // Just ignore the error and skip installing the scratch partition. + Log.w(TAG, e.toString(), e); + } + if (isCancelled()) { + mDynSystem.remove(); + return null; + } + } + mDynSystem.finishInstallation(); } catch (Exception e) { Log.e(TAG, e.toString(), e); @@ -302,12 +320,53 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } } - private void installUserdata() throws Exception { + private void installScratch() throws IOException, InterruptedException { + final long scratchSize = mDynSystem.suggestScratchSize(); + Thread thread = new Thread() { + @Override + public void run() { + mInstallationSession = + mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false); + } + }; + + Log.d(TAG, "Creating partition: scratch, size = " + scratchSize); + thread.start(); + + Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++); + + while (thread.isAlive()) { + if (isCancelled()) { + return; + } + + final long installedSize = mDynSystem.getInstallationProgress().bytes_processed; + + if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) { + progress.installedSize = installedSize; + publishProgress(progress); + } + + Thread.sleep(100); + } + + if (mInstallationSession == null) { + throw new IOException( + "Failed to start installation with requested size: " + scratchSize); + } + // Reset installation session and verify that installation completes successfully. + mInstallationSession = null; + if (!mDynSystem.closePartition()) { + throw new IOException("Failed to complete partition installation: scratch"); + } + } + + private void installUserdata() throws IOException, InterruptedException { Thread thread = new Thread(() -> { mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false); }); - Log.d(TAG, "Creating partition: userdata"); + Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize); thread.start(); Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++); @@ -324,7 +383,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog publishProgress(progress); } - Thread.sleep(10); + Thread.sleep(100); } if (mInstallationSession == null) { @@ -445,7 +504,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog return; } - Thread.sleep(10); + Thread.sleep(100); } if (mInstallationSession == null) { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index be778e92787e..94829b506f95 100755 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -17,6 +17,7 @@ package com.android.packageinstaller; import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid; @@ -87,6 +88,8 @@ public class UninstallerActivity extends Activity { @Override public void onCreate(Bundle icicle) { + getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + // Never restore any state, esp. never create any fragments. The data in the fragment might // be stale, if e.g. the app was uninstalled while the activity was destroyed. super.onCreate(null); diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS new file mode 100644 index 000000000000..e7a20b3f73a4 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/OWNERS @@ -0,0 +1,8 @@ +# Default reviewers for this and subdirectories. +andychou@google.com +arcwang@google.com +goldmanj@google.com +qal@google.com +wengsu@google.com + +# Emergency approvers in case the above are not available diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 0fdb282edc23..88eef6ab109a 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -291,6 +291,9 @@ <uses-permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" /> <!-- Permission needed to read wifi network credentials for CtsNetTestCases --> + <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" /> + + <!-- Permission needed to read wifi network credentials for CtsNetTestCases --> <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" /> <!-- Permission needed to use wifi usability API's for CtsNetTestCases --> @@ -337,6 +340,10 @@ <!-- Permission needed for CTS test - CtsHdmiCecHostTestCases --> <uses-permission android:name="android.permission.HDMI_CEC" /> + <!-- Permission needed for CTS test - WifiManagerTest --> + <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" /> + <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 63b9bb39cba0..8b73c5ed552e 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -47,6 +47,7 @@ import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; +import android.os.Binder; import android.os.BugreportManager; import android.os.BugreportManager.BugreportCallback; import android.os.BugreportManager.BugreportCallback.BugreportErrorCode; @@ -186,7 +187,7 @@ public class BugreportProgressService extends Service { static final int SCREENSHOT_DELAY_SECONDS = 3; /** System property where dumpstate stores last triggered bugreport id */ - private static final String PROPERTY_LAST_ID = "dumpstate.last_id"; + static final String PROPERTY_LAST_ID = "dumpstate.last_id"; private static final String BUGREPORT_SERVICE = "bugreport"; @@ -233,7 +234,7 @@ public class BugreportProgressService extends Service { private File mBugreportsDir; - private BugreportManager mBugreportManager; + @VisibleForTesting BugreportManager mBugreportManager; /** * id of the notification used to set service on foreground. @@ -248,6 +249,11 @@ public class BugreportProgressService extends Service { */ private boolean mTakingScreenshot; + /** + * The delay timeout before taking a screenshot. + */ + @VisibleForTesting int mScreenshotDelaySec = SCREENSHOT_DELAY_SECONDS; + @GuardedBy("sNotificationBundle") private static final Bundle sNotificationBundle = new Bundle(); @@ -282,6 +288,7 @@ public class BugreportProgressService extends Service { mContext.getString(R.string.bugreport_notification_channel), isTv(this) ? NotificationManager.IMPORTANCE_DEFAULT : NotificationManager.IMPORTANCE_LOW)); + mBugreportManager = mContext.getSystemService(BugreportManager.class); } @Override @@ -305,7 +312,7 @@ public class BugreportProgressService extends Service { @Override public IBinder onBind(Intent intent) { - return null; + return new LocalBinder(); } @Override @@ -373,8 +380,14 @@ public class BugreportProgressService extends Service { public void onFinished() { mInfo.renameBugreportFile(); mInfo.renameScreenshots(); + if (mInfo.bugreportFile.length() == 0) { + Log.e(TAG, "Bugreport file empty. File path = " + mInfo.bugreportFile); + onError(BUGREPORT_ERROR_RUNTIME); + return; + } synchronized (mLock) { sendBugreportFinishedBroadcastLocked(); + mMainThreadHandler.post(() -> mInfoDialog.onBugreportFinished(mInfo)); } } @@ -400,10 +413,6 @@ public class BugreportProgressService extends Service { @GuardedBy("mLock") private void sendBugreportFinishedBroadcastLocked() { final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath(); - if (mInfo.bugreportFile.length() == 0) { - Log.e(TAG, "Bugreport file empty. File path = " + bugreportFilePath); - return; - } if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) { sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath, mInfo.bugreportFile); @@ -609,12 +618,21 @@ public class BugreportProgressService extends Service { BugreportInfo info = new BugreportInfo(mContext, baseName, name, shareTitle, shareDescription, bugreportType, mBugreportsDir); + synchronized (mLock) { + if (info.bugreportFile.exists()) { + Log.e(TAG, "Failed to start bugreport generation, the requested bugreport file " + + info.bugreportFile + " already exists"); + return; + } + info.createBugreportFile(); + } ParcelFileDescriptor bugreportFd = info.getBugreportFd(); if (bugreportFd == null) { Log.e(TAG, "Failed to start bugreport generation as " + " bugreport parcel file descriptor is null."); return; } + info.createScreenshotFile(mBugreportsDir); ParcelFileDescriptor screenshotFd = null; if (isDefaultScreenshotRequired(bugreportType, /* hasScreenshotButton= */ !mIsTv)) { screenshotFd = info.getDefaultScreenshotFd(); @@ -627,8 +645,6 @@ public class BugreportProgressService extends Service { } } - mBugreportManager = (BugreportManager) mContext.getSystemService( - Context.BUGREPORT_SERVICE); final Executor executor = ActivityThread.currentActivityThread().getExecutor(); Log.i(TAG, "bugreport type = " + bugreportType @@ -888,12 +904,12 @@ public class BugreportProgressService extends Service { collapseNotificationBar(); final String msg = mContext.getResources() .getQuantityString(com.android.internal.R.plurals.bugreport_countdown, - SCREENSHOT_DELAY_SECONDS, SCREENSHOT_DELAY_SECONDS); + mScreenshotDelaySec, mScreenshotDelaySec); Log.i(TAG, msg); // Show a toast just once, otherwise it might be captured in the screenshot. Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); - takeScreenshot(id, SCREENSHOT_DELAY_SECONDS); + takeScreenshot(id, mScreenshotDelaySec); } /** @@ -1248,6 +1264,7 @@ public class BugreportProgressService extends Service { .setContentText(content) .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT)) + .setOnlyAlertOnce(false) .setDeleteIntent(newCancelIntent(mContext, info)); if (!TextUtils.isEmpty(info.getName())) { @@ -1287,6 +1304,7 @@ public class BugreportProgressService extends Service { .setLocalOnly(true) .setColor(context.getColor( com.android.internal.R.color.system_notification_accent_color)) + .setOnlyAlertOnce(true) .extend(new Notification.TvExtender()); } @@ -1621,6 +1639,16 @@ public class BugreportProgressService extends Service { } /** + * A local binder with interface to return an instance of BugreportProgressService for the + * purpose of testing. + */ + final class LocalBinder extends Binder { + @VisibleForTesting BugreportProgressService getService() { + return BugreportProgressService.this; + } + } + + /** * Helper class encapsulating the UI elements and logic used to display a dialog where user * can change the details of a bugreport. */ @@ -1749,6 +1777,22 @@ public class BugreportProgressService extends Service { } } + /** + * Notifies the dialog that the bugreport has finished so it disables the {@code name} + * field. + * <p>Once the bugreport is finished dumpstate has already generated the final files, so + * changing the name would have no effect. + */ + void onBugreportFinished(BugreportInfo info) { + if (mId == info.id && mInfoName != null) { + mInfoName.setEnabled(false); + mInfoName.setText(null); + if (!TextUtils.isEmpty(info.getName())) { + mInfoName.setText(info.getName()); + } + } + } + void cancel() { if (mDialog != null) { mDialog.cancel(); @@ -1883,12 +1927,10 @@ public class BugreportProgressService extends Service { this.shareDescription = shareDescription == null ? "" : shareDescription; this.type = type; this.baseName = baseName; - createBugreportFile(bugreportsDir); - createScreenshotFile(bugreportsDir); + this.bugreportFile = new File(bugreportsDir, getFileName(this, ".zip")); } - void createBugreportFile(File bugreportsDir) { - bugreportFile = new File(bugreportsDir, getFileName(this, ".zip")); + void createBugreportFile() { createReadWriteFile(bugreportFile); } @@ -1993,12 +2035,21 @@ public class BugreportProgressService extends Service { Log.i(TAG, "Deleting empty bugreport file: " + bugreportFile); bugreportFile.delete(); } - for (File file : screenshotFiles) { - if (file.length() == 0) { + deleteEmptyScreenshots(); + } + + /** + * Deletes empty screenshot files. + */ + private void deleteEmptyScreenshots() { + screenshotFiles.removeIf(file -> { + final long length = file.length(); + if (length == 0) { Log.i(TAG, "Deleting empty screenshot file: " + file); file.delete(); } - } + return length == 0; + }); } /** @@ -2006,7 +2057,8 @@ public class BugreportProgressService extends Service { * {@code initialName} if user has changed it. */ void renameScreenshots() { - if (TextUtils.isEmpty(name)) { + deleteEmptyScreenshots(); + if (TextUtils.isEmpty(name) || screenshotFiles.isEmpty()) { return; } final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size()); @@ -2025,7 +2077,7 @@ public class BugreportProgressService extends Service { if (newFile.length() > 0) { renamedFiles.add(newFile); } else if (newFile.delete()) { - Log.d(TAG, "screenshot file: " + newFile + "deleted successfully."); + Log.d(TAG, "screenshot file: " + newFile + " deleted successfully."); } } screenshotFiles = renamedFiles; diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index b8cfa1e80043..947691206741 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -25,19 +25,23 @@ import static com.android.shell.BugreportPrefs.STATE_SHOW; import static com.android.shell.BugreportPrefs.STATE_UNKNOWN; import static com.android.shell.BugreportPrefs.getWarningState; import static com.android.shell.BugreportPrefs.setWarningState; -import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT; -import static com.android.shell.BugreportProgressService.EXTRA_ID; -import static com.android.shell.BugreportProgressService.EXTRA_NAME; -import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT; -import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED; +import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_REQUESTED; +import static com.android.shell.BugreportProgressService.PROPERTY_LAST_ID; import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.app.ActivityManager; import android.app.ActivityManager.RunningServiceInfo; @@ -46,13 +50,18 @@ import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.BugreportManager; import android.os.Build; import android.os.Bundle; +import android.os.IDumpstate; +import android.os.IDumpstateListener; +import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.os.SystemProperties; import android.service.notification.StatusBarNotification; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.UiObjectNotFoundException; import android.text.TextUtils; import android.text.format.DateUtils; @@ -60,10 +69,12 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; +import androidx.test.rule.ServiceTestRule; import androidx.test.runner.AndroidJUnit4; import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener; +import libcore.io.IoUtils; import libcore.io.Streams; import org.junit.After; @@ -72,17 +83,19 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.SortedSet; @@ -92,10 +105,10 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** - * Integration tests for {@link BugreportReceiver}. + * Integration tests for {@link BugreportProgressService}. * <p> - * These tests don't mock any component and rely on external UI components (like the notification - * bar and activity chooser), which can make them unreliable and slow. + * These tests rely on external UI components (like the notificatio bar and activity chooser), + * which can make them unreliable and slow. * <p> * The general workflow is: * <ul> @@ -115,63 +128,48 @@ public class BugreportReceiverTest { // Timeout for UI operations, in milliseconds. private static final int TIMEOUT = (int) (5 * DateUtils.SECOND_IN_MILLIS); + // The default timeout is too short to verify the notification button state. Using a longer + // timeout in the tests. + private static final int SCREENSHOT_DELAY_SECONDS = 5; + // Timeout for when waiting for a screenshot to finish. private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10; - private static final String BUGREPORTS_DIR = "bugreports"; private static final String BUGREPORT_FILE = "test_bugreport.txt"; - private static final String ZIP_FILE = "test_bugreport.zip"; - private static final String ZIP_FILE2 = "test_bugreport2.zip"; private static final String SCREENSHOT_FILE = "test_screenshot.png"; - private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n"; private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n"; - private static final int PID = 42; - private static final int PID2 = 24; - private static final int ID = 108; - private static final int ID2 = 801; - private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress"; - private static final String MAX_PROPERTY = "dumpstate." + PID + ".max"; - private static final String NAME_PROPERTY = "dumpstate." + PID + ".name"; private static final String NAME = "BUG, Y U NO REPORT?"; - private static final String NAME2 = "A bugreport's life"; private static final String NEW_NAME = "Bug_Forrest_Bug"; - private static final String NEW_NAME2 = "BugsyReportsy"; private static final String TITLE = "Wimbugdom Champion 2015"; - private static final String TITLE2 = "Master of the Universe"; - private static final String DESCRIPTION = "One's description..."; - private static final String DESCRIPTION2 = "...is another's treasure."; - // TODO(b/143130523): Fix (update) tests and add to presubmit - private static final String EXTRA_MAX = "android.intent.extra.MAX"; - private static final String EXTRA_PID = "android.intent.extra.PID"; - private static final String INTENT_BUGREPORT_STARTED = - "com.android.internal.intent.action.BUGREPORT_STARTED"; private static final String NO_DESCRIPTION = null; private static final String NO_NAME = null; private static final String NO_SCREENSHOT = null; private static final String NO_TITLE = null; - private static final int NO_ID = 0; - private static final boolean RENAMED_SCREENSHOTS = true; - private static final boolean DIDNT_RENAME_SCREENSHOTS = false; private String mDescription; - - private String mPlainTextPath; - private String mZipPath; - private String mZipPath2; - private String mScreenshotPath; + private String mProgressTitle; + private int mBugreportId; private Context mContext; private UiBot mUiBot; private CustomActionSendMultipleListener mListener; + private BugreportProgressService mService; + private IDumpstateListener mIDumpstateListener; + private ParcelFileDescriptor mBugreportFd; + private ParcelFileDescriptor mScreenshotFd; + + @Mock private IDumpstate mMockIDumpstate; @Rule public TestName mName = new TestName(); + @Rule public ServiceTestRule mServiceRule = new ServiceTestRule(); @Before public void setUp() throws Exception { Log.i(TAG, getName() + ".setup()"); + MockitoAnnotations.initMocks(this); Instrumentation instrumentation = getInstrumentation(); mContext = instrumentation.getTargetContext(); mUiBot = new UiBot(instrumentation, TIMEOUT); @@ -179,15 +177,8 @@ public class BugreportReceiverTest { cancelExistingNotifications(); - mPlainTextPath = getPath(BUGREPORT_FILE); - mZipPath = getPath(ZIP_FILE); - mZipPath2 = getPath(ZIP_FILE2); - mScreenshotPath = getPath(SCREENSHOT_FILE); - createTextFile(mPlainTextPath, BUGREPORT_CONTENT); - createTextFile(mScreenshotPath, SCREENSHOT_CONTENT); - createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT); - createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT); - + mBugreportId = getBugreportId(); + mProgressTitle = getBugreportInProgress(mBugreportId); // Creates a multi-line description. StringBuilder sb = new StringBuilder(); for (int i = 1; i <= 20; i++) { @@ -195,6 +186,22 @@ public class BugreportReceiverTest { } mDescription = sb.toString(); + // Mocks BugreportManager and updates tests value to the service + mService = ((BugreportProgressService.LocalBinder) mServiceRule.bindService( + new Intent(mContext, BugreportProgressService.class))).getService(); + mService.mBugreportManager = new BugreportManager(mContext, mMockIDumpstate); + mService.mScreenshotDelaySec = SCREENSHOT_DELAY_SECONDS; + // Dup the fds which are passing to startBugreport function. + Mockito.doAnswer(invocation -> { + final boolean isScreenshotRequested = invocation.getArgument(6); + if (isScreenshotRequested) { + mScreenshotFd = ParcelFileDescriptor.dup(invocation.getArgument(3)); + } + mBugreportFd = ParcelFileDescriptor.dup(invocation.getArgument(2)); + return null; + }).when(mMockIDumpstate).startBugreport(anyInt(), any(), any(), any(), anyInt(), any(), + anyBoolean()); + setWarningState(mContext, STATE_HIDE); mUiBot.turnScreenOn(); @@ -203,6 +210,13 @@ public class BugreportReceiverTest { @After public void tearDown() throws Exception { Log.i(TAG, getName() + ".tearDown()"); + if (mBugreportFd != null) { + IoUtils.closeQuietly(mBugreportFd); + } + if (mScreenshotFd != null) { + IoUtils.closeQuietly(mScreenshotFd); + } + mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); try { cancelExistingNotifications(); } finally { @@ -219,131 +233,90 @@ public class BugreportReceiverTest { */ @Test public void testProgress() throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); + assertProgressNotification(mProgressTitle, 0f); - assertProgressNotification(NAME, 0f); - - SystemProperties.set(PROGRESS_PROPERTY, "108"); - assertProgressNotification(NAME, 10.80f); - - assertProgressNotification(NAME, 50.00f); - - SystemProperties.set(PROGRESS_PROPERTY, "950"); - assertProgressNotification(NAME, 95.00f); - - // Make sure progress never goes back... - SystemProperties.set(MAX_PROPERTY, "2000"); - assertProgressNotification(NAME, 95.00f); - - SystemProperties.set(PROGRESS_PROPERTY, "1000"); - assertProgressNotification(NAME, 95.00f); + mIDumpstateListener.onProgress(10); + assertProgressNotification(mProgressTitle, 10); - // ...only forward... - SystemProperties.set(PROGRESS_PROPERTY, "1902"); - assertProgressNotification(NAME, 95.10f); - - SystemProperties.set(PROGRESS_PROPERTY, "1960"); - assertProgressNotification(NAME, 98.00f); + mIDumpstateListener.onProgress(95); + assertProgressNotification(mProgressTitle, 95.00f); // ...but never more than the capped value. - SystemProperties.set(PROGRESS_PROPERTY, "2000"); - assertProgressNotification(NAME, 99.00f); + mIDumpstateListener.onProgress(200); + assertProgressNotification(mProgressTitle, 99); - SystemProperties.set(PROGRESS_PROPERTY, "3000"); - assertProgressNotification(NAME, 99.00f); + mIDumpstateListener.onProgress(300); + assertProgressNotification(mProgressTitle, 99); - Bundle extras = - sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, - NAME, NO_TITLE, NO_DESCRIPTION, 0, RENAMED_SCREENSHOTS); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras); assertServiceNotRunning(); } @Test public void testProgress_cancel() throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); - final NumberFormat nf = NumberFormat.getPercentInstance(); - nf.setMinimumFractionDigits(2); - nf.setMaximumFractionDigits(2); - - assertProgressNotification(NAME, 00.00f); + assertProgressNotification(mProgressTitle, 00.00f); - cancelFromNotification(); + cancelFromNotification(mProgressTitle); - waitForService(false); + assertServiceNotRunning(); } @Test public void testProgress_takeExtraScreenshot() throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); takeScreenshot(); assertScreenshotButtonEnabled(false); waitForScreenshotButtonEnabled(true); - sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath); - - Bundle extras = acceptBugreportAndGetSharedIntent(ID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, - NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 1); assertServiceNotRunning(); } @Test public void testScreenshotFinishesAfterBugreport() throws Exception { - resetProperties(); - - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); takeScreenshot(); - sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT); - waitShareNotification(ID); + sendBugreportFinished(); + waitShareNotification(mBugreportId); // There's no indication in the UI about the screenshot finish, so just sleep like a baby... sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS); - Bundle extras = acceptBugreportAndGetSharedIntent(ID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE, - NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS); + Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 1); assertServiceNotRunning(); } @Test public void testProgress_changeDetailsInvalidInput() throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME); - - // Check initial name. - detailsUi.assertName(NAME); + DetailsUi detailsUi = new DetailsUi(mBugreportId); - // Change name - it should have changed system property once focus is changed. + // Change name detailsUi.focusOnName(); detailsUi.nameField.setText(NEW_NAME); detailsUi.focusAwayFromName(); - assertPropertyValue(NAME_PROPERTY, NEW_NAME); - - // Cancel the dialog to make sure property was restored. - detailsUi.clickCancel(); - assertPropertyValue(NAME_PROPERTY, NAME); + detailsUi.clickOk(); // Now try to set an invalid name. - detailsUi.reOpen(NAME); + detailsUi.reOpen(NEW_NAME); detailsUi.nameField.setText("/etc/passwd"); detailsUi.clickOk(); - assertPropertyValue(NAME_PROPERTY, "_etc_passwd"); // Finally, make the real changes. detailsUi.reOpen("_etc_passwd"); @@ -353,27 +326,20 @@ public class BugreportReceiverTest { detailsUi.clickOk(); - assertPropertyValue(NAME_PROPERTY, NEW_NAME); assertProgressNotification(NEW_NAME, 00.00f); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, - mScreenshotPath, TITLE); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, - NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(TITLE); + assertActionSendMultiple(extras, NEW_NAME, TITLE, mDescription, 0); assertServiceNotRunning(); } @Test public void testProgress_cancelBugClosesDetailsDialog() throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME); - detailsUi.assertName(NAME); // Sanity check - - cancelFromNotification(); + cancelFromNotification(mProgressTitle); mUiBot.collapseStatusBar(); assertDetailsUiClosed(); @@ -381,40 +347,24 @@ public class BugreportReceiverTest { } @Test - public void testProgress_changeDetailsPlainBugreport() throws Exception { - changeDetailsTest(true); - } - - @Test - public void testProgress_changeDetailsZippedBugreport() throws Exception { - changeDetailsTest(false); - } - - private void changeDetailsTest(boolean plainText) throws Exception { - resetProperties(); - sendBugreportStarted(1000); + public void testProgress_changeDetailsTest() throws Exception { + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME); - - // Check initial name. - detailsUi.assertName(NAME); + DetailsUi detailsUi = new DetailsUi(mBugreportId); // Change fields. - detailsUi.reOpen(NAME); + detailsUi.reOpen(mProgressTitle); detailsUi.nameField.setText(NEW_NAME); detailsUi.titleField.setText(TITLE); detailsUi.descField.setText(mDescription); detailsUi.clickOk(); - assertPropertyValue(NAME_PROPERTY, NEW_NAME); assertProgressNotification(NEW_NAME, 00.00f); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, - plainText? mPlainTextPath : mZipPath, mScreenshotPath, TITLE); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, - NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(TITLE); + assertActionSendMultiple(extras, NEW_NAME, TITLE, mDescription, 0); assertServiceNotRunning(); } @@ -430,60 +380,18 @@ public class BugreportReceiverTest { } private void changeJustDetailsTest(boolean touchDetails) throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME, touchDetails); + DetailsUi detailsUi = new DetailsUi(mBugreportId, touchDetails); detailsUi.nameField.setText(""); detailsUi.titleField.setText(""); detailsUi.descField.setText(mDescription); detailsUi.clickOk(); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, - NO_NAME, NO_TITLE, mDescription, 0, DIDNT_RENAME_SCREENSHOTS); - - assertServiceNotRunning(); - } - - @Test - public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception { - resetProperties(); - sendBugreportStarted(ID, PID, NAME, 1000); - waitForScreenshotButtonEnabled(true); - - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME); - detailsUi.assertName(NAME); - detailsUi.assertTitle(""); - detailsUi.assertDescription(""); - assertTrue("didn't enable name on UI", detailsUi.nameField.isEnabled()); - detailsUi.nameField.setText(NEW_NAME); - detailsUi.titleField.setText(TITLE); - detailsUi.descField.setText(DESCRIPTION); - detailsUi.clickOk(); - - sendBugreportStarted(ID2, PID2, NAME2, 1000); - - sendBugreportFinished(ID, mZipPath, mScreenshotPath); - Bundle extras = acceptBugreportAndGetSharedIntent(TITLE); - - detailsUi = new DetailsUi(mUiBot, ID2, NAME2); - detailsUi.assertName(NAME2); - detailsUi.assertTitle(""); - detailsUi.assertDescription(""); - assertTrue("didn't enable name on UI", detailsUi.nameField.isEnabled()); - detailsUi.nameField.setText(NEW_NAME2); - detailsUi.titleField.setText(TITLE2); - detailsUi.descField.setText(DESCRIPTION2); - detailsUi.clickOk(); - - // Must use a different zip file otherwise it will fail because zip already contains - // title.txt and description.txt entries. - extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT, TITLE2); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2, - NEW_NAME2, TITLE2, DESCRIPTION2, 0, RENAMED_SCREENSHOTS); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras, NO_NAME, NO_TITLE, mDescription, 0); assertServiceNotRunning(); } @@ -507,26 +415,25 @@ public class BugreportReceiverTest { } private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception { - resetProperties(); - sendBugreportStarted(1000); + sendBugreportStarted(); if (waitScreenshot) { waitForScreenshotButtonEnabled(true); } - DetailsUi detailsUi = new DetailsUi(mUiBot, ID, NAME); + DetailsUi detailsUi = new DetailsUi(mBugreportId); // Finish the bugreport while user's still typing the name. detailsUi.nameField.setText(NEW_NAME); - sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath); + sendBugreportFinished(); // Wait until the share notification is received... - waitShareNotification(ID); + waitShareNotification(mBugreportId); // ...then close notification bar. mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); // Make sure UI was updated properly. assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled()); - assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString()); + assertNotEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText()); // Finish changing other fields. detailsUi.titleField.setText(TITLE); @@ -534,9 +441,8 @@ public class BugreportReceiverTest { detailsUi.clickOk(); // Finally, share bugreport. - Bundle extras = acceptBugreportAndGetSharedIntent(ID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, - NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS); + Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras, NO_NAME, TITLE, mDescription, 0); assertServiceNotRunning(); } @@ -569,11 +475,14 @@ public class BugreportReceiverTest { } // Send notification and click on share. - sendBugreportFinished(NO_ID, mPlainTextPath, null); - mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, NO_ID)); + sendBugreportStarted(); + waitForScreenshotButtonEnabled(true); + sendBugreportFinished(); + mUiBot.clickOnNotification(mContext.getString( + R.string.bugreport_finished_title, mBugreportId)); // Handle the warning - mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm)); + mUiBot.getObject(mContext.getString(R.string.bugreport_confirm)); // TODO: get ok and dontShowAgain from the dialog reference above UiObject dontShowAgain = mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat)); @@ -597,7 +506,7 @@ public class BugreportReceiverTest { // Share the bugreport. mUiBot.chooseActivity(UI_NAME); Bundle extras = mListener.getExtras(); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); + assertActionSendMultiple(extras); // Make sure it's hidden now. int newState = getWarningState(mContext, STATE_UNKNOWN); @@ -605,35 +514,37 @@ public class BugreportReceiverTest { } @Test - public void testShareBugreportAfterServiceDies() throws Exception { - sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT); - waitForService(false); - Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); - } + public void testBugreportFinished_withEmptyBugreportFile() throws Exception { + sendBugreportStarted(); - @Test - public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); - } + IoUtils.closeQuietly(mBugreportFd); + mBugreportFd = null; + sendBugreportFinished(); - @Test - public void testBugreportFinished_zippedBugreportAndScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); + assertServiceNotRunning(); } @Test - public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); + public void testShareBugreportAfterServiceDies() throws Exception { + sendBugreportStarted(); + waitForScreenshotButtonEnabled(true); + sendBugreportFinished(); + killService(); + assertServiceNotRunning(); + Bundle extras = acceptBugreportAndGetSharedIntent(mBugreportId); + assertActionSendMultiple(extras); } @Test - public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); + public void testBugreportRequestTwice_oneStartBugreportInvoked() throws Exception { + sendBugreportStarted(); + new BugreportRequestedReceiver().onReceive(mContext, + new Intent(INTENT_BUGREPORT_REQUESTED)); + getInstrumentation().waitForIdleSync(); + + verify(mMockIDumpstate, times(1)).startBugreport(anyInt(), any(), any(), any(), + anyInt(), any(), anyBoolean()); + sendBugreportFinished(); } private void cancelExistingNotifications() { @@ -664,10 +575,10 @@ public class BugreportReceiverTest { assertEquals("old notifications were not cancelled", 0, nm.getActiveNotifications().length); } - private void cancelFromNotification() { - openProgressNotification(NAME); - UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString( - com.android.internal.R.string.cancel).toUpperCase()); + private void cancelFromNotification(String name) { + openProgressNotification(name); + UiObject cancelButton = mUiBot.getObject(mContext.getString( + com.android.internal.R.string.cancel)); mUiBot.click(cancelButton, "cancel_button"); } @@ -676,67 +587,60 @@ public class BugreportReceiverTest { // TODO: need a way to get the ProgresBar from the "android:id/progress" UIObject... } - private UiObject openProgressNotification(String bugreportName) { - Log.v(TAG, "Looking for progress notification for '" + bugreportName + "'"); - return mUiBot.getNotification(bugreportName); - } - - void resetProperties() { - // TODO: call method to remove property instead - SystemProperties.set(PROGRESS_PROPERTY, "Reset"); - SystemProperties.set(MAX_PROPERTY, "Reset"); - SystemProperties.set(NAME_PROPERTY, "Reset"); + private void openProgressNotification(String title) { + Log.v(TAG, "Looking for progress notification for '" + title + "'"); + UiObject2 notification = mUiBot.getNotification2(title); + if (notification != null) { + mUiBot.expandNotification(notification); + } } /** - * Sends a "bugreport started" intent with the default values. + * Sends a "bugreport requested" intent with the default values. */ - private void sendBugreportStarted(int max) throws Exception { - sendBugreportStarted(ID, PID, NAME, max); - } - - private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception { - Intent intent = new Intent(INTENT_BUGREPORT_STARTED); - intent.setPackage("com.android.shell"); - intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(EXTRA_ID, id); - intent.putExtra(EXTRA_PID, pid); - intent.putExtra(EXTRA_NAME, name); - intent.putExtra(EXTRA_MAX, max); - mContext.sendBroadcast(intent); + private void sendBugreportStarted() throws Exception { + Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED); + // Ideally, we should invoke BugreportRequestedReceiver by sending + // INTENT_BUGREPORT_REQUESTED. But the intent has been protected broadcast by the system + // starting from S. + new BugreportRequestedReceiver().onReceive(mContext, intent); + + ArgumentCaptor<IDumpstateListener> listenerCap = ArgumentCaptor.forClass( + IDumpstateListener.class); + verify(mMockIDumpstate, timeout(TIMEOUT)).startBugreport(anyInt(), any(), any(), any(), + anyInt(), listenerCap.capture(), anyBoolean()); + mIDumpstateListener = listenerCap.getValue(); + assertNotNull("Dumpstate listener should not be null", mIDumpstateListener); + mIDumpstateListener.onProgress(0); } /** - * Sends a "bugreport finished" intent and waits for the result. + * Sends a "bugreport finished" event and waits for the result. * + * @param id The bugreport id for finished notification string title substitution. * @return extras sent in the shared intent. */ - private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath, - String screenshotPath) { - return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath); + private Bundle sendBugreportFinishedAndGetSharedIntent(int id) throws Exception { + sendBugreportFinished(); + return acceptBugreportAndGetSharedIntent(id); } /** - * Sends a "bugreport finished" intent and waits for the result. + * Sends a "bugreport finished" event and waits for the result. * + * @param notificationTitle The title of finished notification. * @return extras sent in the shared intent. */ - private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath, - String screenshotPath) { - sendBugreportFinished(id, bugreportPath, screenshotPath); - return acceptBugreportAndGetSharedIntent(id); - } - - // TODO: document / merge these 3 sendBugreportFinishedAndGetSharedIntent methods - private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath, - String screenshotPath, String notificationTitle) { - sendBugreportFinished(id, bugreportPath, screenshotPath); + private Bundle sendBugreportFinishedAndGetSharedIntent(String notificationTitle) + throws Exception { + sendBugreportFinished(); return acceptBugreportAndGetSharedIntent(notificationTitle); } /** * Accepts the notification to share the finished bugreport and waits for the result. * + * @param id The bugreport id for finished notification string title substitution. * @return extras sent in the shared intent. */ private Bundle acceptBugreportAndGetSharedIntent(int id) { @@ -744,7 +648,12 @@ public class BugreportReceiverTest { return acceptBugreportAndGetSharedIntent(notificationTitle); } - // TODO: document and/or merge these 2 acceptBugreportAndGetSharedIntent methods + /** + * Accepts the notification to share the finished bugreport and waits for the result. + * + * @param notificationTitle The title of finished notification. + * @return extras sent in the shared intent. + */ private Bundle acceptBugreportAndGetSharedIntent(String notificationTitle) { mUiBot.clickOnNotification(notificationTitle); mUiBot.chooseActivity(UI_NAME); @@ -759,53 +668,38 @@ public class BugreportReceiverTest { } /** - * Sends a "bugreport finished" intent. + * Callbacks to service to finish the bugreport. */ - private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) { - Intent intent = new Intent(INTENT_BUGREPORT_FINISHED); - intent.setPackage("com.android.shell"); - intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - if (id != NO_ID) { - intent.putExtra(EXTRA_ID, id); + private void sendBugreportFinished() throws Exception { + if (mBugreportFd != null) { + writeZipFile(mBugreportFd, BUGREPORT_FILE, BUGREPORT_CONTENT); } - if (bugreportPath != null) { - intent.putExtra(EXTRA_BUGREPORT, bugreportPath); + if (mScreenshotFd != null) { + writeScreenshotFile(mScreenshotFd, SCREENSHOT_CONTENT); } - if (screenshotPath != null) { - intent.putExtra(EXTRA_SCREENSHOT, screenshotPath); - } - - mContext.sendBroadcast(intent); + mIDumpstateListener.onFinished(); + getInstrumentation().waitForIdleSync(); } /** * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent. */ - private void assertActionSendMultiple(Bundle extras, String bugreportContent, - String screenshotContent) throws IOException { - assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE, - NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS); + private void assertActionSendMultiple(Bundle extras) throws IOException { + assertActionSendMultiple(extras, NO_NAME, NO_TITLE, NO_DESCRIPTION, 0); } /** * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent. * * @param extras extras received in the intent - * @param bugreportContent expected content in the bugreport file - * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any - * @param id emulated dumpstate id - * @param pid emulated dumpstate pid - * @param name expected subject * @param name bugreport name as provided by the user (or received by dumpstate) * @param title bugreport name as provided by the user * @param description bugreport description as provided by the user * @param numberScreenshots expected number of screenshots taken by Shell. - * @param renamedScreenshots whether the screenshots are expected to be renamed */ - private void assertActionSendMultiple(Bundle extras, String bugreportContent, - String screenshotContent, int id, int pid, String subject, - String name, String title, String description, - int numberScreenshots, boolean renamedScreenshots) throws IOException { + private void assertActionSendMultiple(Bundle extras, String name, String title, + String description, int numberScreenshots) + throws IOException { String body = extras.getString(Intent.EXTRA_TEXT); assertContainsRegex("missing build info", SystemProperties.get("ro.build.description"), body); @@ -815,11 +709,21 @@ public class BugreportReceiverTest { assertContainsRegex("missing description", description, body); } - assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT)); + final String extrasSubject = extras.getString(Intent.EXTRA_SUBJECT); + if (title != null) { + assertEquals("wrong subject", title, extrasSubject); + } else { + if (name != null) { + assertEquals("wrong subject", getBugreportName(name), extrasSubject); + } else { + assertTrue("wrong subject", extrasSubject.startsWith( + getBugreportPrefixName())); + } + } List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM); int expectedNumberScreenshots = numberScreenshots; - if (screenshotContent != null) { + if (getScreenshotContent() != null) { expectedNumberScreenshots ++; // Add screenshot received by dumpstate } int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file @@ -858,7 +762,7 @@ public class BugreportReceiverTest { } } // Check external screenshot - if (screenshotContent != null) { + if (getScreenshotContent() != null) { assertNotNull("did not get .png attachment for external screenshot", externalScreenshotUri); assertContent(externalScreenshotUri, SCREENSHOT_CONTENT); @@ -866,17 +770,18 @@ public class BugreportReceiverTest { assertNull("should not have .png attachment for external screenshot", externalScreenshotUri); } - // Check internal screenshots. - SortedSet<String> expectedNames = new TreeSet<>(); - for (int i = 1 ; i <= numberScreenshots; i++) { - String prefix = renamedScreenshots ? name : Integer.toString(pid); - String expectedName = "screenshot-" + prefix + "-" + i + ".png"; - expectedNames.add(expectedName); + // Check internal screenshots' file names. + if (name != null) { + SortedSet<String> expectedNames = new TreeSet<>(); + for (int i = 1; i <= numberScreenshots; i++) { + String expectedName = "screenshot-" + name + "-" + i + ".png"; + expectedNames.add(expectedName); + } + // Ideally we should use MoreAsserts, but the error message in case of failure is not + // really useful. + assertEquals("wrong names for internal screenshots", + expectedNames, internalScreenshotNames); } - // Ideally we should use MoreAsserts, but the error message in case of failure is not - // really useful. - assertEquals("wrong names for internal screenshots", - expectedNames, internalScreenshotNames); } private void assertContent(Uri uri, String expectedContent) throws IOException { @@ -909,28 +814,9 @@ public class BugreportReceiverTest { fail("Did not find entry '" + entryName + "' on file '" + uri + "'"); } - private void assertPropertyValue(String key, String expectedValue) { - // Since the property is set in a different thread by BugreportProgressService, we need to - // poll it a couple times... - - for (int i = 1; i <= 5; i++) { - String actualValue = SystemProperties.get(key); - if (expectedValue.equals(actualValue)) { - return; - } - Log.d(TAG, "Value of property " + key + " (" + actualValue - + ") does not match expected value (" + expectedValue - + ") on attempt " + i + ". Sleeping before next attempt..."); - sleep(1000); - } - // Final try... - String actualValue = SystemProperties.get(key); - assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue); - } - private void assertServiceNotRunning() { - String service = BugreportProgressService.class.getName(); - assertFalse("Service '" + service + "' is still running", isServiceRunning(service)); + mServiceRule.unbindService(); + waitForService(false); } private boolean isServiceRunning(String name) { @@ -962,7 +848,7 @@ public class BugreportReceiverTest { private void killService() { String service = BugreportProgressService.class.getName(); - + mServiceRule.unbindService(); if (!isServiceRunning(service)) return; Log.w(TAG, "Service '" + service + "' is still running, killing it"); @@ -980,18 +866,19 @@ public class BugreportReceiverTest { } } - private void createTextFile(String path, String content) throws IOException { - Log.v(TAG, "createFile(" + path + ")"); + private void writeScreenshotFile(ParcelFileDescriptor fd, String content) throws IOException { + Log.v(TAG, "writeScreenshotFile(" + fd + ")"); try (Writer writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(path)))) { + new FileOutputStream(fd.getFileDescriptor())))) { writer.write(content); } } - private void createZipFile(String path, String entryName, String content) throws IOException { - Log.v(TAG, "createZipFile(" + path + ", " + entryName + ")"); + private void writeZipFile(ParcelFileDescriptor fd, String entryName, String content) + throws IOException { + Log.v(TAG, "writeZipFile(" + fd + ", " + entryName + ")"); try (ZipOutputStream zos = new ZipOutputStream( - new BufferedOutputStream(new FileOutputStream(path)))) { + new BufferedOutputStream(new FileOutputStream(fd.getFileDescriptor())))) { ZipEntry entry = new ZipEntry(entryName); zos.putNextEntry(entry); byte[] data = content.getBytes(); @@ -1000,25 +887,13 @@ public class BugreportReceiverTest { } } - private String getPath(String file) { - final File rootDir = mContext.getFilesDir(); - final File dir = new File(rootDir, BUGREPORTS_DIR); - if (!dir.exists()) { - Log.i(TAG, "Creating directory " + dir); - assertTrue("Could not create directory " + dir, dir.mkdir()); - } - String path = new File(dir, file).getAbsolutePath(); - Log.v(TAG, "Path for '" + file + "': " + path); - return path; - } - /** * Gets the notification button used to take a screenshot. */ private UiObject getScreenshotButton() { - openProgressNotification(NAME); - return mUiBot.getVisibleObject( - mContext.getString(R.string.bugreport_screenshot_action).toUpperCase()); + openProgressNotification(mProgressTitle); + return mUiBot.getObject( + mContext.getString(R.string.bugreport_screenshot_action)); } /** @@ -1072,12 +947,36 @@ public class BugreportReceiverTest { Log.d(TAG, "woke up"); } + private int getBugreportId() { + return SystemProperties.getInt(PROPERTY_LAST_ID, 1); + } + + private String getBugreportInProgress(int bugreportId) { + return mContext.getString(R.string.bugreport_in_progress_title, bugreportId); + } + + private String getBugreportPrefixName() { + String buildId = SystemProperties.get("ro.build.id", "UNKNOWN_BUILD"); + String deviceName = SystemProperties.get("ro.product.name", "UNKNOWN_DEVICE"); + return String.format("bugreport-%s-%s", deviceName, buildId); + } + + private String getBugreportName(String name) { + return String.format("%s-%s.zip", getBugreportPrefixName(), name); + } + + private String getScreenshotContent() { + if (mScreenshotFd == null) { + return NO_SCREENSHOT; + } + return SCREENSHOT_CONTENT; + } + /** * Helper class containing the UiObjects present in the bugreport info dialog. */ private final class DetailsUi { - final UiObject detailsButton; final UiObject nameField; final UiObject titleField; final UiObject descField; @@ -1088,10 +987,9 @@ public class BugreportReceiverTest { * Gets the UI objects by opening the progress notification and clicking on DETAILS. * * @param id bugreport id - * @param id bugreport name */ - DetailsUi(UiBot uiBot, int id, String name) throws UiObjectNotFoundException { - this(uiBot, id, name, true); + DetailsUi(int id) throws UiObjectNotFoundException { + this(id, true); } /** @@ -1099,13 +997,12 @@ public class BugreportReceiverTest { * the notification itself. * * @param id bugreport id - * @param id bugreport name */ - DetailsUi(UiBot uiBot, int id, String name, boolean clickDetails) - throws UiObjectNotFoundException { - final UiObject notification = openProgressNotification(name); - detailsButton = mUiBot.getVisibleObject(mContext.getString( - R.string.bugreport_info_action).toUpperCase()); + DetailsUi(int id, boolean clickDetails) throws UiObjectNotFoundException { + openProgressNotification(mProgressTitle); + final UiObject notification = mUiBot.getObject(mProgressTitle); + final UiObject detailsButton = mUiBot.getObject(mContext.getString( + R.string.bugreport_info_action)); if (clickDetails) { mUiBot.click(detailsButton, "details_button"); @@ -1123,24 +1020,6 @@ public class BugreportReceiverTest { cancelButton = mUiBot.getObjectById("android:id/button2"); } - private void assertField(String name, UiObject field, String expected) - throws UiObjectNotFoundException { - String actual = field.getText().toString(); - assertEquals("Wrong value on field '" + name + "'", expected, actual); - } - - void assertName(String expected) throws UiObjectNotFoundException { - assertField("name", nameField, expected); - } - - void assertTitle(String expected) throws UiObjectNotFoundException { - assertField("title", titleField, expected); - } - - void assertDescription(String expected) throws UiObjectNotFoundException { - assertField("description", descField, expected); - } - /** * Set focus on the name field so it can be validated once focus is lost. */ @@ -1159,6 +1038,8 @@ public class BugreportReceiverTest { void reOpen(String name) { openProgressNotification(name); + final UiObject detailsButton = mUiBot.getObject(mContext.getString( + R.string.bugreport_info_action)); mUiBot.click(detailsButton, "details_button"); } diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java index e8397659e692..53b124ff9c4c 100644 --- a/packages/Shell/tests/src/com/android/shell/UiBot.java +++ b/packages/Shell/tests/src/com/android/shell/UiBot.java @@ -18,17 +18,23 @@ package com.android.shell; import android.app.Instrumentation; import android.app.StatusBarManager; +import android.os.SystemClock; import android.support.test.uiautomator.By; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiSelector; import android.support.test.uiautomator.Until; +import android.text.format.DateUtils; import android.util.Log; import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; +import java.util.List; + /** * A helper class for UI-related testing tasks. */ @@ -36,6 +42,9 @@ final class UiBot { private static final String TAG = "UiBot"; private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; + private static final String ANDROID_PACKAGE = "android"; + + private static final long SHORT_UI_TIMEOUT_MS = (3 * DateUtils.SECOND_IN_MILLIS); private final Instrumentation mInstrumentation; private final UiDevice mDevice; @@ -48,9 +57,9 @@ final class UiBot { } /** - * Opens the system notification and gets a given notification. + * Opens the system notification and gets a UiObject with the text. * - * @param text Notificaton's text as displayed by the UI. + * @param text Notification's text as displayed by the UI. * @return notification object. */ public UiObject getNotification(String text) { @@ -62,6 +71,43 @@ final class UiBot { return getObject(text); } + /** + * Opens the system notification and gets a notification containing the text. + * + * @param text Notification's text as displayed by the UI. + * @return notification object. + */ + public UiObject2 getNotification2(String text) { + boolean opened = mDevice.openNotification(); + Log.v(TAG, "openNotification(): " + opened); + final UiObject2 notificationScroller = mDevice.wait(Until.findObject( + By.res(SYSTEMUI_PACKAGE, "notification_stack_scroller")), mTimeout); + assertNotNull("could not get notification stack scroller", notificationScroller); + final List<UiObject2> notificationList = notificationScroller.getChildren(); + for (UiObject2 notification: notificationList) { + final UiObject2 notificationText = notification.findObject(By.textContains(text)); + if (notificationText != null) { + return notification; + } + } + return null; + } + + /** + * Expands the notification. + * + * @param notification The notification object returned by {@link #getNotification2(String)}. + */ + public void expandNotification(UiObject2 notification) { + final UiObject2 expandBtn = notification.findObject( + By.res(ANDROID_PACKAGE, "expand_button")); + if (expandBtn.getContentDescription().equals("Collapse")) { + return; + } + expandBtn.click(); + mDevice.waitForIdle(); + } + public void collapseStatusBar() throws Exception { // TODO: mDevice should provide such method.. StatusBarManager sbm = @@ -162,6 +208,12 @@ final class UiBot { */ public void chooseActivity(String name) { // It uses an intent chooser now, so just getting the activity by text is enough... + final String share = mInstrumentation.getContext().getString( + com.android.internal.R.string.share); + boolean gotIt = mDevice.wait(Until.hasObject(By.text(share)), mTimeout); + assertTrue("could not get share activity (" + share + ")", gotIt); + swipeUp(); + SystemClock.sleep(SHORT_UI_TIMEOUT_MS); UiObject activity = getObject(name); click(activity, name); } @@ -173,6 +225,11 @@ final class UiBot { public void turnScreenOn() throws Exception { mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); mDevice.executeShellCommand("wm dismiss-keyguard"); + mDevice.waitForIdle(); } + public void swipeUp() { + mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() * 3 / 4, + mDevice.getDisplayWidth() / 2, 0, 30); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..57e656827f1c 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,12 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +101,27 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } diff --git a/services/Android.bp b/services/Android.bp index f40f7cfa7321..ef52c2aff002 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -83,7 +83,6 @@ java_library { "services.voiceinteraction", "services.wifi", "service-blobstore", - "service-connectivity", "service-jobscheduler", "android.hidl.base-V1.0-java", ], diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index a704c58a9b70..66bbf66e88db 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -372,7 +372,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind checkArgument(getCallingUserId() == userId, "Must be called by either same user or system"); - mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg); + int callingUid = Binder.getCallingUid(); + if (mAppOpsManager.checkPackage(callingUid, pkg) != AppOpsManager.MODE_ALLOWED) { + throw new SecurityException(pkg + " doesn't belong to uid " + callingUid); + } } @Override diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 26c0e59cb885..164ce615bff1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -74,7 +74,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.res.Configuration; import android.database.ContentObserver; import android.net.CaptivePortal; import android.net.CaptivePortalData; @@ -95,7 +94,6 @@ import android.net.INetworkManagementEventObserver; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; -import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.ISocketKeepaliveCallback; import android.net.InetAddresses; @@ -173,8 +171,8 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.Xml; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -189,7 +187,6 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; -import com.android.internal.util.XmlUtils; import com.android.modules.utils.BasicShellCommandHandler; import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; import com.android.net.module.util.LinkPropertiesUtils.CompareResult; @@ -220,14 +217,7 @@ import com.google.android.collect.Lists; import libcore.io.IoUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; import java.io.FileDescriptor; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; import java.io.PrintWriter; import java.net.Inet4Address; import java.net.InetAddress; @@ -336,7 +326,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @VisibleForTesting protected INetd mNetd; private INetworkStatsService mStatsService; - private INetworkPolicyManager mPolicyManager; + private NetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; /** @@ -945,15 +935,15 @@ public class ConnectivityService extends IConnectivityManager.Stub } public ConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService, INetworkPolicyManager policyManager) { - this(context, netManager, statsService, policyManager, getDnsResolver(context), - new IpConnectivityLog(), NetdService.getInstance(), new Dependencies()); + INetworkStatsService statsService) { + this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(), + NetdService.getInstance(), new Dependencies()); } @VisibleForTesting protected ConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService, INetworkPolicyManager policyManager, - IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) { + INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger, + INetd netd, Dependencies deps) { if (DBG) log("ConnectivityService starting up"); mDeps = Objects.requireNonNull(deps, "missing Dependencies"); @@ -991,7 +981,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService"); mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService"); - mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager"); + mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); mPolicyManagerInternal = Objects.requireNonNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); @@ -1007,12 +997,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // To ensure uid rules are synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService // reading existing policy from disk. - try { - mPolicyManager.registerListener(mPolicyListener); - } catch (RemoteException e) { - // ouch, no rules updates means some processes may never get network - loge("unable to register INetworkPolicyListener" + e); - } + mPolicyManager.registerListener(mPolicyListener); final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); @@ -2007,7 +1992,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void handleRestrictBackgroundChanged(boolean restrictBackground) { if (mRestrictBackground == restrictBackground) return; - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean curMetered = nai.networkCapabilities.isMetered(); maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, restrictBackground); @@ -2715,7 +2700,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private NetworkAgentInfo[] networksSortedById() { NetworkAgentInfo[] networks = new NetworkAgentInfo[0]; - networks = mNetworkAgentInfos.values().toArray(networks); + networks = mNetworkAgentInfos.toArray(networks); Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId())); return networks; } @@ -2761,11 +2746,6 @@ public class ConnectivityService extends IConnectivityManager.Stub handleAsyncChannelHalfConnect(msg); break; } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai != null) nai.asyncChannel.disconnect(); - break; - } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { handleAsyncChannelDisconnected(msg); break; @@ -2775,8 +2755,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void maybeHandleNetworkAgentMessage(Message msg) { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai == null) { + final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj; + final NetworkAgentInfo nai = arg.first; + if (!mNetworkAgentInfos.contains(nai)) { if (VDBG) { log(String.format("%s from unknown NetworkAgent", eventName(msg.what))); } @@ -2785,7 +2766,7 @@ public class ConnectivityService extends IConnectivityManager.Stub switch (msg.what) { case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { - NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj; + NetworkCapabilities networkCapabilities = (NetworkCapabilities) arg.second; if (networkCapabilities.hasConnectivityManagedCapability()) { Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability."); } @@ -2802,13 +2783,13 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: { - LinkProperties newLp = (LinkProperties) msg.obj; + LinkProperties newLp = (LinkProperties) arg.second; processLinkPropertiesFromAgent(nai, newLp); handleUpdateLinkProperties(nai, newLp); break; } case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: { - NetworkInfo info = (NetworkInfo) msg.obj; + NetworkInfo info = (NetworkInfo) arg.second; updateNetworkInfo(nai, info); break; } @@ -2833,7 +2814,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_SOCKET_KEEPALIVE: { - mKeepaliveTracker.handleEventSocketKeepalive(nai, msg); + mKeepaliveTracker.handleEventSocketKeepalive(nai, msg.arg1, msg.arg2); break; } case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: { @@ -2844,7 +2825,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final ArrayList<Network> underlying; try { - underlying = ((Bundle) msg.obj).getParcelableArrayList( + underlying = ((Bundle) arg.second).getParcelableArrayList( NetworkAgent.UNDERLYING_NETWORKS_KEY); } catch (NullPointerException | ClassCastException e) { break; @@ -2923,8 +2904,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.toShortString()); - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); teardownUnneededNetwork(nai); break; } @@ -3016,13 +2996,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } updateInetCondition(nai); // Let the NetworkAgent know the state of its network - Bundle redirectUrlBundle = new Bundle(); - redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl); // TODO: Evaluate to update partial connectivity to status to NetworkAgent. - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_REPORT_NETWORK_STATUS, - (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), - 0, redirectUrlBundle); + nai.onValidationStatusChanged( + valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK, + redirectUrl); // If NetworkMonitor detects partial connectivity before // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification @@ -3056,6 +3033,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } break; } + case NetworkAgentInfo.EVENT_AGENT_REGISTERED: { + handleNetworkAgentRegistered(msg); + break; + } + case NetworkAgentInfo.EVENT_AGENT_DISCONNECTED: { + handleNetworkAgentDisconnected(msg); + break; + } } return true; } @@ -3232,7 +3217,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handlePrivateDnsSettingsChanged() { final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { handlePerNetworkPrivateDnsConfig(nai, cfg); if (networkRequiresPrivateDnsValidation(nai)) { handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); @@ -3330,7 +3315,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleAsyncChannelHalfConnect(Message msg) { ensureRunningOnConnectivityServiceThread(); - final AsyncChannel ac = (AsyncChannel) msg.obj; if (mNetworkProviderInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); @@ -3342,39 +3326,45 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Error connecting NetworkFactory"); mNetworkProviderInfos.remove(msg.obj); } - } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) log("NetworkAgent connected"); - // A network agent has requested a connection. Establish the connection. - mNetworkAgentInfos.get(msg.replyTo).asyncChannel. - sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - } else { - loge("Error connecting NetworkAgent"); - NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); - if (nai != null) { - final boolean wasDefault = isDefaultNetwork(nai); - synchronized (mNetworkForNetId) { - mNetworkForNetId.remove(nai.network.getNetId()); - } - mNetIdManager.releaseNetId(nai.network.getNetId()); - // Just in case. - mLegacyTypeTracker.remove(nai, wasDefault); + } + } + + private void handleNetworkAgentRegistered(Message msg) { + final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj; + if (!mNetworkAgentInfos.contains(nai)) { + return; + } + + if (msg.arg1 == NetworkAgentInfo.ARG_AGENT_SUCCESS) { + if (VDBG) log("NetworkAgent registered"); + } else { + loge("Error connecting NetworkAgent"); + mNetworkAgentInfos.remove(nai); + if (nai != null) { + final boolean wasDefault = isDefaultNetwork(nai); + synchronized (mNetworkForNetId) { + mNetworkForNetId.remove(nai.network.getNetId()); } + mNetIdManager.releaseNetId(nai.network.getNetId()); + // Just in case. + mLegacyTypeTracker.remove(nai, wasDefault); } } } - // This is a no-op if it's called with a message designating a network that has + private void handleNetworkAgentDisconnected(Message msg) { + NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj; + if (mNetworkAgentInfos.contains(nai)) { + disconnectAndDestroyNetwork(nai); + } + } + + // This is a no-op if it's called with a message designating a provider that has // already been destroyed, because its reference will not be found in the relevant // maps. private void handleAsyncChannelDisconnected(Message msg) { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai != null) { - disconnectAndDestroyNetwork(nai); - } else { - NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); - if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); - } + NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); + if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); } // Destroys a network, remove references to it from the internal state managed by @@ -3418,7 +3408,7 @@ public class ConnectivityService extends IConnectivityManager.Stub wakeupModifyInterface(iface, nai.networkCapabilities, false); } nai.networkMonitor().notifyNetworkDisconnected(); - mNetworkAgentInfos.remove(nai.messenger); + mNetworkAgentInfos.remove(nai); nai.clatd.update(); synchronized (mNetworkForNetId) { // Remove the NetworkAgent, but don't mark the netId as @@ -3526,7 +3516,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRequests.put(nri.request, nri); mNetworkRequestInfoLogs.log("REGISTER " + nri); if (nri.request.isListen()) { - for (NetworkAgentInfo network : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo network : mNetworkAgentInfos) { if (nri.request.networkCapabilities.hasSignalStrength() && network.satisfiesImmutableCapabilitiesOf(nri.request)) { updateSignalStrengthThresholds(network, "REGISTER", nri.request); @@ -3591,8 +3581,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean isNetworkPotentialSatisfier( @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) { // listen requests won't keep up a network satisfying it. If this is not a multilayer - // request, we can return immediately. For multilayer requests, we have to check to see if - // any of the multilayer requests may have a potential satisfier. + // request, return immediately. For multilayer requests, check to see if any of the + // multilayer requests may have a potential satisfier. if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) { return false; } @@ -3742,7 +3732,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { // listens don't have a singular affectedNetwork. Check all networks to see // if this listen request applies and remove it. - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { nai.removeRequest(nri.request.requestId); if (nri.request.networkCapabilities.hasSignalStrength() && nai.satisfiesImmutableCapabilitiesOf(nri.request)) { @@ -3815,13 +3805,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (always) { - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept)); + nai.onSaveAcceptUnvalidated(accept); } if (!accept) { // Tell the NetworkAgent to not automatically reconnect to the network. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // Teardown the network. teardownUnneededNetwork(nai); } @@ -3852,13 +3841,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Use the current design or save the user choice into IpMemoryStore. if (always) { - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept)); + nai.onSaveAcceptUnvalidated(accept); } if (!accept) { // Tell the NetworkAgent to not automatically reconnect to the network. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // Tear down the network. teardownUnneededNetwork(nai); } else { @@ -3996,7 +3984,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void rematchForAvoidBadWifiUpdate() { rematchAllNetworksAndRequests(); - for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai: mNetworkAgentInfos) { if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { sendUpdatedScoreToFactories(nai); } @@ -4139,7 +4127,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // to a network that provides no or limited connectivity is not useful, because the user // cannot use that network except through the notification shown by this method, and the // notification is only shown if the network is explicitly selected by the user. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when // NetworkMonitor detects the network is partial connectivity. Need to change the design to @@ -4789,7 +4777,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return new VpnInfo[0]; } List<VpnInfo> infoList = new ArrayList<>(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { VpnInfo info = createVpnInfo(nai); if (info != null) { infoList.add(info); @@ -4890,7 +4878,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) { ensureRunningOnConnectivityServiceThread(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) { updateCapabilitiesForNetwork(nai); } @@ -5081,101 +5069,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public int checkMobileProvisioning(int suggestedTimeOutMs) { - // TODO: Remove? Any reason to trigger a provisioning check? - return -1; - } - - /** Location to an updatable file listing carrier provisioning urls. - * An example: - * - * <?xml version="1.0" encoding="utf-8"?> - * <provisioningUrls> - * <provisioningUrl mcc="310" mnc="4">http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s</provisioningUrl> - * </provisioningUrls> - */ - private static final String PROVISIONING_URL_PATH = - "/data/misc/radio/provisioning_urls.xml"; - private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH); - - /** XML tag for root element. */ - private static final String TAG_PROVISIONING_URLS = "provisioningUrls"; - /** XML tag for individual url */ - private static final String TAG_PROVISIONING_URL = "provisioningUrl"; - /** XML attribute for mcc */ - private static final String ATTR_MCC = "mcc"; - /** XML attribute for mnc */ - private static final String ATTR_MNC = "mnc"; - - private String getProvisioningUrlBaseFromFile() { - XmlPullParser parser; - Configuration config = mContext.getResources().getConfiguration(); - - try (FileReader fileReader = new FileReader(mProvisioningUrlFile)) { - parser = Xml.newPullParser(); - parser.setInput(fileReader); - XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); - - while (true) { - XmlUtils.nextElement(parser); - - String element = parser.getName(); - if (element == null) break; - - if (element.equals(TAG_PROVISIONING_URL)) { - String mcc = parser.getAttributeValue(null, ATTR_MCC); - try { - if (mcc != null && Integer.parseInt(mcc) == config.mcc) { - String mnc = parser.getAttributeValue(null, ATTR_MNC); - if (mnc != null && Integer.parseInt(mnc) == config.mnc) { - parser.next(); - if (parser.getEventType() == XmlPullParser.TEXT) { - return parser.getText(); - } - } - } - } catch (NumberFormatException e) { - loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e); - } - } - } - return null; - } catch (FileNotFoundException e) { - loge("Carrier Provisioning Urls file not found"); - } catch (XmlPullParserException e) { - loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); - } catch (IOException e) { - loge("I/O exception reading Carrier Provisioning Urls file: " + e); - } - return null; - } - - @Override - public String getMobileProvisioningUrl() { - enforceSettingsPermission(); - String url = getProvisioningUrlBaseFromFile(); - if (TextUtils.isEmpty(url)) { - url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); - } else { - log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); - } - // populate the iccid, imei and phone number in the provisioning url. - if (!TextUtils.isEmpty(url)) { - String phoneNumber = mTelephonyManager.getLine1Number(); - if (TextUtils.isEmpty(phoneNumber)) { - phoneNumber = "0000000000"; - } - url = String.format(url, - mTelephonyManager.getSimSerialNumber() /* ICCID */, - mTelephonyManager.getDeviceId() /* IMEI */, - phoneNumber /* Phone number */); - } - - return url; - } - - @Override public void setProvisioningNotificationVisible(boolean visible, int networkType, String action) { enforceSettingsPermission(); @@ -5591,7 +5484,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mAppOpsManager.checkPackage(callerUid, callerPackageName); } - private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { + private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { final SortedSet<Integer> thresholds = new TreeSet<>(); synchronized (nai) { for (final NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -5603,14 +5496,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - return new ArrayList<>(thresholds); + // TODO: use NetworkStackUtils.convertToIntArray after moving it + return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds)); } private void updateSignalStrengthThresholds( NetworkAgentInfo nai, String reason, NetworkRequest request) { - ArrayList<Integer> thresholdsArray = getSignalStrengthThresholds(nai); - Bundle thresholds = new Bundle(); - thresholds.putIntegerArrayList("thresholds", thresholdsArray); + final int[] thresholdsArray = getSignalStrengthThresholds(nai); if (VDBG || (DBG && !"CONNECT".equals(reason))) { String detail; @@ -5620,12 +5512,10 @@ public class ConnectivityService extends IConnectivityManager.Stub detail = reason; } log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s", - detail, Arrays.toString(thresholdsArray.toArray()), nai.toShortString())); + detail, Arrays.toString(thresholdsArray), nai.toShortString())); } - nai.asyncChannel.sendMessage( - android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, - 0, 0, thresholds); + nai.onSignalStrengthThresholdsUpdated(thresholdsArray); } private void ensureValidNetworkSpecifier(NetworkCapabilities nc) { @@ -5735,7 +5625,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai = mNetworkForNetId.get(network.getNetId()); } if (nai != null) { - nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE); + nai.onBandwidthUpdateRequested(); synchronized (mBandwidthRequests) { final int uid = mDeps.getCallingUid(); Integer uidReqs = mBandwidthRequests.get(uid); @@ -5978,7 +5868,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // NetworkAgentInfo keyed off its connecting messenger // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays // NOTE: Only should be accessed on ConnectivityServiceThread, except dump(). - private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = new HashMap<>(); + private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>(); @GuardedBy("mBlockedAppUids") private final HashSet<Integer> mBlockedAppUids = new HashSet<>(); @@ -6026,17 +5916,17 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Register a new agent. {@see #registerNetworkAgent} below. */ - public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig) { - return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, + return registerNetworkAgent(na, networkInfo, linkProperties, networkCapabilities, currentScore, networkAgentConfig, NetworkProvider.ID_NONE); } /** * Register a new agent with ConnectivityService to handle a network. * - * @param messenger a messenger for ConnectivityService to contact the agent asynchronously. + * @param na a reference for ConnectivityService to contact the agent asynchronously. * @param networkInfo the initial info associated with this network. It can be updated later : * see {@link #updateNetworkInfo}. * @param linkProperties the initial link properties of this network. They can be updated @@ -6049,7 +5939,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param providerId the ID of the provider owning this NetworkAgent. * @return the network created for this agent. */ - public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { @@ -6061,14 +5951,14 @@ public class ConnectivityService extends IConnectivityManager.Stub final int uid = mDeps.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - return registerNetworkAgentInternal(messenger, networkInfo, linkProperties, + return registerNetworkAgentInternal(na, networkInfo, linkProperties, networkCapabilities, currentScore, networkAgentConfig, providerId, uid); } finally { Binder.restoreCallingIdentity(token); } } - private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo, + private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) { if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { @@ -6084,7 +5974,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network // satisfies mDefaultRequest. final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); - final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), + final NetworkAgentInfo nai = new NetworkAgentInfo(na, new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this, mNetd, mDnsResolver, mNMS, providerId, uid); @@ -6102,7 +5992,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.network, name, new NetworkMonitorCallbacks(nai)); // NetworkAgentInfo registration will finish when the NetworkMonitor is created. // If the network disconnects or sends any other event before that, messages are deferred by - // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the + // NetworkAgent until nai.connect(), which will be called when finalizing the // registration. return nai.network; } @@ -6110,7 +6000,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { nai.onNetworkMonitorCreated(networkMonitor); if (VDBG) log("Got NetworkAgent Messenger"); - mNetworkAgentInfos.put(nai.messenger, nai); + mNetworkAgentInfos.add(nai); synchronized (mNetworkForNetId) { mNetworkForNetId.put(nai.network.getNetId(), nai); } @@ -6120,7 +6010,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } catch (RemoteException e) { e.rethrowAsRuntimeException(); } - nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger); + nai.notifyRegistered(); NetworkInfo networkInfo = nai.networkInfo; updateNetworkInfo(nai, networkInfo); updateUids(nai, null, nai.networkCapabilities); @@ -6933,7 +6823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } } - nai.asyncChannel.disconnect(); + nai.disconnect(); } private void handleLingerComplete(NetworkAgentInfo oldNetwork) { @@ -7123,7 +7013,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Gather the list of all relevant agents and sort them by score. final ArrayList<NetworkAgentInfo> nais = new ArrayList<>(); - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { if (!nai.everConnected) continue; nais.add(nai); } @@ -7158,7 +7048,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void applyNetworkReassignment(@NonNull final NetworkReassignment changes, final long now) { - final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos.values(); + final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos; // Since most of the time there are only 0 or 1 background networks, it would probably // be more efficient to just use an ArrayList here. TODO : measure performance @@ -7251,7 +7141,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais); // Tear down all unneeded networks. - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (nai.getLingerExpiry() > 0) { // This network has active linger timers and no requests, but is not @@ -7488,7 +7378,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // This has to happen after matching the requests, because callbacks are just requests. notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); } else if (state == NetworkInfo.State.DISCONNECTED) { - networkAgent.asyncChannel.disconnect(); + networkAgent.disconnect(); if (networkAgent.isVPN()) { updateUids(networkAgent, networkAgent.networkCapabilities, null); } @@ -7576,7 +7466,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param newRules The new rules to apply. */ private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) { - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean metered = nai.networkCapabilities.isMetered(); final boolean oldBlocked, newBlocked; // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid @@ -7682,7 +7572,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureRunningOnConnectivityServiceThread(); ArrayList<Network> defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) { defaultNetworks.add(nai.network); } @@ -8233,6 +8123,13 @@ public class ConnectivityService extends IConnectivityManager.Stub final IBinder iCb = cb.asBinder(); final NetworkRequestInfo nri = cbInfo.mRequestInfo; + // Connectivity Diagnostics are meant to be used with a single network request. It would be + // confusing for these networks to change when an NRI is satisfied in another layer. + if (nri.isMultilayerRequest()) { + throw new IllegalArgumentException("Connectivity Diagnostics do not support multilayer " + + "network requests."); + } + // This means that the client registered the same callback multiple times. Do // not override the previous entry, and exit silently. if (mConnectivityDiagnosticsCallbacks.containsKey(iCb)) { @@ -8259,7 +8156,8 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { for (int i = 0; i < mNetworkForNetId.size(); i++) { final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i); - if (nai.satisfies(nri.request)) { + // Connectivity Diagnostics rejects multilayer requests at registration hence get(0) + if (nai.satisfies(nri.mRequests.get(0))) { matchingNetworks.add(nai); } } @@ -8387,7 +8285,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mConnectivityDiagnosticsCallbacks.entrySet()) { final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue(); final NetworkRequestInfo nri = cbInfo.mRequestInfo; - if (nai.satisfies(nri.request)) { + // Connectivity Diagnostics rejects multilayer requests at registration hence get(0). + if (nai.satisfies(nri.mRequests.get(0))) { if (checkConnectivityDiagnosticsPermissions( nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) { results.add(entry.getValue().mCb); @@ -8416,7 +8315,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } - for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo virtual : mNetworkAgentInfos) { if (virtual.supportsUnderlyingNetworks() && virtual.networkCapabilities.getOwnerUid() == callbackUid && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) { diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java index 2bc8925be019..0779f7117d82 100644 --- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java +++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java @@ -20,7 +20,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import android.content.Context; -import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.os.INetworkManagementService; import android.os.ServiceManager; @@ -36,9 +35,11 @@ public final class ConnectivityServiceInitializer extends SystemService { public ConnectivityServiceInitializer(Context context) { super(context); + // Load JNI libraries used by ConnectivityService and its dependencies + System.loadLibrary("service-connectivity"); // TODO: Define formal APIs to get the needed services. mConnectivity = new ConnectivityService(context, getNetworkManagementService(), - getNetworkStatsService(), getNetworkPolicyManager()); + getNetworkStatsService()); } @Override @@ -57,10 +58,4 @@ public final class ConnectivityServiceInitializer extends SystemService { return INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); } - - private INetworkPolicyManager getNetworkPolicyManager() { - return INetworkPolicyManager.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); - } - } diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index 500e768372f5..f2b63a642c29 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -236,4 +236,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { throw new RuntimeException(e.toString()); } } + + @Override + public long suggestScratchSize() throws RemoteException { + return getGsiService().suggestScratchSize(); + } } diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index a82e146113b6..bf53f2813949 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -14,6 +14,9 @@ per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com # Sensor Privacy per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS +# ServiceWatcher +per-file ServiceWatcher.java = sooniln@google.com + per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 40f24283d1b8..7e67f9758dfe 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10459,12 +10459,10 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - if (uid == Process.INVALID_UID) { - return Process.INVALID_UID; - } + // If the uid is Process.INVALID_UID, the below 'if' check will be always true if (UserHandle.getAppId(uid) != UserHandle.getAppId(callingUid)) { // Requires the DUMP permission if the target package doesn't belong - // to the caller. + // to the caller or it doesn't exist. enforceCallingPermission(android.Manifest.permission.DUMP, function); } return uid; diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index ef1b574c29a8..b4d74e0900f9 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -148,7 +154,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List<ActivityManager.RunningTaskInfo> tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 2c06d8230f13..b5d875d5c162 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -122,6 +122,8 @@ final public class IpConnectivityMetrics extends SystemService { public IpConnectivityMetrics(Context ctx, ToIntFunction<Context> capacityGetter) { super(ctx); + // Load JNI libraries used by the IpConnectivityMetrics service and its dependencies + System.loadLibrary("service-connectivity"); mCapacityGetter = capacityGetter; initBuffer(); } diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 96cbfde2a0a0..34d9ccc15dba 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -18,10 +18,7 @@ package com.android.server.connectivity; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NattSocketKeepalive.NATT_PORT; -import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER; -import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER; import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE; -import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE; import static android.net.SocketKeepalive.BINDER_DIED; import static android.net.SocketKeepalive.DATA_RECEIVED; import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES; @@ -330,10 +327,9 @@ public class KeepaliveTracker { Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.toShortString()); switch (mType) { case TYPE_NATT: - mNai.asyncChannel.sendMessage( - CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); - mNai.asyncChannel - .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); + final NattKeepalivePacketData nattData = (NattKeepalivePacketData) mPacket; + mNai.onAddNattKeepalivePacketFilter(slot, nattData); + mNai.onStartNattSocketKeepalive(slot, mInterval, nattData); break; case TYPE_TCP: try { @@ -342,11 +338,10 @@ public class KeepaliveTracker { handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET); return; } - mNai.asyncChannel.sendMessage( - CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); + final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket; + mNai.onAddTcpKeepalivePacketFilter(slot, tcpData); // TODO: check result from apf and notify of failure as needed. - mNai.asyncChannel - .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); + mNai.onStartTcpSocketKeepalive(slot, mInterval, tcpData); break; default: Log.wtf(TAG, "Starting keepalive with unknown type: " + mType); @@ -394,9 +389,8 @@ public class KeepaliveTracker { mTcpController.stopSocketMonitor(mSlot); // fall through case TYPE_NATT: - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, - mSlot); + mNai.onStopSocketKeepalive(mSlot); + mNai.onRemoveKeepalivePacketFilter(mSlot); break; default: Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); @@ -548,17 +542,13 @@ public class KeepaliveTracker { } /** Handle keepalive events from lower layer. */ - public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, - @NonNull Message message) { - int slot = message.arg1; - int reason = message.arg2; - + public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) { KeepaliveInfo ki = null; try { ki = mKeepalives.get(nai).get(slot); } catch(NullPointerException e) {} if (ki == null) { - Log.e(TAG, "Event " + message.what + "," + slot + "," + reason + Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason + " for unknown keepalive " + slot + " on " + nai.toShortString()); return; } @@ -601,7 +591,7 @@ public class KeepaliveTracker { ki.mStartedState = KeepaliveInfo.NOT_STARTED; cleanupStoppedKeepalive(nai, slot); } else { - Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason + Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason + " for keepalive in wrong state: " + ki.toString()); } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 52b9f5c15c50..841c9706a111 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -27,25 +27,35 @@ import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; import android.net.LinkProperties; +import android.net.NattKeepalivePacketData; import android.net.Network; +import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMonitorManager; import android.net.NetworkRequest; import android.net.NetworkState; +import android.net.TcpKeepalivePacketData; +import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.INetworkManagementService; -import android.os.Messenger; +import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; -import com.android.internal.util.AsyncChannel; +import com.android.connectivity.aidl.INetworkAgent; +import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.util.WakeupMessage; import com.android.server.ConnectivityService; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.SortedSet; import java.util.TreeSet; @@ -221,6 +231,31 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { */ public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001; + /** + * Inform ConnectivityService that the agent is half-connected. + * arg1 = ARG_AGENT_SUCCESS or ARG_AGENT_FAILURE + * obj = NetworkAgentInfo + * @hide + */ + public static final int EVENT_AGENT_REGISTERED = 1002; + + /** + * Inform ConnectivityService that the agent was disconnected. + * obj = NetworkAgentInfo + * @hide + */ + public static final int EVENT_AGENT_DISCONNECTED = 1003; + + /** + * Argument for EVENT_AGENT_HALF_CONNECTED indicating failure. + */ + public static final int ARG_AGENT_FAILURE = 0; + + /** + * Argument for EVENT_AGENT_HALF_CONNECTED indicating success. + */ + public static final int ARG_AGENT_SUCCESS = 1; + // All linger timers for this network, sorted by expiry time. A linger timer is added whenever // a request is moved to a network with a better score, regardless of whether the network is or // was lingering or not. @@ -262,8 +297,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // report is generated. Once non-null, it will never be null again. @Nullable private ConnectivityReport mConnectivityReport; - public final Messenger messenger; - public final AsyncChannel asyncChannel; + public final INetworkAgent networkAgent; + // Only accessed from ConnectivityService handler thread + private final AgentDeathMonitor mDeathMonitor = new AgentDeathMonitor(); public final int factorySerialNumber; @@ -279,13 +315,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { private final Context mContext; private final Handler mHandler; - public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, + public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, int creatorUid) { - this.messenger = messenger; - asyncChannel = ac; + networkAgent = na; network = net; networkInfo = info; linkProperties = lp; @@ -300,6 +335,249 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { this.creatorUid = creatorUid; } + private class AgentDeathMonitor implements IBinder.DeathRecipient { + @Override + public void binderDied() { + notifyDisconnected(); + } + } + + /** + * Notify the NetworkAgent that it was registered, and should be unregistered if it dies. + * + * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be + * registered once. + */ + public void notifyRegistered() { + try { + networkAgent.asBinder().linkToDeath(mDeathMonitor, 0); + networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler)); + } catch (RemoteException e) { + Log.e(TAG, "Error registering NetworkAgent", e); + maybeUnlinkDeathMonitor(); + mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_FAILURE, 0, this) + .sendToTarget(); + return; + } + + mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget(); + } + + /** + * Disconnect the NetworkAgent. Must be called from the ConnectivityService handler thread. + */ + public void disconnect() { + try { + networkAgent.onDisconnected(); + } catch (RemoteException e) { + Log.i(TAG, "Error disconnecting NetworkAgent", e); + // Fall through: it's fine if the remote has died + } + + notifyDisconnected(); + maybeUnlinkDeathMonitor(); + } + + private void maybeUnlinkDeathMonitor() { + try { + networkAgent.asBinder().unlinkToDeath(mDeathMonitor, 0); + } catch (NoSuchElementException e) { + // Was not linked: ignore + } + } + + private void notifyDisconnected() { + // Note this may be called multiple times if ConnectivityService disconnects while the + // NetworkAgent also dies. ConnectivityService ignores disconnects of already disconnected + // agents. + mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED, this).sendToTarget(); + } + + /** + * Notify the NetworkAgent that bandwidth update was requested. + */ + public void onBandwidthUpdateRequested() { + try { + networkAgent.onBandwidthUpdateRequested(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending bandwidth update request event", e); + } + } + + /** + * Notify the NetworkAgent that validation status has changed. + */ + public void onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl) { + try { + networkAgent.onValidationStatusChanged(validationStatus, captivePortalUrl); + } catch (RemoteException e) { + Log.e(TAG, "Error sending validation status change event", e); + } + } + + /** + * Notify the NetworkAgent that the acceptUnvalidated setting should be saved. + */ + public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { + try { + networkAgent.onSaveAcceptUnvalidated(acceptUnvalidated); + } catch (RemoteException e) { + Log.e(TAG, "Error sending accept unvalidated event", e); + } + } + + /** + * Notify the NetworkAgent that NATT socket keepalive should be started. + */ + public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + @NonNull NattKeepalivePacketData packetData) { + try { + networkAgent.onStartNattSocketKeepalive(slot, intervalDurationMs, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending NATT socket keepalive start event", e); + } + } + + /** + * Notify the NetworkAgent that TCP socket keepalive should be started. + */ + public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + @NonNull TcpKeepalivePacketData packetData) { + try { + networkAgent.onStartTcpSocketKeepalive(slot, intervalDurationMs, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending TCP socket keepalive start event", e); + } + } + + /** + * Notify the NetworkAgent that socket keepalive should be stopped. + */ + public void onStopSocketKeepalive(int slot) { + try { + networkAgent.onStopSocketKeepalive(slot); + } catch (RemoteException e) { + Log.e(TAG, "Error sending TCP socket keepalive stop event", e); + } + } + + /** + * Notify the NetworkAgent that signal strength thresholds should be updated. + */ + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + try { + networkAgent.onSignalStrengthThresholdsUpdated(thresholds); + } catch (RemoteException e) { + Log.e(TAG, "Error sending signal strength thresholds event", e); + } + } + + /** + * Notify the NetworkAgent that automatic reconnect should be prevented. + */ + public void onPreventAutomaticReconnect() { + try { + networkAgent.onPreventAutomaticReconnect(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending prevent automatic reconnect event", e); + } + } + + /** + * Notify the NetworkAgent that a NATT keepalive packet filter should be added. + */ + public void onAddNattKeepalivePacketFilter(int slot, + @NonNull NattKeepalivePacketData packetData) { + try { + networkAgent.onAddNattKeepalivePacketFilter(slot, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending add NATT keepalive packet filter event", e); + } + } + + /** + * Notify the NetworkAgent that a TCP keepalive packet filter should be added. + */ + public void onAddTcpKeepalivePacketFilter(int slot, + @NonNull TcpKeepalivePacketData packetData) { + try { + networkAgent.onAddTcpKeepalivePacketFilter(slot, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending add TCP keepalive packet filter event", e); + } + } + + /** + * Notify the NetworkAgent that a keepalive packet filter should be removed. + */ + public void onRemoveKeepalivePacketFilter(int slot) { + try { + networkAgent.onRemoveKeepalivePacketFilter(slot); + } catch (RemoteException e) { + Log.e(TAG, "Error sending remove keepalive packet filter event", e); + } + } + + // TODO: consider moving out of NetworkAgentInfo into its own class + private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub { + private final Handler mHandler; + + private NetworkAgentMessageHandler(Handler handler) { + mHandler = handler; + } + + @Override + public void sendNetworkCapabilities(NetworkCapabilities nc) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, + new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget(); + } + + @Override + public void sendLinkProperties(LinkProperties lp) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, + new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget(); + } + + @Override + public void sendNetworkInfo(NetworkInfo info) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED, + new Pair<>(NetworkAgentInfo.this, info)).sendToTarget(); + } + + @Override + public void sendScore(int score) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, score, 0, + new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial) { + mHandler.obtainMessage(NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED, + explicitlySelected ? 1 : 0, acceptPartial ? 1 : 0, + new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendSocketKeepaliveEvent(int slot, int reason) { + mHandler.obtainMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE, + slot, reason, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendUnderlyingNetworks(@Nullable List<Network> networks) { + final Bundle args = new Bundle(); + if (networks instanceof ArrayList<?>) { + args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, + (ArrayList<Network>) networks); + } else { + args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, + networks == null ? null : new ArrayList<>(networks)); + } + mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED, + new Pair<>(NetworkAgentInfo.this, args)).sendToTarget(); + } + } + /** * Inform NetworkAgentInfo that a new NetworkMonitor was created. */ diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java index 06721aea5540..93930ae16de8 100644 --- a/services/core/java/com/android/server/connectivity/PacManager.java +++ b/services/core/java/com/android/server/connectivity/PacManager.java @@ -177,7 +177,7 @@ public class PacManager { * @param proxy Proxy information that is about to be broadcast. * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST */ - synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { + public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) { // Allow to send broadcast, nothing to do. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c121d24099f3..a7b9622ab3c0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -331,6 +331,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; @@ -12455,12 +12456,17 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.addAllPermissionGroups(pkg, chatty); } + // If a permission has had its defining app changed, or it has had its protection + // upgraded, we need to revoke apps that hold it + final List<String> permissionsWithChangedDefinition; // Don't allow ephemeral applications to define new permissions. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { + permissionsWithChangedDefinition = null; Slog.w(TAG, "Permissions from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permissions."); } else { - mPermissionManager.addAllPermissions(pkg, chatty); + permissionsWithChangedDefinition = + mPermissionManager.addAllPermissions(pkg, chatty); } int collectionSize = ArrayUtils.size(pkg.getInstrumentations()); @@ -12489,7 +12495,10 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (oldPkg != null) { + boolean hasOldPkg = oldPkg != null; + boolean hasPermissionDefinitionChanges = + !CollectionUtils.isEmpty(permissionsWithChangedDefinition); + if (hasOldPkg || hasPermissionDefinitionChanges) { // We need to call revokeRuntimePermissionsIfGroupChanged async as permission // revoke callbacks from this method might need to kill apps which need the // mPackages lock on a different thread. This would dead lock. @@ -12500,9 +12509,16 @@ public class PackageManagerService extends IPackageManager.Stub // won't be granted yet, hence new packages are no problem. final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet()); - AsyncTask.execute(() -> + AsyncTask.execute(() -> { + if (hasOldPkg) { mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg, - allPackageNames)); + allPackageNames); + } + if (hasPermissionDefinitionChanges) { + mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged( + permissionsWithChangedDefinition, allPackageNames); + } + }); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f5d7d9eda1ba..9aa47a67d4e2 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3724,7 +3724,7 @@ public class UserManagerService extends IUserManager.Stub { UserData putUserInfo(UserInfo userInfo) { final UserData userData = new UserData(); userData.info = userInfo; - synchronized (mUsers) { + synchronized (mUsersLock) { mUsers.put(userInfo.id, userData); } return userData; @@ -3732,7 +3732,7 @@ public class UserManagerService extends IUserManager.Stub { @VisibleForTesting void removeUserInfo(@UserIdInt int userId) { - synchronized (mUsers) { + synchronized (mUsersLock) { mUsers.remove(userId); } } @@ -4052,7 +4052,7 @@ public class UserManagerService extends IUserManager.Stub { userFile.delete(); updateUserIds(); if (RELEASE_DELETED_USER_ID) { - synchronized (mUsers) { + synchronized (mUsersLock) { mRemovingUserIds.delete(userId); } } @@ -5183,6 +5183,9 @@ public class UserManagerService extends IUserManager.Stub { debugMsg + " for another profile " + targetUserId + " from " + callingUserId); } + Slog.w(LOG_TAG, debugMsg + " for another profile " + + targetUserId + " from " + callingUserId); + return false; } UserInfo targetUserInfo = getUserInfoLU(targetUserId); diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index cfa0449aaf33..5e04171a3bca 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -83,6 +83,8 @@ public final class BasePermission { final @PermissionType int type; + private boolean mPermissionDefinitionChanged; + String sourcePackageName; int protectionLevel; @@ -126,6 +128,11 @@ public final class BasePermission { public String getSourcePackageName() { return sourcePackageName; } + + public boolean isPermissionDefinitionChanged() { + return mPermissionDefinitionChanged; + } + public int getType() { return type; } @@ -140,6 +147,10 @@ public final class BasePermission { this.perm = perm; } + public void setPermissionDefinitionChanged(boolean shouldOverride) { + mPermissionDefinitionChanged = shouldOverride; + } + public int[] computeGids(int userId) { if (perUser) { final int[] userGids = new int[gids.length]; @@ -322,6 +333,7 @@ public final class BasePermission { final PackageSettingBase pkgSetting = (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName()); // Allow system apps to redefine non-system permissions + boolean ownerChanged = false; if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) { final boolean currentOwnerIsSystem; if (bp.perm == null) { @@ -347,6 +359,7 @@ public final class BasePermission { String msg = "New decl " + pkg + " of permission " + p.getName() + " is system; overriding " + bp.sourcePackageName; PackageManagerService.reportSettingsProblem(Log.WARN, msg); + ownerChanged = true; bp = null; } } @@ -354,6 +367,7 @@ public final class BasePermission { if (bp == null) { bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL); } + boolean wasNonRuntime = !bp.isRuntime(); StringBuilder r = null; if (bp.perm == null) { if (bp.sourcePackageName == null @@ -397,6 +411,11 @@ public final class BasePermission { && Objects.equals(bp.perm.getName(), p.getName())) { bp.protectionLevel = p.getProtectionLevel(); } + if (bp.isRuntime() && (ownerChanged || wasNonRuntime)) { + // If this is a runtime permission and the owner has changed, or this was a normal + // permission, then permission state should be cleaned up + bp.mPermissionDefinitionChanged = true; + } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 66d8b5974261..3ffca028b1c0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2344,8 +2344,74 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void addAllPermissions(AndroidPackage pkg, boolean chatty) { + /** + * If permissions are upgraded to runtime, or their owner changes to the system, then any + * granted permissions must be revoked. + * + * @param permissionsToRevoke A list of permission names to revoke + * @param allPackageNames All package names + * @param permissionCallback Callback for permission changed + */ + private void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames, + @NonNull PermissionCallback permissionCallback) { + + final int[] userIds = mUserManagerInt.getUserIds(); + final int numPermissions = permissionsToRevoke.size(); + final int numUserIds = userIds.length; + final int numPackages = allPackageNames.size(); + final int callingUid = Binder.getCallingUid(); + + for (int permNum = 0; permNum < numPermissions; permNum++) { + String permName = permissionsToRevoke.get(permNum); + BasePermission bp = mSettings.getPermission(permName); + if (bp == null || !bp.isRuntime()) { + continue; + } + for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { + final int userId = userIds[userIdNum]; + for (int packageNum = 0; packageNum < numPackages; packageNum++) { + final String packageName = allPackageNames.get(packageNum); + final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId); + if (uid < Process.FIRST_APPLICATION_UID) { + // do not revoke from system apps + continue; + } + final int permissionState = checkPermissionImpl(permName, packageName, + userId); + final int flags = getPermissionFlags(permName, packageName, userId); + final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED + | FLAG_PERMISSION_POLICY_FIXED + | FLAG_PERMISSION_GRANTED_BY_DEFAULT + | FLAG_PERMISSION_GRANTED_BY_ROLE; + if (permissionState == PackageManager.PERMISSION_GRANTED + && (flags & flagMask) == 0) { + EventLog.writeEvent(0x534e4554, "154505240", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + EventLog.writeEvent(0x534e4554, "168319670", uid, + "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + Slog.e(TAG, "Revoking permission " + permName + " from package " + + packageName + " due to definition change"); + try { + revokeRuntimePermissionInternal(permName, packageName, + false, callingUid, userId, null, permissionCallback); + } catch (Exception e) { + Slog.e(TAG, "Could not revoke " + permName + " from " + + packageName, e); + } + } + } + } + bp.setPermissionDefinitionChanged(false); + } + } + + private List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) { final int N = ArrayUtils.size(pkg.getPermissions()); + ArrayList<String> definitionChangedPermissions = new ArrayList<>(); for (int i=0; i<N; i++) { ParsedPermission p = pkg.getPermissions().get(i); @@ -2367,21 +2433,26 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + final BasePermission bp; if (p.isTree()) { - final BasePermission bp = BasePermission.createOrUpdate( + bp = BasePermission.createOrUpdate( mPackageManagerInt, mSettings.getPermissionTreeLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); mSettings.putPermissionTreeLocked(p.getName(), bp); } else { - final BasePermission bp = BasePermission.createOrUpdate( + bp = BasePermission.createOrUpdate( mPackageManagerInt, mSettings.getPermissionLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); mSettings.putPermissionLocked(p.getName(), bp); } + if (bp.isPermissionDefinitionChanged()) { + definitionChangedPermissions.add(p.getName()); + } } } + return definitionChangedPermissions; } private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { @@ -4672,9 +4743,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage, oldPackage, allPackageNames, mDefaultPermissionCallback); } + + @Override + public void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames) { + PermissionManagerService.this.revokeRuntimePermissionsIfPermissionDefinitionChanged( + permissionsToRevoke, allPackageNames, mDefaultPermissionCallback); + } + @Override - public void addAllPermissions(AndroidPackage pkg, boolean chatty) { - PermissionManagerService.this.addAllPermissions(pkg, chatty); + public List<String> addAllPermissions(AndroidPackage pkg, boolean chatty) { + return PermissionManagerService.this.addAllPermissions(pkg, chatty); } @Override public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 37f40595450d..393e8527a991 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -254,12 +254,26 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager @NonNull ArrayList<String> allPackageNames); /** + * Some permissions might have been owned by a non-system package, and the system then defined + * said permission. Some other permissions may one have been install permissions, but are now + * runtime or higher. These permissions should be revoked. + * + * @param permissionsToRevoke A list of permission names to revoke + * @param allPackageNames All packages + */ + public abstract void revokeRuntimePermissionsIfPermissionDefinitionChanged( + @NonNull List<String> permissionsToRevoke, + @NonNull ArrayList<String> allPackageNames); + + /** * Add all permissions in the given package. * <p> * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to * the permission settings. + * + * @return A list of BasePermissions that were updated, and need to be revoked from packages */ - public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); + public abstract List<String> addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty); public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 4f95696dce88..e0db93a01efd 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -168,7 +168,6 @@ cc_defaults { static_libs: [ "android.hardware.broadcastradio@common-utils-1x-lib", - "libservice-connectivity-static", ], product_variables: { diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index 00342866aa30..f076ca9afbea 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -46,6 +46,8 @@ #include <utils/misc.h> #include <utils/Log.h> +#include <android-base/strings.h> + using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; @@ -200,67 +202,13 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return 0; } - char* mergedreasonpos = mergedreason; - int i = 0; - for (auto wakeupReason : wakeupReasons) { - auto reasonline = const_cast<char*>(wakeupReason.c_str()); - char* pos = reasonline; - char* endPos; - int len; - // First field is the index or 'Abort'. - int irq = (int)strtol(pos, &endPos, 10); - if (pos != endPos) { - // Write the irq number to the merged reason string. - len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%d" : ":%d", irq); - } else { - // The first field is not an irq, it may be the word Abort. - const size_t abortPrefixLen = strlen("Abort:"); - if (strncmp(pos, "Abort:", abortPrefixLen) != 0) { - // Ooops. - ALOGE("Bad reason line: %s", reasonline); - continue; - } - - // Write 'Abort' to the merged reason string. - len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "Abort" : ":Abort"); - endPos = pos + abortPrefixLen; - } - pos = endPos; - - if (len >= 0 && len < remainreasonlen) { - mergedreasonpos += len; - remainreasonlen -= len; - } - - // Skip whitespace; rest of the buffer is the reason string. - while (*pos == ' ') { - pos++; - } + std::string mergedReasonStr = ::android::base::Join(wakeupReasons, ":"); + strncpy(mergedreason, mergedReasonStr.c_str(), remainreasonlen); + mergedreason[remainreasonlen - 1] = '\0'; - // Chop newline at end. - char* endpos = pos; - while (*endpos != 0) { - if (*endpos == '\n') { - *endpos = 0; - break; - } - endpos++; - } - - len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos); - if (len >= 0 && len < remainreasonlen) { - mergedreasonpos += len; - remainreasonlen -= len; - } - i++; - } - - ALOGV("Got %d reasons", i); - if (i > 0) { - *mergedreasonpos = 0; - } + ALOGV("Got %d reasons", (int)wakeupReasons.size()); - return mergedreasonpos - mergedreason; + return strlen(mergedreason); } // The caller must be holding gPowerHalMutex. diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 8cb3e6d1ae73..ccf685c1abd7 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -40,8 +40,6 @@ int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_vr_VrManagerService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_location_GnssLocationProvider(JNIEnv* env); -int register_android_server_connectivity_Vpn(JNIEnv* env); -int register_android_server_TestNetworkService(JNIEnv* env); int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*); int register_android_server_tv_TvUinputBridge(JNIEnv* env); int register_android_server_tv_TvInputHal(JNIEnv* env); @@ -93,8 +91,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_VibratorService(env); register_android_server_SystemServer(env); register_android_server_location_GnssLocationProvider(env); - register_android_server_connectivity_Vpn(env); - register_android_server_TestNetworkService(env); register_android_server_devicepolicy_CryptoTestHelper(env); register_android_server_ConsumerIrService(env); register_android_server_BatteryStatsService(env); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b5c5bb52d050..d55a5b7792d4 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -221,6 +221,8 @@ public final class SystemServer { "com.android.server.companion.CompanionDeviceManagerService"; private static final String STATS_COMPANION_APEX_PATH = "/apex/com.android.os.statsd/javalib/service-statsd.jar"; + private static final String CONNECTIVITY_SERVICE_APEX_PATH = + "/apex/com.android.tethering/javalib/service-connectivity.jar"; private static final String STATS_COMPANION_LIFECYCLE_CLASS = "com.android.server.stats.StatsCompanion$Lifecycle"; private static final String STATS_PULL_ATOM_SERVICE_CLASS = @@ -1217,7 +1219,8 @@ public final class SystemServer { } t.traceBegin("IpConnectivityMetrics"); - mSystemServiceManager.startService(IP_CONNECTIVITY_METRICS_CLASS); + mSystemServiceManager.startServiceFromJar(IP_CONNECTIVITY_METRICS_CLASS, + CONNECTIVITY_SERVICE_APEX_PATH); t.traceEnd(); t.traceBegin("NetworkWatchlistService"); @@ -1558,8 +1561,8 @@ public final class SystemServer { // This has to be called after NetworkManagementService, NetworkStatsService // and NetworkPolicyManager because ConnectivityService needs to take these // services to initialize. - // TODO: Dynamically load service-connectivity.jar by using startServiceFromJar. - mSystemServiceManager.startService(CONNECTIVITY_SERVICE_INITIALIZER_CLASS); + mSystemServiceManager.startServiceFromJar(CONNECTIVITY_SERVICE_INITIALIZER_CLASS, + CONNECTIVITY_SERVICE_APEX_PATH); connectivity = IConnectivityManager.Stub.asInterface( ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); // TODO: Use ConnectivityManager instead of ConnectivityService. diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS new file mode 100644 index 000000000000..28aff188dbd8 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 847766 +nfuller@google.com +include /core/java/android/app/timedetector/OWNERS diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index 5024ae27ee49..835ecaa8c90d 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -361,7 +361,13 @@ public final class PhoneAccount implements Parcelable { */ public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000; - /* NEXT CAPABILITY: 0x8000 */ + /** + * Flag indicating whether this {@link PhoneAccount} is capable of supporting the call composer + * functionality for enriched calls. + */ + public static final int CAPABILITY_CALL_COMPOSER = 0x8000; + + /* NEXT CAPABILITY: 0x10000 */ /** * URI scheme for telephone number URIs. @@ -1088,6 +1094,9 @@ public final class PhoneAccount implements Parcelable { if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) { sb.append("AdhocConf"); } + if (hasCapabilities(CAPABILITY_CALL_COMPOSER)) { + sb.append("CallComposer "); + } return sb.toString(); } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index da2d4d82481b..3f8b68305914 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -266,10 +266,69 @@ public class TelecomManager { /** * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a string call * subject which will be associated with an outgoing call. Should only be specified if the - * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}. + * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT} + * or {@link PhoneAccount#CAPABILITY_CALL_COMPOSER}. */ public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT"; + // Values for EXTRA_PRIORITY + /** + * Indicates the call composer call priority is normal. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_NORMAL = 0; + + /** + * Indicates the call composer call priority is urgent. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_URGENT = 1; + + /** + * Extra for the call composer call priority, either {@link #PRIORITY_NORMAL} or + * {@link #PRIORITY_URGENT}. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY"; + + /** + * Extra for the call composer call location, an {@link android.location.Location} parcelable + * class to represent the geolocation as a latitude and longitude pair. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION"; + + /** + * A boolean extra set on incoming calls to indicate that the call has a picture specified. + * Given that image download could take a (short) time, the EXTRA is set immediately upon + * adding the call to the Dialer app, this allows the Dialer app to reserve space for an image + * if one is expected. The EXTRA may be unset if the image download ends up failing for some + * reason. + */ + public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE"; + + /** + * A URI representing the picture that was downloaded when a call is received. + * This is a content URI within the call log provider which can be used to open a file + * descriptor. This could be set a short time after a call is added to the Dialer app if the + * download is delayed for some reason. The Dialer app will receive a callback via + * {@link Call.Callback#onDetailsChanged} when this value has changed. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE"; + + // TODO(hallliu), This UUID is obtained from TelephonyManager#uploadCallComposerPicture. + /** + * A ParcelUuid used as a token to represent a picture that was uploaded prior to the call + * being placed. + */ + public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE"; + /** * The extra used by a {@link ConnectionService} to provide the handle of the caller that * has initiated a new incoming call. diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 4e9e6a8440a9..74b2aad5293e 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4056,6 +4056,17 @@ public class CarrierConfigManager { "default_preferred_apn_name_string"; /** + * Indicates if the carrier supports call composer. + */ + public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool"; + + /** + * Indicates the carrier server url that serves the call composer picture. + */ + public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = + "call_composer_picture_server_url_string"; + + /** * For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values * for IPv4 and IPv6 if both are sent. * TODO: remove in later release @@ -4613,6 +4624,8 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); + sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false); + sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, ""); sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false); sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false); } diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/telephony/java/android/telephony/data/ApnThrottleStatus.aidl new file mode 100644 index 000000000000..46bc4abde159 --- /dev/null +++ b/telephony/java/android/telephony/data/ApnThrottleStatus.aidl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** @hide */ +package android.telephony.data; + +parcelable ApnThrottleStatus; diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.java b/telephony/java/android/telephony/data/ApnThrottleStatus.java new file mode 100644 index 000000000000..51461d17690a --- /dev/null +++ b/telephony/java/android/telephony/data/ApnThrottleStatus.java @@ -0,0 +1,383 @@ +/* + * 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.telephony.data; + +import android.annotation.ElapsedRealtimeLong; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation; + +import java.util.Objects; + +/** + * Status information regarding the throttle status of an APN type. + * + * @hide + */ +@SystemApi +public final class ApnThrottleStatus implements Parcelable { + /** + * The APN type is not throttled. + */ + public static final int THROTTLE_TYPE_NONE = 1; + + /** + * The APN type is throttled until {@link android.os.SystemClock#elapsedRealtime()} + * has reached {@link ApnThrottleStatus#getThrottleExpiryTimeMillis} + */ + public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; + + /** {@hide} */ + @IntDef(flag = true, prefix = {"THROTTLE_TYPE_"}, value = { + ApnThrottleStatus.THROTTLE_TYPE_NONE, + ApnThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME, + }) + public @interface ThrottleType { + } + + /** + * The framework will not retry the APN type. + */ + public static final int RETRY_TYPE_NONE = 1; + + /** + * The next time the framework retries, it will attempt to establish a new connection. + */ + public static final int RETRY_TYPE_NEW_CONNECTION = 2; + + /** + * The next time the framework retires, it will retry to handover. + */ + public static final int RETRY_TYPE_HANDOVER = 3; + + /** {@hide} */ + @IntDef(flag = true, prefix = {"RETRY_TYPE_"}, value = { + ApnThrottleStatus.RETRY_TYPE_NONE, + ApnThrottleStatus.RETRY_TYPE_NEW_CONNECTION, + ApnThrottleStatus.RETRY_TYPE_HANDOVER, + }) + public @interface RetryType { + } + + private final int mSlotIndex; + private final @AccessNetworkConstants.TransportType int mTransportType; + private final @Annotation.ApnType int mApnType; + private final long mThrottleExpiryTimeMillis; + private final @RetryType int mRetryType; + private final @ThrottleType int mThrottleType; + + /** + * The slot index that the status applies to. + * + * @return the slot index + */ + public int getSlotIndex() { + return mSlotIndex; + } + + /** + * The type of transport that the status applies to. + * + * @return the transport type + */ + @AccessNetworkConstants.TransportType + public int getTransportType() { + return mTransportType; + } + + /** + * The APN type that the status applies to. + * + * @return the apn type + */ + @Annotation.ApnType + public int getApnType() { + return mApnType; + } + + /** + * The type of throttle applied to the APN type. + * + * @return the throttle type + */ + @ThrottleType + public int getThrottleType() { + return mThrottleType; + } + + /** + * Indicates the type of request that the framework will make the next time it retries + * to call {@link IDataService#setupDataCall}. + * + * @return the retry type + */ + @RetryType + public int getRetryType() { + return mRetryType; + } + + /** + * Gets the time at which the throttle expires. The value is based off of + * {@link SystemClock#elapsedRealtime}. + * + * This value only applies when the throttle type is set to + * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}. + * + * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely. + * + * @return the time at which the throttle expires + */ + @ElapsedRealtimeLong + public long getThrottleExpiryTimeMillis() { + return mThrottleExpiryTimeMillis; + } + + private ApnThrottleStatus(int slotIndex, + @AccessNetworkConstants.TransportType int transportType, + @Annotation.ApnType int apnTypes, + @ThrottleType int throttleType, + long throttleExpiryTimeMillis, + @RetryType int retryType) { + mSlotIndex = slotIndex; + mTransportType = transportType; + mApnType = apnTypes; + mThrottleType = throttleType; + mThrottleExpiryTimeMillis = throttleExpiryTimeMillis; + mRetryType = retryType; + } + + private ApnThrottleStatus(@NonNull Parcel source) { + mSlotIndex = source.readInt(); + mTransportType = source.readInt(); + mApnType = source.readInt(); + mThrottleExpiryTimeMillis = source.readLong(); + mRetryType = source.readInt(); + mThrottleType = source.readInt(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSlotIndex); + dest.writeInt(mTransportType); + dest.writeInt(mApnType); + dest.writeLong(mThrottleExpiryTimeMillis); + dest.writeInt(mRetryType); + dest.writeInt(mThrottleType); + } + + public static final @NonNull Parcelable.Creator<ApnThrottleStatus> CREATOR = + new Parcelable.Creator<ApnThrottleStatus>() { + @Override + public ApnThrottleStatus createFromParcel(@NonNull Parcel source) { + return new ApnThrottleStatus(source); + } + + @Override + public ApnThrottleStatus[] newArray(int size) { + return new ApnThrottleStatus[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(mSlotIndex, mApnType, mRetryType, mThrottleType, + mThrottleExpiryTimeMillis, mTransportType); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj instanceof ApnThrottleStatus) { + ApnThrottleStatus other = (ApnThrottleStatus) obj; + return this.mSlotIndex == other.mSlotIndex + && this.mApnType == other.mApnType + && this.mRetryType == other.mRetryType + && this.mThrottleType == other.mThrottleType + && this.mThrottleExpiryTimeMillis == other.mThrottleExpiryTimeMillis + && this.mTransportType == other.mTransportType; + } else { + return false; + } + } + + @Override + public String toString() { + return "ApnThrottleStatus{" + + "mSlotIndex=" + mSlotIndex + + ", mTransportType=" + mTransportType + + ", mApnType=" + ApnSetting.getApnTypeString(mApnType) + + ", mThrottleExpiryTimeMillis=" + mThrottleExpiryTimeMillis + + ", mRetryType=" + mRetryType + + ", mThrottleType=" + mThrottleType + + '}'; + } + + /** + * Provides a convenient way to set the fields of an {@link ApnThrottleStatus} when creating a + * new instance. + * + * <p>The example below shows how you might create a new {@code ApnThrottleStatus}: + * + * <pre><code> + * + * DataCallResponseApnThrottleStatus = new ApnThrottleStatus.Builder() + * .setSlotIndex(1) + * .setApnType({@link ApnSetting#TYPE_EMERGENCY}) + * .setNoThrottle() + * .setRetryType({@link ApnThrottleStatus#RETRY_TYPE_NEW_CONNECTION}) + * .build(); + * </code></pre> + */ + public static final class Builder { + private int mSlotIndex; + private @AccessNetworkConstants.TransportType int mTransportType; + private @Annotation.ApnType int mApnType; + private long mThrottleExpiryTimeMillis; + private @RetryType int mRetryType; + private @ThrottleType int mThrottleType; + public static final long NO_THROTTLE_EXPIRY_TIME = + DataCallResponse.RETRY_DURATION_UNDEFINED; + + /** + * Default constructor for the Builder. + */ + public Builder() { + } + + /** + * Set the slot index. + * + * @param slotIndex the slot index. + * @return The same instance of the builder. + */ + @NonNull + public Builder setSlotIndex(int slotIndex) { + this.mSlotIndex = slotIndex; + return this; + } + + /** + * Set the transport type. + * + * @param transportType the transport type. + * @return The same instance of the builder. + */ + @NonNull + public Builder setTransportType(@AccessNetworkConstants.TransportType + int transportType) { + this.mTransportType = transportType; + return this; + } + + /** + * Set the APN type. + * + * @param apnType the APN type. + * @return The same instance of the builder. + */ + @NonNull + public Builder setApnType(@Annotation.ApnType int apnType) { + this.mApnType = apnType; + return this; + } + + /** + * Sets the time at which the throttle will expire. The value is based off of + * {@link SystemClock#elapsedRealtime}. + * + * When setting this value, the throttle type is set to + * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}. + * + * A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely. + * + * @param throttleExpiryTimeMillis The elapsed time at which the throttle expires. + * Throws {@link IllegalArgumentException} for values less + * than 0. + * @return The same instance of the builder. + */ + @NonNull + public Builder setThrottleExpiryTimeMillis( + @ElapsedRealtimeLong long throttleExpiryTimeMillis) { + if (throttleExpiryTimeMillis >= 0) { + this.mThrottleExpiryTimeMillis = throttleExpiryTimeMillis; + this.mThrottleType = THROTTLE_TYPE_ELAPSED_TIME; + } else { + throw new IllegalArgumentException("throttleExpiryTimeMillis must be greater than " + + "or equal to 0"); + } + return this; + } + + /** + * Sets the status of the APN type as not being throttled. + * + * When setting this value, the throttle type is set to + * {@link ApnThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to + * {@link Builder#NO_THROTTLE_EXPIRY_TIME}. + * + * @return The same instance of the builder. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setNoThrottle() { + mThrottleType = THROTTLE_TYPE_NONE; + mThrottleExpiryTimeMillis = NO_THROTTLE_EXPIRY_TIME; + return this; + } + + /** + * Set the type of request that the framework will make the next time it retries + * to call {@link IDataService#setupDataCall}. + * + * @param retryType the type of request + * @return The same instance of the builder. + */ + @NonNull + public Builder setRetryType(@RetryType int retryType) { + this.mRetryType = retryType; + return this; + } + + /** + * Build the {@link ApnThrottleStatus} + * + * @return the {@link ApnThrottleStatus} object + */ + @NonNull + public ApnThrottleStatus build() { + return new ApnThrottleStatus( + mSlotIndex, + mTransportType, + mApnType, + mThrottleType, + mThrottleExpiryTimeMillis, + mRetryType); + } + } +} diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index f0088b913d4e..8348502586a5 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -109,10 +109,10 @@ public final class DataCallResponse implements Parcelable { public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; /** - * Indicates that data retry interval is not specified. Platform can determine when to + * Indicates that data retry duration is not specified. Platform can determine when to * perform data setup appropriately. */ - public static final int RETRY_INTERVAL_UNDEFINED = -1; + public static final int RETRY_DURATION_UNDEFINED = -1; /** * Indicates that the pdu session id is not set. @@ -254,19 +254,26 @@ public final class DataCallResponse implements Parcelable { /** * @return The suggested data retry time in milliseconds. * - * @deprecated Use {@link #getRetryIntervalMillis()} instead. + * @deprecated Use {@link #getRetryDurationMillis()} instead. */ @Deprecated public int getSuggestedRetryTime() { + + // To match the pre-deprecated getSuggestedRetryTime() behavior. + if (mSuggestedRetryTime == RETRY_DURATION_UNDEFINED) { + return 0; + } else if (mSuggestedRetryTime > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } return (int) mSuggestedRetryTime; } /** - * @return The network suggested data retry interval in milliseconds. {@code Long.MAX_VALUE} - * indicates data retry should not occur. {@link #RETRY_INTERVAL_UNDEFINED} indicates network - * did not suggest any retry interval. + * @return The network suggested data retry duration in milliseconds. {@code Long.MAX_VALUE} + * indicates data retry should not occur. {@link #RETRY_DURATION_UNDEFINED} indicates network + * did not suggest any retry duration. */ - public long getRetryIntervalMillis() { + public long getRetryDurationMillis() { return mSuggestedRetryTime; } @@ -537,7 +544,7 @@ public final class DataCallResponse implements Parcelable { public static final class Builder { private @DataFailureCause int mCause; - private long mSuggestedRetryTime = RETRY_INTERVAL_UNDEFINED; + private long mSuggestedRetryTime = RETRY_DURATION_UNDEFINED; private int mId; @@ -592,7 +599,7 @@ public final class DataCallResponse implements Parcelable { * @param suggestedRetryTime The suggested data retry time in milliseconds. * @return The same instance of the builder. * - * @deprecated Use {@link #setRetryIntervalMillis(long)} instead. + * @deprecated Use {@link #setRetryDurationMillis(long)} instead. */ @Deprecated public @NonNull Builder setSuggestedRetryTime(int suggestedRetryTime) { @@ -601,13 +608,13 @@ public final class DataCallResponse implements Parcelable { } /** - * Set the network suggested data retry interval. + * Set the network suggested data retry duration. * - * @param retryIntervalMillis The suggested data retry interval in milliseconds. + * @param retryDurationMillis The suggested data retry duration in milliseconds. * @return The same instance of the builder. */ - public @NonNull Builder setRetryIntervalMillis(long retryIntervalMillis) { - mSuggestedRetryTime = retryIntervalMillis; + public @NonNull Builder setRetryDurationMillis(long retryDurationMillis) { + mSuggestedRetryTime = retryDurationMillis; return this; } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 77685971c138..2ec965101930 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -107,6 +107,9 @@ public abstract class DataService extends Service { private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED = 11; private static final int DATA_SERVICE_REQUEST_START_HANDOVER = 12; private static final int DATA_SERVICE_REQUEST_CANCEL_HANDOVER = 13; + private static final int DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED = 14; + private static final int DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED = 15; + private static final int DATA_SERVICE_INDICATION_APN_UNTHROTTLED = 16; private final HandlerThread mHandlerThread; @@ -129,6 +132,8 @@ public abstract class DataService extends Service { private final List<IDataServiceCallback> mDataCallListChangedCallbacks = new ArrayList<>(); + private final List<IDataServiceCallback> mApnUnthrottledCallbacks = new ArrayList<>(); + /** * Constructor * @param slotIndex SIM slot index the data service provider associated with. @@ -326,6 +331,19 @@ public abstract class DataService extends Service { } } + private void registerForApnUnthrottled(IDataServiceCallback callback) { + synchronized (mApnUnthrottledCallbacks) { + mApnUnthrottledCallbacks.add(callback); + } + } + + private void unregisterForApnUnthrottled(IDataServiceCallback callback) { + synchronized (mApnUnthrottledCallbacks) { + mApnUnthrottledCallbacks.remove(callback); + } + } + + /** * Notify the system that current data call list changed. Data service must invoke this * method whenever there is any data call status changed. @@ -343,6 +361,21 @@ public abstract class DataService extends Service { } /** + * Notify the system that a given APN was unthrottled. + * + * @param apn Access Point Name defined by the carrier. + */ + public final void notifyApnUnthrottled(@NonNull String apn) { + synchronized (mApnUnthrottledCallbacks) { + for (IDataServiceCallback callback : mApnUnthrottledCallbacks) { + mHandler.obtainMessage(DATA_SERVICE_INDICATION_APN_UNTHROTTLED, + mSlotIndex, 0, new ApnUnthrottledIndication(apn, + callback)).sendToTarget(); + } + } + } + + /** * Called when the instance of data service is destroyed (e.g. got unbind or binder died) * or when the data service provider is removed. The extended class should implement this * method to perform cleanup works. @@ -429,6 +462,16 @@ public abstract class DataService extends Service { } } + private static final class ApnUnthrottledIndication { + public final String apn; + public final IDataServiceCallback callback; + ApnUnthrottledIndication(String apn, + IDataServiceCallback callback) { + this.apn = apn; + this.callback = callback; + } + } + private class DataServiceHandler extends Handler { DataServiceHandler(Looper looper) { @@ -544,6 +587,26 @@ public abstract class DataService extends Service { (cReq.callback != null) ? new DataServiceCallback(cReq.callback) : null); break; + case DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED: + if (serviceProvider == null) break; + serviceProvider.registerForApnUnthrottled((IDataServiceCallback) message.obj); + break; + case DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED: + if (serviceProvider == null) break; + callback = (IDataServiceCallback) message.obj; + serviceProvider.unregisterForApnUnthrottled(callback); + break; + case DATA_SERVICE_INDICATION_APN_UNTHROTTLED: + if (serviceProvider == null) break; + ApnUnthrottledIndication apnUnthrottledIndication = + (ApnUnthrottledIndication) message.obj; + try { + apnUnthrottledIndication.callback + .onApnUnthrottled(apnUnthrottledIndication.apn); + } catch (RemoteException e) { + loge("Failed to call onApnUnthrottled. " + e); + } + break; } } } @@ -695,6 +758,26 @@ public abstract class DataService extends Service { mHandler.obtainMessage(DATA_SERVICE_REQUEST_CANCEL_HANDOVER, slotIndex, 0, req).sendToTarget(); } + + @Override + public void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback) { + if (callback == null) { + loge("registerForUnthrottleApn: callback is null"); + return; + } + mHandler.obtainMessage(DATA_SERVICE_REQUEST_REGISTER_APN_UNTHROTTLED, slotIndex, + 0, callback).sendToTarget(); + } + + @Override + public void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback) { + if (callback == null) { + loge("uregisterForUnthrottleApn: callback is null"); + return; + } + mHandler.obtainMessage(DATA_SERVICE_REQUEST_UNREGISTER_APN_UNTHROTTLED, + slotIndex, 0, callback).sendToTarget(); + } } private void log(String s) { diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java index eef0e017f998..52bf15fd16c3 100644 --- a/telephony/java/android/telephony/data/DataServiceCallback.java +++ b/telephony/java/android/telephony/data/DataServiceCallback.java @@ -233,7 +233,7 @@ public class DataServiceCallback { */ @NonNull public static String resultCodeToString(@DataServiceCallback.ResultCode int resultCode) { - switch(resultCode) { + switch (resultCode) { case RESULT_SUCCESS: return "RESULT_SUCCESS"; case RESULT_ERROR_UNSUPPORTED: @@ -248,4 +248,22 @@ public class DataServiceCallback { return "Missing case for result code=" + resultCode; } } + + /** + * Indicates that the specified APN is no longer throttled. + * + * @param apn Access Point Name defined by the carrier. + */ + public void onApnUnthrottled(@NonNull String apn) { + if (mCallback != null) { + try { + if (DBG) Rlog.d(TAG, "onApnUnthrottled"); + mCallback.onApnUnthrottled(apn); + } catch (RemoteException e) { + Rlog.e(TAG, "onApnUnthrottled: remote exception", e); + } + } else { + Rlog.e(TAG, "onApnUnthrottled: callback is null!"); + } + } } diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index 33226feb0e35..3f1f033d6f11 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -40,4 +40,6 @@ oneway interface IDataService void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback); void startHandover(int slotId, int cid, IDataServiceCallback callback); void cancelHandover(int slotId, int cid, IDataServiceCallback callback); + void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback); + void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback); } diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl index d296e7b19be8..9cc2feac331a 100644 --- a/telephony/java/android/telephony/data/IDataServiceCallback.aidl +++ b/telephony/java/android/telephony/data/IDataServiceCallback.aidl @@ -32,4 +32,5 @@ oneway interface IDataServiceCallback void onDataCallListChanged(in List<DataCallResponse> dataCallList); void onHandoverStarted(int result); void onHandoverCancelled(int result); + void onApnUnthrottled(in String apn); } diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl index 3bf09bc19788..2904082616e7 100644 --- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl +++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl @@ -17,6 +17,7 @@ package android.telephony.data; import android.telephony.data.IQualifiedNetworksServiceCallback; +import android.telephony.data.ApnThrottleStatus; /** * {@hide} @@ -25,4 +26,5 @@ interface IQualifiedNetworksService { oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback); oneway void removeNetworkAvailabilityProvider(int slotId); + oneway void reportApnThrottleStatusChanged(int slotId, in List<ApnThrottleStatus> statuses); } diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java index 05971c4d2e70..4af63b4cf981 100644 --- a/telephony/java/android/telephony/data/QualifiedNetworksService.java +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -28,6 +28,7 @@ import android.os.Message; import android.os.RemoteException; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.Annotation.ApnType; +import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; @@ -65,6 +66,7 @@ public abstract class QualifiedNetworksService extends Service { private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER = 2; private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS = 3; private static final int QNS_UPDATE_QUALIFIED_NETWORKS = 4; + private static final int QNS_APN_THROTTLE_STATUS_CHANGED = 5; private final HandlerThread mHandlerThread; @@ -160,6 +162,17 @@ public abstract class QualifiedNetworksService extends Service { } /** + * The framework calls this method when the throttle status of an APN changes. + * + * This method is meant to be overridden. + * + * @param statuses the statuses that have changed + */ + public void reportApnThrottleStatusChanged(@NonNull List<ApnThrottleStatus> statuses) { + Log.d(TAG, "reportApnThrottleStatusChanged: statuses size=" + statuses.size()); + } + + /** * Called when the qualified networks provider is removed. The extended class should * implement this method to perform cleanup works. */ @@ -197,6 +210,12 @@ public abstract class QualifiedNetworksService extends Service { + slotIndex); } break; + case QNS_APN_THROTTLE_STATUS_CHANGED: + if (provider != null) { + List<ApnThrottleStatus> statuses = (List<ApnThrottleStatus>) message.obj; + provider.reportApnThrottleStatusChanged(statuses); + } + break; case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER: if (provider != null) { @@ -286,6 +305,13 @@ public abstract class QualifiedNetworksService extends Service { mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0) .sendToTarget(); } + + @Override + public void reportApnThrottleStatusChanged(int slotIndex, + List<ApnThrottleStatus> statuses) { + mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses) + .sendToTarget(); + } } private void log(String s) { diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 1b51936e873b..aaa68d6f7d57 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -207,6 +208,42 @@ public final class ImsCallProfile implements Parcelable { "android.telephony.ims.extra.RETRY_CALL_FAIL_NETWORKTYPE"; /** + * Extra for the call composer call priority, either {@link ImsCallProfile#PRIORITY_NORMAL} or + * {@link ImsCallProfile#PRIORITY_URGENT}. It can be set via + * {@link #setCallExtraInt(String, int)}. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY"; + + // TODO(hallliu) remove the reference to the maximum length and update it later. + /** + * Extra for the call composer call subject, a string of maximum length 60 characters. + * It can be set via {@link #setCallExtra(String, String)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT"; + + /** + * Extra for the call composer call location, an {@Link android.location.Location} parcelable + * class to represent the geolocation as a latitude and longitude pair. It can be set via + * {@link #setCallExtraParcelable(String, Parcelable)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION"; + + /** + * Extra for the call composer picture URL, a String that indicates the URL on the carrier’s + * server infrastructure to get the picture. It can be set via + * {@link #setCallExtra(String, String)}. + * + * Reference: RCC.20 Section 2.4.3.2 + */ + public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL"; + + /** * Values for EXTRA_OIR / EXTRA_CNAP */ /** @@ -244,6 +281,21 @@ public final class ImsCallProfile implements Parcelable { */ public static final int DIALSTRING_USSD = 2; + // Values for EXTRA_PRIORITY + /** + * Indicates the call composer call priority is normal. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_NORMAL = 0; + + /** + * Indicates the call composer call priority is urgent. + * + * Reference: RCC.20 Section 2.4.4.2 + */ + public static final int PRIORITY_URGENT = 1; + /** * Call is not restricted on peer side and High Definition media is supported */ @@ -588,6 +640,19 @@ public final class ImsCallProfile implements Parcelable { return mCallExtras.getInt(name, defaultValue); } + /** + * Get the call extras (Parcelable), given the extra name. + * @param name call extra name + * @return the corresponding call extra Parcelable or null if not applicable + */ + @Nullable + public <T extends Parcelable> T getCallExtraParcelable(@Nullable String name) { + if (mCallExtras != null) { + return mCallExtras.getParcelable(name); + } + return null; + } + public void setCallExtra(String name, String value) { if (mCallExtras != null) { mCallExtras.putString(name, value); @@ -607,6 +672,17 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set the call extra value (Parcelable), given the call extra name. + * @param name call extra name + * @param parcelable call extra value + */ + public void setCallExtraParcelable(@NonNull String name, @NonNull Parcelable parcelable) { + if (mCallExtras != null) { + mCallExtras.putParcelable(name, parcelable); + } + } + + /** * Set the call restrict cause, which provides the reason why a call has been restricted from * using High Definition media. */ diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java index a3efb799029a..0aff99709a52 100755 --- a/telephony/java/android/telephony/ims/ImsCallSession.java +++ b/telephony/java/android/telephony/ims/ImsCallSession.java @@ -101,10 +101,29 @@ public class ImsCallSession { */ public static class Listener { /** - * Called when a request is sent out to initiate a new session - * and 1xx response is received from the network. + * Called when the session is initiating. * - * @param session the session object that carries out the IMS session + * see: {@link ImsCallSessionListener#callSessionInitiating(ImsCallProfile)} + */ + public void callSessionInitiating(ImsCallSession session, + ImsCallProfile profile) { + // no-op + } + + /** + * Called when the session failed before initiating was called. + * + * see: {@link ImsCallSessionListener#callSessionInitiatingFailed(ImsReasonInfo)} + */ + public void callSessionInitiatingFailed(ImsCallSession session, + ImsReasonInfo reasonInfo) { + // no-op + } + + /** + * Called when the session is progressing. + * + * see: {@link ImsCallSessionListener#callSessionProgressing(ImsStreamMediaProfile)} */ public void callSessionProgressing(ImsCallSession session, ImsStreamMediaProfile profile) { @@ -1179,6 +1198,13 @@ public class ImsCallSession { * Notifies the result of the basic session operation (setup / terminate). */ @Override + public void callSessionInitiating(ImsCallProfile profile) { + if (mListener != null) { + mListener.callSessionInitiating(ImsCallSession.this, profile); + } + } + + @Override public void callSessionProgressing(ImsStreamMediaProfile profile) { if (mListener != null) { mListener.callSessionProgressing(ImsCallSession.this, profile); @@ -1193,6 +1219,13 @@ public class ImsCallSession { } @Override + public void callSessionInitiatingFailed(ImsReasonInfo reasonInfo) { + if (mListener != null) { + mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); + } + } + + @Override public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) { if (mListener != null) { mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo); diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java index 86bb5d9f0b09..db99acfd9a35 100644 --- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java +++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java @@ -53,8 +53,45 @@ public class ImsCallSessionListener { } /** - * A request has been sent out to initiate a new IMS call session and a 1xx response has been - * received from the network. + * Called when the network first begins to establish the call session and is now connecting + * to the remote party. This must be called once after {@link ImsCallSessionImplBase#start} and + * before any other method on this listener. After this is called, + * {@link #callSessionProgressing(ImsStreamMediaProfile)} must be called to communicate any + * further updates. + * <p/> + * Once this is called, {@link #callSessionTerminated} must be called + * to end the call session. In the event that the session failed before the remote party + * was contacted, {@link #callSessionInitiatingFailed} must be called. + * + * @param profile the associated {@link ImsCallProfile}. + */ + public void callSessionInitiating(@NonNull ImsCallProfile profile) { + try { + mListener.callSessionInitiating(profile); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * The IMS call session establishment has failed while initiating. + * + * @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session + * establishment failure. + */ + public void callSessionInitiatingFailed(@NonNull ImsReasonInfo reasonInfo) { + try { + mListener.callSessionInitiatingFailed(reasonInfo); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Called after the network has contacted the remote party and the call state should move to + * ALERTING. + * + * @param profile the associated {@link ImsCallProfile}. */ public void callSessionProgressing(ImsStreamMediaProfile profile) { try { @@ -65,7 +102,8 @@ public class ImsCallSessionListener { } /** - * The IMS call session has been initiated. + * Called once the outgoing IMS call session has been begun between the local and remote party. + * The call state should move to ACTIVE. * * @param profile the associated {@link ImsCallProfile}. */ @@ -82,7 +120,12 @@ public class ImsCallSessionListener { * * @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session * establishment failure. + * @deprecated {@link #callSessionInitiated(ImsCallProfile)} is called immediately after + * the session is first started which meant that there was no time in which a call to this + * method was technically valid. This method is replaced starting Android S in favor of + * {@link #callSessionInitiatingFailed(ImsReasonInfo)}. */ + @Deprecated public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) { try { mListener.callSessionInitiatedFailed(reasonInfo); diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl index ed895b77a164..ed0375251ffb 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl @@ -37,6 +37,8 @@ oneway interface IImsCallSessionListener { /** * Notifies the result of the basic session operation (setup / terminate). */ + void callSessionInitiating(in ImsCallProfile profile); + void callSessionInitiatingFailed(in ImsReasonInfo reasonInfo); void callSessionProgressing(in ImsStreamMediaProfile profile); void callSessionInitiated(in ImsCallProfile profile); void callSessionInitiatedFailed(in ImsReasonInfo reasonInfo); diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index e570fb6f5612..0b2c6d974980 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -231,8 +231,9 @@ public class MmTelFeature extends ImsFeature { * The capabilities that are used in MmTelFeature are defined as * {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE}, * {@link MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, - * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, and - * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}. + * {@link MmTelCapabilities#CAPABILITY_TYPE_UT}, + * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}, and + * {@link MmTelCapabilities#CAPABILITY_TYPE_CALL_COMPOSER}. * * The capabilities of this MmTelFeature will be set by the framework. */ @@ -275,7 +276,8 @@ public class MmTelFeature extends ImsFeature { CAPABILITY_TYPE_VOICE, CAPABILITY_TYPE_VIDEO, CAPABILITY_TYPE_UT, - CAPABILITY_TYPE_SMS + CAPABILITY_TYPE_SMS, + CAPABILITY_TYPE_CALL_COMPOSER }) @Retention(RetentionPolicy.SOURCE) public @interface MmTelCapability {} @@ -301,6 +303,11 @@ public class MmTelFeature extends ImsFeature { public static final int CAPABILITY_TYPE_SMS = 1 << 3; /** + * This MmTelFeature supports Call Composer (section 2.4 of RC.20) + */ + public static final int CAPABILITY_TYPE_CALL_COMPOSER = 1 << 4; + + /** * @hide */ @Override @@ -343,6 +350,8 @@ public class MmTelFeature extends ImsFeature { builder.append(isCapable(CAPABILITY_TYPE_UT)); builder.append(" SMS: "); builder.append(isCapable(CAPABILITY_TYPE_SMS)); + builder.append(" CALL_COMPOSER: "); + builder.append(isCapable(CAPABILITY_TYPE_CALL_COMPOSER)); builder.append("]"); return builder.toString(); } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 76fc4f7d0519..6fbde503c3a0 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -113,6 +113,7 @@ public class DctConstants { public static final int EVENT_NR_TIMER_WATCHDOG = BASE + 53; public static final int EVENT_CARRIER_CONFIG_CHANGED = BASE + 54; public static final int EVENT_SIM_STATE_UPDATED = BASE + 55; + public static final int EVENT_APN_UNTHROTTLED = BASE + 56; /***** Constants *****/ diff --git a/tests/net/Android.bp b/tests/net/Android.bp index a7622198cec7..f6a2846c9b3c 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -70,4 +70,7 @@ android_test { "android.test.base", "android.test.mock", ], + jni_libs: [ + "libservice-connectivity", + ], } diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 70f6386aa891..8e1875168a84 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -25,7 +25,6 @@ import android.content.ServiceConnection import android.net.ConnectivityManager import android.net.IDnsResolver import android.net.INetd -import android.net.INetworkPolicyManager import android.net.INetworkStatsService import android.net.LinkProperties import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL @@ -88,8 +87,6 @@ class ConnectivityServiceIntegrationTest { @Mock private lateinit var statsService: INetworkStatsService @Mock - private lateinit var policyManager: INetworkPolicyManager - @Mock private lateinit var log: IpConnectivityLog @Mock private lateinit var netd: INetd @@ -171,7 +168,7 @@ class ConnectivityServiceIntegrationTest { } private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService( - context, netManager, statsService, policyManager, dnsResolver, log, netd, deps) + context, netManager, statsService, dnsResolver, log, netd, deps) private fun makeDependencies(): ConnectivityService.Dependencies { val deps = spy(ConnectivityService.Dependencies()) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a613e5e332fc..efd852ba2f98 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -166,7 +166,6 @@ import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; -import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; @@ -183,6 +182,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkPolicyManager; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; @@ -365,7 +365,6 @@ public class ConnectivityServiceTest { @Mock INetworkManagementService mNetworkManagementService; @Mock INetworkStatsService mStatsService; @Mock IBatteryStats mBatteryStatsService; - @Mock INetworkPolicyManager mNpm; @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; @@ -380,6 +379,7 @@ public class ConnectivityServiceTest { @Mock TelephonyManager mTelephonyManager; @Mock MockableSystemProperties mSystemProperties; @Mock EthernetManager mEthernetManager; + @Mock NetworkPolicyManager mNetworkPolicyManager; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -477,6 +477,7 @@ public class ConnectivityServiceTest { if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager; if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager; if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager; + if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager; return super.getSystemService(name); } @@ -1326,7 +1327,6 @@ public class ConnectivityServiceTest { mService = new ConnectivityService(mServiceContext, mNetworkManagementService, mStatsService, - mNpm, mMockDnsResolver, mock(IpConnectivityLog.class), mMockNetd, @@ -1336,7 +1336,7 @@ public class ConnectivityServiceTest { final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor = ArgumentCaptor.forClass(INetworkPolicyListener.class); - verify(mNpm).registerListener(policyListenerCaptor.capture()); + verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture()); mPolicyListener = policyListenerCaptor.getValue(); // Create local CM before sending system ready so that we can answer @@ -7810,8 +7810,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission( @@ -7826,8 +7825,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7842,8 +7840,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7859,8 +7856,7 @@ public class ConnectivityServiceTest { public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception { final Network network = new Network(NET_ID); final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, network, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, @@ -7894,8 +7890,7 @@ public class ConnectivityServiceTest { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setAdministratorUids(new int[] {Process.myUid()}); final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo( - null, null, null, null, null, nc, 0, mServiceContext, null, null, + new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, @@ -7914,8 +7909,7 @@ public class ConnectivityServiceTest { nc.setOwnerUid(Process.myUid()); nc.setAdministratorUids(new int[] {Process.myUid()}); final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo( - null, null, null, null, null, nc, 0, mServiceContext, null, null, + new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index aafa18a532fa..96c56e32f156 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -353,7 +353,7 @@ public class LingerMonitorTest { NetworkCapabilities caps = new NetworkCapabilities(); caps.addCapability(0); caps.addTransportType(transport); - NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, + NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null, caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE, Binder.getCallingUid()); nai.everValidated = true; diff --git a/wifi/MOVED.txt b/wifi/MOVED.txt new file mode 100644 index 000000000000..6ffb23cb0aaf --- /dev/null +++ b/wifi/MOVED.txt @@ -0,0 +1,8 @@ +Source code and tests for Wifi module APIs have moved to +packages/modules/Wifi/framework. + +- frameworks/base/wifi/java -> packages/modules/Wifi/framework/java +- frameworks/base/wifi/tests -> packages/modules/Wifi/framework/tests + +What remains in frameworks/base/wifi are Wifi APIs that +are not part of the Wifi module. |