diff options
Diffstat (limited to 'services')
30 files changed, 1384 insertions, 578 deletions
diff --git a/services/core/Android.bp b/services/core/Android.bp index f91e69240605..c40afbfe4f97 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -209,7 +209,6 @@ filegroup { "java/com/android/server/TestNetworkService.java", "java/com/android/server/connectivity/AutodestructReference.java", "java/com/android/server/connectivity/ConnectivityConstants.java", - "java/com/android/server/connectivity/ConnectivityResources.java", "java/com/android/server/connectivity/DnsManager.java", "java/com/android/server/connectivity/KeepaliveTracker.java", "java/com/android/server/connectivity/LingerMonitor.java", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3194bdcaad18..a0bdd7f63cfc 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -69,11 +69,14 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_VPN; -import static android.net.NetworkPolicyManager.RULE_NONE; -import static android.net.NetworkPolicyManager.uidRulesToString; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE; +import static android.net.NetworkPolicyManager.blockedReasonsToString; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired; import static android.os.Process.INVALID_UID; @@ -106,6 +109,8 @@ import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityDiagnosticsManager.DataStallReport; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.ConnectivityManager.RestrictBackgroundStatus; +import android.net.ConnectivityResources; import android.net.ConnectivitySettingsManager; import android.net.DataStallReportParcelable; import android.net.DnsResolverServiceManager; @@ -115,9 +120,9 @@ import android.net.IConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkActivityListener; +import android.net.INetworkAgent; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; -import android.net.INetworkPolicyListener; import android.net.IOnCompleteListener; import android.net.IQosCallback; import android.net.ISocketKeepaliveCallback; @@ -135,6 +140,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMonitorManager; import android.net.NetworkPolicyManager; +import android.net.NetworkPolicyManager.NetworkPolicyCallback; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; @@ -208,7 +214,6 @@ import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; -import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; @@ -222,7 +227,6 @@ import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.PermissionUtils; import com.android.server.connectivity.AutodestructReference; -import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.KeepaliveTracker; @@ -237,7 +241,6 @@ import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProfileNetworkPreferences; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; -import com.android.server.net.NetworkPolicyManagerInternal; import libcore.io.IoUtils; @@ -285,7 +288,7 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed * by OEMs for configuration purposes, as this value is overridden by - * Settings.Global.CAPTIVE_PORTAL_HTTP_URL. + * ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL. * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose * (preferably via runtime resource overlays). */ @@ -318,7 +321,7 @@ public class ConnectivityService extends IConnectivityManager.Stub protected int mNascentDelayMs; // How long to delay to removal of a pending intent based request. - // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS + // See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS private final int mReleasePendingIntentDelayMs; private MockableSystemProperties mSystemProperties; @@ -331,12 +334,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private volatile boolean mLockdownEnabled; /** - * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal - * handler thread, they don't need a lock. + * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in + * internal handler thread, they don't need a lock. */ - private SparseIntArray mUidRules = new SparseIntArray(); - /** Flag indicating if background data is restricted. */ - private boolean mRestrictBackground; + private SparseIntArray mUidBlockedReasons = new SparseIntArray(); private final Context mContext; private final ConnectivityResources mResources; @@ -352,7 +353,6 @@ public class ConnectivityService extends IConnectivityManager.Stub protected INetd mNetd; private NetworkStatsManager mStatsManager; private NetworkPolicyManager mPolicyManager; - private NetworkPolicyManagerInternal mPolicyManagerInternal; private final NetdCallback mNetdCallback; /** @@ -510,16 +510,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Handle private DNS validation status updates. private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38; - /** - * Used to handle onUidRulesChanged event from NetworkPolicyManagerService. - */ - private static final int EVENT_UID_RULES_CHANGED = 39; - - /** - * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService. - */ - private static final int EVENT_DATA_SAVER_CHANGED = 40; - /** * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has * been tested. @@ -596,6 +586,13 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50; /** + * Event to specify that reasons for why an uid is blocked changed. + * arg1 = uid + * arg2 = blockedReasons + */ + private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51; + + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. */ @@ -1206,7 +1203,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRanker = new NetworkRanker(); final NetworkRequest defaultInternetRequest = createDefaultRequest(); mDefaultRequest = new NetworkRequestInfo( - defaultInternetRequest, null, + Process.myUid(), defaultInternetRequest, null, new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */); mNetworkRequests.put(defaultInternetRequest, mDefaultRequest); @@ -1234,7 +1231,7 @@ public class ConnectivityService extends IConnectivityManager.Stub new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper()); mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000); + ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000); mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); // TODO: Consider making the timer customizable. @@ -1242,9 +1239,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mStatsManager = mContext.getSystemService(NetworkStatsManager.class); mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); - mPolicyManagerInternal = Objects.requireNonNull( - LocalServices.getService(NetworkPolicyManagerInternal.class), - "missing NetworkPolicyManagerInternal"); mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver"); mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler); @@ -1253,10 +1247,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); - // To ensure uid rules are synchronized with Network Policy, register for + // To ensure uid state is synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService // reading existing policy from disk. - mPolicyManager.registerListener(mPolicyListener); + mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback); final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); @@ -1306,10 +1300,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter); final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, + ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT); final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(), - Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, + ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS); mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); @@ -1344,7 +1338,7 @@ public class ConnectivityService extends IConnectivityManager.Stub netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.removeCapability(NET_CAPABILITY_NOT_VPN); - netCap.setUids(Collections.singleton(uids)); + netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids))); return netCap; } @@ -1416,8 +1410,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (enable) { handleRegisterNetworkRequest(new NetworkRequestInfo( - networkRequest, null, - new Binder(), + Process.myUid(), networkRequest, null, new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */)); } else { @@ -1427,10 +1420,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void handleConfigureAlwaysOnNetworks() { - handleAlwaysOnNetworkRequest( - mDefaultMobileDataRequest, Settings.Global.MOBILE_DATA_ALWAYS_ON, true); - handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED, - false); + handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest, + ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */); + handleAlwaysOnNetworkRequest(mDefaultWifiRequest, + ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */); handleAlwaysOnNetworkRequest(mDefaultVehicleRequest, com.android.internal.R.bool.config_vehicleInternalNetworkAlwaysRequested); } @@ -1443,12 +1436,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // Watch for whether or not to keep mobile data always on. mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON), + Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON), EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); // Watch for whether or not to keep wifi always on. mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED), + Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED), EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); } @@ -1564,7 +1557,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final int requestId = nri.getActiveRequest() != null ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId; mNetworkInfoBlockingLogs.log(String.format( - "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId())); + "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId())); } /** @@ -1780,12 +1773,13 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.network, createWithLocationInfoSanitizedIfNecessaryWhenParceled( nc, false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); + getCallingPid(), mDeps.getCallingUid(), callingPackageName, + callingAttributionTag)); } } // No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null. - final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid()); + final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid()); if (null != networks) { for (final Network network : networks) { final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network); @@ -1795,7 +1789,7 @@ public class ConnectivityService extends IConnectivityManager.Stub createWithLocationInfoSanitizedIfNecessaryWhenParceled( nc, false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, + getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); } } @@ -1878,7 +1872,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return createWithLocationInfoSanitizedIfNecessaryWhenParceled( getNetworkCapabilitiesInternal(network), false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, callingAttributionTag); + getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag); } @VisibleForTesting @@ -1897,40 +1891,137 @@ public class ConnectivityService extends IConnectivityManager.Stub return newNc; } - private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName, - @Nullable String callingAttributionTag) { - final long token = Binder.clearCallingIdentity(); - try { - return mLocationPermissionChecker.checkLocationPermission( - callerPkgName, callingAttributionTag, callerUid, null /* message */); - } finally { - Binder.restoreCallingIdentity(token); + /** + * Wrapper used to cache the permission check results performed for the corresponding + * app. This avoid performing multiple permission checks for different fields in + * NetworkCapabilities. + * Note: This wrapper does not support any sort of invalidation and thus must not be + * persistent or long-lived. It may only be used for the time necessary to + * compute the redactions required by one particular NetworkCallback or + * synchronous call. + */ + private class RedactionPermissionChecker { + private final int mCallingPid; + private final int mCallingUid; + @NonNull private final String mCallingPackageName; + @Nullable private final String mCallingAttributionTag; + + private Boolean mHasLocationPermission = null; + private Boolean mHasLocalMacAddressPermission = null; + private Boolean mHasSettingsPermission = null; + + RedactionPermissionChecker(int callingPid, int callingUid, + @NonNull String callingPackageName, @Nullable String callingAttributionTag) { + mCallingPid = callingPid; + mCallingUid = callingUid; + mCallingPackageName = callingPackageName; + mCallingAttributionTag = callingAttributionTag; + } + + private boolean hasLocationPermissionInternal() { + final long token = Binder.clearCallingIdentity(); + try { + return mLocationPermissionChecker.checkLocationPermission( + mCallingPackageName, mCallingAttributionTag, mCallingUid, + null /* message */); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Returns whether the app holds location permission or not (might return cached result + * if the permission was already checked before). + */ + public boolean hasLocationPermission() { + if (mHasLocationPermission == null) { + // If there is no cached result, perform the check now. + mHasLocationPermission = hasLocationPermissionInternal(); + } + return mHasLocationPermission; + } + + /** + * Returns whether the app holds local mac address permission or not (might return cached + * result if the permission was already checked before). + */ + public boolean hasLocalMacAddressPermission() { + if (mHasLocalMacAddressPermission == null) { + // If there is no cached result, perform the check now. + mHasLocalMacAddressPermission = + checkLocalMacAddressPermission(mCallingPid, mCallingUid); + } + return mHasLocalMacAddressPermission; + } + + /** + * Returns whether the app holds settings permission or not (might return cached + * result if the permission was already checked before). + */ + public boolean hasSettingsPermission() { + if (mHasSettingsPermission == null) { + // If there is no cached result, perform the check now. + mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid); + } + return mHasSettingsPermission; + } + } + + private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions, + @NetworkCapabilities.NetCapability long redaction) { + return (redactions & redaction) != 0; + } + + /** + * Use the provided |applicableRedactions| to check the receiving app's + * permissions and clear/set the corresponding bit in the returned bitmask. The bitmask + * returned will be used to ensure the necessary redactions are performed by NetworkCapabilities + * before being sent to the corresponding app. + */ + private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions( + @NetworkCapabilities.RedactionType long applicableRedactions, + @NonNull RedactionPermissionChecker redactionPermissionChecker, + boolean includeLocationSensitiveInfo) { + long redactions = applicableRedactions; + if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) { + if (includeLocationSensitiveInfo + && redactionPermissionChecker.hasLocationPermission()) { + redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION; + } + } + if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) { + if (redactionPermissionChecker.hasLocalMacAddressPermission()) { + redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS; + } + } + if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) { + if (redactionPermissionChecker.hasSettingsPermission()) { + redactions &= ~REDACT_FOR_NETWORK_SETTINGS; + } } + return redactions; } @VisibleForTesting @Nullable NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled( @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo, - int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) { + int callingPid, int callingUid, @NonNull String callingPkgName, + @Nullable String callingAttributionTag) { if (nc == null) { return null; } - Boolean hasLocationPermission = null; - final NetworkCapabilities newNc; // Avoid doing location permission check if the transport info has no location sensitive // data. - if (includeLocationSensitiveInfo - && nc.getTransportInfo() != null - && nc.getTransportInfo().hasLocationSensitiveFields()) { - hasLocationPermission = - hasLocationPermission(callerUid, callerPkgName, callingAttributionTag); - newNc = new NetworkCapabilities(nc, hasLocationPermission); - } else { - newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */); - } + final RedactionPermissionChecker redactionPermissionChecker = + new RedactionPermissionChecker(callingPid, callingUid, callingPkgName, + callingAttributionTag); + final long redactions = retrieveRequiredRedactions( + nc.getApplicableRedactions(), redactionPermissionChecker, + includeLocationSensitiveInfo); + final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions); // Reset owner uid if not destined for the owner app. - if (callerUid != nc.getOwnerUid()) { + if (callingUid != nc.getOwnerUid()) { newNc.setOwnerUid(INVALID_UID); return newNc; } @@ -1939,23 +2030,17 @@ public class ConnectivityService extends IConnectivityManager.Stub // Owner UIDs already checked above. No need to re-check. return newNc; } - // If the caller does not want location sensitive data & target SDK >= S, then mask info. - // Else include the owner UID iff the caller has location permission to provide backwards + // If the calling does not want location sensitive data & target SDK >= S, then mask info. + // Else include the owner UID iff the calling has location permission to provide backwards // compatibility for older apps. if (!includeLocationSensitiveInfo && isTargetSdkAtleast( - Build.VERSION_CODES.S, callerUid, callerPkgName)) { + Build.VERSION_CODES.S, callingUid, callingPkgName)) { newNc.setOwnerUid(INVALID_UID); return newNc; } - - if (hasLocationPermission == null) { - // Location permission not checked yet, check now for masking owner UID. - hasLocationPermission = - hasLocationPermission(callerUid, callerPkgName, callingAttributionTag); - } // Reset owner uid if the app has no location permission. - if (!hasLocationPermission) { + if (!redactionPermissionChecker.hasLocationPermission()) { newNc.setOwnerUid(INVALID_UID); } return newNc; @@ -1987,6 +2072,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc, int callerUid, String callerPackageName) { if (!checkSettingsPermission()) { + // There is no need to track the effective UID of the request here. If the caller lacks + // the settings permission, the effective UID is the same as the calling ID. nc.setSingleUid(callerUid); } nc.setRequestorUidAndPackageName(callerUid, callerPackageName); @@ -2002,6 +2089,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @Override + public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() { + enforceAccessPermission(); + final int callerUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + return mPolicyManager.getRestrictBackgroundStatus(callerUid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + // TODO: Consider delete this function or turn it into a no-op method. @Override public NetworkState[] getAllNetworkState() { @@ -2237,53 +2336,17 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { - @Override - public void onUidRulesChanged(int uid, int uidRules) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules)); - } + private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() { @Override - public void onRestrictBackgroundChanged(boolean restrictBackground) { - // caller is NPMS, since we only register with them - if (LOGD_BLOCKED_NETWORKINFO) { - log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); - } - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0)); + public void onUidBlockedReasonChanged(int uid, int blockedReasons) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED, + uid, blockedReasons)); } }; - void handleUidRulesChanged(int uid, int newRules) { - // skip update when we've already applied rules - final int oldRules = mUidRules.get(uid, RULE_NONE); - if (oldRules == newRules) return; - - maybeNotifyNetworkBlockedForNewUidRules(uid, newRules); - - if (newRules == RULE_NONE) { - mUidRules.delete(uid); - } else { - mUidRules.put(uid, newRules); - } - } - - void handleRestrictBackgroundChanged(boolean restrictBackground) { - if (mRestrictBackground == restrictBackground) return; - - final List<UidRange> blockedRanges = mVpnBlockedUidRanges; - for (final NetworkAgentInfo nai : mNetworkAgentInfos) { - final boolean curMetered = nai.networkCapabilities.isMetered(); - maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, - restrictBackground, blockedRanges, blockedRanges); - } - - mRestrictBackground = restrictBackground; - } - - private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered, - boolean isBackgroundRestricted) { - return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered, - isBackgroundRestricted); + void handleUidBlockedReasonChanged(int uid, int blockedReasons) { + maybeNotifyNetworkBlockedForNewState(uid, blockedReasons); + mUidBlockedReasons.put(uid, blockedReasons); } private boolean checkAnyPermissionOf(String... permissions) { @@ -2470,6 +2533,11 @@ public class ConnectivityService extends IConnectivityManager.Stub mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService"); } + private boolean checkLocalMacAddressPermission(int pid, int uid) { + return PERMISSION_GRANTED == mContext.checkPermission( + Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid); + } + private void sendConnectedBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -2757,19 +2825,16 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.println(); - pw.print("Restrict background: "); - pw.println(mRestrictBackground); - pw.println(); - pw.println("Status for known UIDs:"); pw.increaseIndent(); - final int size = mUidRules.size(); + final int size = mUidBlockedReasons.size(); for (int i = 0; i < size; i++) { // Don't crash if the array is modified while dumping in bugreports. try { - final int uid = mUidRules.keyAt(i); - final int uidRules = mUidRules.get(uid, RULE_NONE); - pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules)); + final int uid = mUidBlockedReasons.keyAt(i); + final int blockedReasons = mUidBlockedReasons.valueAt(i); + pw.println("UID=" + uid + " blockedReasons=" + + blockedReasonsToString(blockedReasons)); } catch (ArrayIndexOutOfBoundsException e) { pw.println(" ArrayIndexOutOfBoundsException"); } catch (ConcurrentModificationException e) { @@ -2904,7 +2969,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (0 == defaultRequest.mRequests.size()) { pw.println("none, this should never occur."); } else { - pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids()); + pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges()); } pw.decreaseIndent(); pw.decreaseIndent(); @@ -3005,6 +3070,9 @@ public class ConnectivityService extends IConnectivityManager.Stub case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: { if (nai.everConnected) { loge("ERROR: cannot call explicitlySelected on already-connected network"); + // Note that if the NAI had been connected, this would affect the + // score, and therefore would require re-mixing the score and performing + // a rematch. } nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1); nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2); @@ -3110,7 +3178,8 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; if (nai.lastCaptivePortalDetected && - Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { + ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID + == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.toShortString()); nai.onPreventAutomaticReconnect(); teardownUnneededNetwork(nai); @@ -3221,8 +3290,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private int getCaptivePortalMode() { return Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.CAPTIVE_PORTAL_MODE, - Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); + ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, + ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT); } private boolean maybeHandleNetworkAgentInfoMessage(Message msg) { @@ -3690,7 +3759,7 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Replacing " + existingRequest.mRequests.get(0) + " with " + nri.mRequests.get(0) + " because their intents matched."); } - handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(), + handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(), /* callOnUnavailable */ false); } handleRegisterNetworkRequest(nri); @@ -4088,6 +4157,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // network, we should respect the user's option and don't need to popup the // PARTIAL_CONNECTIVITY notification to user again. nai.networkAgentConfig.acceptPartialConnectivity = accept; + nai.updateScoreForNetworkAgentConfigUpdate(); rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } @@ -4350,7 +4420,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Intent intent = new Intent(action); if (type != NotificationType.PRIVATE_DNS_BROKEN) { - intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null)); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Some OEMs have their own Settings package. Thus, need to get the current using // Settings package name instead of just use default name "com.android.settings". @@ -4446,7 +4516,13 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkPolicyManager netPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); - final int networkPreference = netPolicyManager.getMultipathPreference(network); + final long token = Binder.clearCallingIdentity(); + final int networkPreference; + try { + networkPreference = netPolicyManager.getMultipathPreference(network); + } finally { + Binder.restoreCallingIdentity(token); + } if (networkPreference != 0) { return networkPreference; } @@ -4565,11 +4641,8 @@ public class ConnectivityService extends IConnectivityManager.Stub handlePrivateDnsValidationUpdate( (PrivateDnsValidationUpdate) msg.obj); break; - case EVENT_UID_RULES_CHANGED: - handleUidRulesChanged(msg.arg1, msg.arg2); - break; - case EVENT_DATA_SAVER_CHANGED: - handleRestrictBackgroundChanged(toBool(msg.arg1)); + case EVENT_UID_BLOCKED_REASON_CHANGED: + handleUidBlockedReasonChanged(msg.arg1, msg.arg2); break; case EVENT_SET_REQUIRE_VPN_FOR_UIDS: handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj); @@ -5042,8 +5115,8 @@ public class ConnectivityService extends IConnectivityManager.Stub for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean curMetered = nai.networkCapabilities.isMetered(); - maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges); + maybeNotifyNetworkBlocked(nai, curMetered, curMetered, + mVpnBlockedUidRanges, newVpnBlockedUidRanges); } mVpnBlockedUidRanges = newVpnBlockedUidRanges; @@ -5291,6 +5364,8 @@ public class ConnectivityService extends IConnectivityManager.Stub boolean mPendingIntentSent; @Nullable final Messenger mMessenger; + + // Information about the caller that caused this object to be created. @Nullable private final IBinder mBinder; final int mPid; @@ -5298,6 +5373,13 @@ public class ConnectivityService extends IConnectivityManager.Stub final @NetworkCallback.Flag int mCallbackFlags; @Nullable final String mCallingAttributionTag; + + // Effective UID of this request. This is different from mUid when a privileged process + // files a request on behalf of another UID. This UID is used to determine blocked status, + // UID matching, and so on. mUid above is used for permission checks and to enforce the + // maximum limit of registered callbacks per UID. + final int mAsUid; + // In order to preserve the mapping of NetworkRequest-to-callback when apps register // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be // maintained for keying off of. This is only a concern when the original nri @@ -5321,17 +5403,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private Set<UidRange> getUids() { // networkCapabilities.getUids() returns a defensive copy. // multilayer requests will all have the same uids so return the first one. - final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids() - ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids(); - return uids; + final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges(); + return (null == uids) ? new ArraySet<>() : uids; } - NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi, - @Nullable String callingAttributionTag) { - this(Collections.singletonList(r), r, pi, callingAttributionTag); + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, + @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) { + this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r, + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r, @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) { ensureAllNetworkRequestsHaveType(r); @@ -5342,6 +5423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = null; mPid = getCallingPid(); mUid = mDeps.getCallingUid(); + mAsUid = asUid; mNetworkRequestCounter.incrementCountOrThrow(mUid); /** * Location sensitive data not included in pending intent. Only included in @@ -5351,14 +5433,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mCallingAttributionTag = callingAttributionTag; } - NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m, + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @Nullable String callingAttributionTag) { - this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag); + this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags, + callingAttributionTag); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r, + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r, @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @@ -5371,6 +5454,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = binder; mPid = getCallingPid(); mUid = mDeps.getCallingUid(); + mAsUid = asUid; mPendingIntent = null; mNetworkRequestCounter.incrementCountOrThrow(mUid); mCallbackFlags = callbackFlags; @@ -5413,18 +5497,19 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = nri.mBinder; mPid = nri.mPid; mUid = nri.mUid; + mAsUid = nri.mAsUid; mPendingIntent = nri.mPendingIntent; mNetworkRequestCounter.incrementCountOrThrow(mUid); mCallbackFlags = nri.mCallbackFlags; mCallingAttributionTag = nri.mCallingAttributionTag; } - NetworkRequestInfo(@NonNull final NetworkRequest r) { - this(Collections.singletonList(r)); + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) { + this(asUid, Collections.singletonList(r)); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r) { - this(r, r.get(0), null /* pi */, null /* callingAttributionTag */); + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) { + this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */); } // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer @@ -5460,9 +5545,10 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String toString() { - return "uid/pid:" + mUid + "/" + mPid + " active request Id: " + final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid; + return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: " + (mActiveRequest == null ? null : mActiveRequest.requestId) - + " callback request Id: " + + " callbackRequest: " + mNetworkRequestForCallback.requestId + " " + mRequests + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent) @@ -5563,7 +5649,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, + public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities, int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder, int legacyType, int callbackFlags, @NonNull String callingPackageName, @Nullable String callingAttributionTag) { @@ -5575,6 +5661,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities; final int callingUid = mDeps.getCallingUid(); + // Privileged callers can track the default network of another UID by passing in a UID. + if (asUid != Process.INVALID_UID) { + enforceSettingsPermission(); + } else { + asUid = callingUid; + } final NetworkRequest.Type reqType; try { reqType = NetworkRequest.Type.values()[reqTypeInt]; @@ -5584,10 +5676,10 @@ public class ConnectivityService extends IConnectivityManager.Stub switch (reqType) { case TRACK_DEFAULT: // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities} - // is unused and will be replaced by ones appropriate for the caller. - // This allows callers to keep track of the default network for their app. + // is unused and will be replaced by ones appropriate for the UID (usually, the + // calling app). This allows callers to keep track of the default network. networkCapabilities = copyDefaultNetworkCapabilitiesForUid( - defaultNc, callingUid, callingPackageName); + defaultNc, asUid, callingUid, callingPackageName); enforceAccessPermission(); break; case TRACK_SYSTEM_DEFAULT: @@ -5639,7 +5731,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId(), reqType); final NetworkRequestInfo nri = getNriToRegister( - networkRequest, messenger, binder, callbackFlags, callingAttributionTag); + asUid, networkRequest, messenger, binder, callbackFlags, + callingAttributionTag); if (DBG) log("requestNetwork for " + nri); // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were @@ -5666,25 +5759,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * requests registered to track the default request. If there is currently a per-app default * tracking the app requestor, then we need to create a version of this nri that mirrors that of * the tracking per-app default so that callbacks are sent to the app requestor appropriately. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param nr the network request for the nri. * @param msgr the messenger for the nri. * @param binder the binder for the nri. * @param callingAttributionTag the calling attribution tag for the nri. * @return the nri to register. */ - private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr, + private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr, @Nullable final Messenger msgr, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @Nullable String callingAttributionTag) { final List<NetworkRequest> requests; if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) { requests = copyDefaultNetworkRequestsForUid( - nr.getRequestorUid(), nr.getRequestorPackageName()); + asUid, nr.getRequestorUid(), nr.getRequestorPackageName()); } else { requests = Collections.singletonList(nr); } return new NetworkRequestInfo( - requests, nr, msgr, binder, callbackFlags, callingAttributionTag); + asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag); } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities, @@ -5765,8 +5860,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); - NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, operation, callingAttributionTag); + NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation, + callingAttributionTag); if (DBG) log("pendingRequest for " + nri); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri)); @@ -5776,14 +5871,14 @@ public class ConnectivityService extends IConnectivityManager.Stub private void releasePendingNetworkRequestWithDelay(PendingIntent operation) { mHandler.sendMessageDelayed( mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, - getCallingUid(), 0, operation), mReleasePendingIntentDelayMs); + mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs); } @Override public void releasePendingNetworkRequest(PendingIntent operation) { Objects.requireNonNull(operation, "PendingIntent cannot be null."); mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, - getCallingUid(), 0, operation)); + mDeps.getCallingUid(), 0, operation)); } // In order to implement the compatibility measure for pre-M apps that call @@ -5833,7 +5928,7 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags, + new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags, callingAttributionTag); if (VDBG) log("listenForNetwork for " + nri); @@ -5858,8 +5953,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); - NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, operation, callingAttributionTag); + NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation, + callingAttributionTag); if (VDBG) log("pendingListenForNetwork for " + nri); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); @@ -5880,7 +5975,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void releaseNetworkRequest(NetworkRequest networkRequest) { ensureNetworkRequestHasType(networkRequest); mHandler.sendMessage(mHandler.obtainMessage( - EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest)); + EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest)); } private void handleRegisterNetworkProvider(NetworkProviderInfo npi) { @@ -6009,33 +6104,37 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Get a copy of the network requests of the default request that is currently tracking the * given uid. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param requestorUid the uid to check the default for. * @param requestorPackageName the requestor's package name. * @return a copy of the default's NetworkRequest that is tracking the given uid. */ @NonNull private List<NetworkRequest> copyDefaultNetworkRequestsForUid( - @NonNull final int requestorUid, @NonNull final String requestorPackageName) { + final int asUid, final int requestorUid, @NonNull final String requestorPackageName) { return copyNetworkRequestsForUid( - getDefaultRequestTrackingUid(requestorUid).mRequests, - requestorUid, requestorPackageName); + getDefaultRequestTrackingUid(asUid).mRequests, + asUid, requestorUid, requestorPackageName); } /** * Copy the given nri's NetworkRequest collection. * @param requestsToCopy the NetworkRequest collection to be copied. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param requestorUid the uid to set on the copied collection. * @param requestorPackageName the package name to set on the copied collection. * @return the copied NetworkRequest collection. */ @NonNull private List<NetworkRequest> copyNetworkRequestsForUid( - @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid, - @NonNull final String requestorPackageName) { + @NonNull final List<NetworkRequest> requestsToCopy, final int asUid, + final int requestorUid, @NonNull final String requestorPackageName) { final List<NetworkRequest> requests = new ArrayList<>(); for (final NetworkRequest nr : requestsToCopy) { requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid( - nr.networkCapabilities, requestorUid, requestorPackageName), + nr.networkCapabilities, asUid, requestorUid, requestorPackageName), nr.legacyType, nextNetworkRequestId(), nr.type)); } return requests; @@ -6043,12 +6142,17 @@ public class ConnectivityService extends IConnectivityManager.Stub @NonNull private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid( - @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid, - @NonNull final String requestorPackageName) { + @NonNull final NetworkCapabilities netCapToCopy, final int asUid, + final int requestorUid, @NonNull final String requestorPackageName) { + // These capabilities are for a TRACK_DEFAULT callback, so: + // 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between + // mDefaultRequest and a per-UID default request. + // TODO: stop depending on the fact that these two unrelated things happen to be the same + // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will + // not do this in the case of a privileged application. final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy); netCap.removeCapability(NET_CAPABILITY_NOT_VPN); - netCap.setSingleUid(requestorUid); - netCap.setUids(new ArraySet<>()); + netCap.setSingleUid(asUid); restrictRequestUidsForCallerAndSetRequestorInfo( netCap, requestorUid, requestorPackageName); return netCap; @@ -6129,7 +6233,7 @@ public class ConnectivityService extends IConnectivityManager.Stub for (final NetworkRequestInfo nri : mDefaultNetworkRequests) { // Currently, all network requests will have the same uids therefore checking the first // one is sufficient. If/when uids are tracked at the nri level, this can change. - final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids(); + final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges(); if (null == uids) { continue; } @@ -6570,7 +6674,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } - final Set<UidRange> ranges = nai.networkCapabilities.getUids(); + final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges(); final int vpnAppUid = nai.networkCapabilities.getOwnerUid(); // TODO: this create a window of opportunity for apps to receive traffic between the time // when the old rules are removed and the time when new rules are added. To fix this, @@ -6826,8 +6930,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean meteredChanged = oldMetered != newMetered; if (meteredChanged) { - maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); + maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, + mVpnBlockedUidRanges, mVpnBlockedUidRanges); } final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) @@ -6935,8 +7039,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, NetworkCapabilities newNc) { - Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids(); - Set<UidRange> newRanges = null == newNc ? null : newNc.getUids(); + Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges(); + Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges(); if (null == prevRanges) prevRanges = new ArraySet<>(); if (null == newRanges) newRanges = new ArraySet<>(); final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges); @@ -7172,7 +7276,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, includeLocationSensitiveInfo, nri.mUid, + nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid, nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( @@ -7193,7 +7297,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, includeLocationSensitiveInfo, nri.mUid, + netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid, nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); break; @@ -7949,9 +8053,9 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean metered = nai.networkCapabilities.isMetered(); boolean blocked; - blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges); - blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid), - metered, mRestrictBackground); + blocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges); + blocked |= NetworkPolicyManager.isUidBlocked( + mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE), metered); callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0); } @@ -7969,27 +8073,26 @@ public class ConnectivityService extends IConnectivityManager.Stub * * @param nai The target NetworkAgentInfo. * @param oldMetered True if the previous network capabilities is metered. - * @param newRestrictBackground True if data saver is enabled. */ private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered, - boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground, - List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) { + boolean newMetered, List<UidRange> oldBlockedUidRanges, + List<UidRange> newBlockedUidRanges) { for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest nr = nai.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); - final int uidRules = mUidRules.get(nri.mUid); final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked; - oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges); + oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges); newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges) - ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges) + ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges) : oldVpnBlocked; - oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered, - oldRestrictBackground); - newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered, - newRestrictBackground); + final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE); + oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked( + blockedReasons, oldMetered); + newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked( + blockedReasons, newMetered); if (oldBlocked != newBlocked) { callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, @@ -7999,19 +8102,20 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Notify apps with a given UID of the new blocked state according to new uid rules. + * Notify apps with a given UID of the new blocked state according to new uid state. * @param uid The uid for which the rules changed. - * @param newRules The new rules to apply. + * @param blockedReasons The reasons for why an uid is blocked. */ - private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) { + private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) { for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean metered = nai.networkCapabilities.isMetered(); final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges); final boolean oldBlocked, newBlocked; - oldBlocked = vpnBlocked || isUidBlockedByRules( - uid, mUidRules.get(uid), metered, mRestrictBackground); - newBlocked = vpnBlocked || isUidBlockedByRules( - uid, newRules, metered, mRestrictBackground); + + oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( + mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered); + newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( + blockedReasons, metered); if (oldBlocked == newBlocked) { continue; } @@ -8019,7 +8123,7 @@ public class ConnectivityService extends IConnectivityManager.Stub for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest nr = nai.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); - if (nri != null && nri.mUid == uid) { + if (nri != null && nri.mAsUid == uid) { callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg); } } @@ -8159,7 +8263,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } settingUrl = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.CAPTIVE_PORTAL_HTTP_URL); + ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL); if (!TextUtils.isEmpty(settingUrl)) { return settingUrl; } @@ -8241,7 +8345,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // restore private DNS settings to default mode (opportunistic) if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) { Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC); + ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC); } Settings.Global.putString(mContext.getContentResolver(), @@ -8358,7 +8462,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo vpn = getVpnForUid(uid); if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE - || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) { + || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) { return INVALID_UID; } @@ -8784,7 +8888,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in // handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the // callback's binder death. - final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId); + final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId); final ConnectivityDiagnosticsCallbackInfo cbInfo = new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName); @@ -8997,13 +9101,13 @@ public class ConnectivityService extends IConnectivityManager.Stub if (networkAgent.networkCapabilities.hasTransport( NetworkCapabilities.TRANSPORT_CELLULAR)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, + ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE, 10); type = NetworkCapabilities.TRANSPORT_CELLULAR; } else if (networkAgent.networkCapabilities.hasTransport( NetworkCapabilities.TRANSPORT_WIFI)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, + ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI, 15); type = NetworkCapabilities.TRANSPORT_WIFI; } else { @@ -9267,8 +9371,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArrayList<NetworkRequest> nrs = new ArrayList<>(); nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities)); nrs.add(createDefaultRequest()); - setNetworkRequestUids(nrs, pref.capabilities.getUids()); - final NetworkRequestInfo nri = new NetworkRequestInfo(nrs); + setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids())); + final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs); result.add(nri); } return result; @@ -9439,7 +9543,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Include this nri if it will be tracked by the new per-app default requests. final boolean isNriGoingToBeTracked = - getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest; + getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest; if (isNriGoingToBeTracked) { defaultCallbackRequests.add(nri); } @@ -9461,7 +9565,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>(); for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) { final NetworkRequestInfo trackingNri = - getDefaultRequestTrackingUid(callbackRequest.mUid); + getDefaultRequestTrackingUid(callbackRequest.mAsUid); // If this nri is not being tracked, the change it back to an untracked nri. if (trackingNri == mDefaultRequest) { @@ -9471,21 +9575,20 @@ public class ConnectivityService extends IConnectivityManager.Stub continue; } - final String requestorPackageName = - callbackRequest.mRequests.get(0).getRequestorPackageName(); + final NetworkRequest request = callbackRequest.mRequests.get(0); callbackRequestsToRegister.add(new NetworkRequestInfo( callbackRequest, copyNetworkRequestsForUid( - trackingNri.mRequests, callbackRequest.mUid, requestorPackageName))); + trackingNri.mRequests, callbackRequest.mAsUid, + callbackRequest.mUid, request.getRequestorPackageName()))); } return callbackRequestsToRegister; } private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests, @NonNull final Set<UidRange> uids) { - final Set<UidRange> ranges = new ArraySet<>(uids); for (final NetworkRequest req : requests) { - req.networkCapabilities.setUids(ranges); + req.networkCapabilities.setUids(UidRange.toIntRanges(uids)); } } @@ -9581,7 +9684,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ranges.add(new UidRange(uid, uid)); } setNetworkRequestUids(requests, ranges); - return new NetworkRequestInfo(requests); + return new NetworkRequestInfo(Process.myUid(), requests); } private NetworkRequest createUnmeteredNetworkRequest() { diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 10d6570929ed..3ea0ce173745 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -643,7 +643,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { String route, String gateway, String ifName) throws RemoteException { final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), - ifName); + ifName, RouteInfo.RTN_UNICAST); mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute)); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index f4231d29fe9b..78ffcbdaff4d 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -60,6 +60,7 @@ import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; import android.telephony.DisconnectCause; +import android.telephony.LinkCapacityEstimate; import android.telephony.LocationAccessPolicy; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; @@ -318,7 +319,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataEnabledReason; - private Map<Integer, Long> mAllowedNetworkTypesList; + private int[] mAllowedNetworkTypeReason; + private long[] mAllowedNetworkTypeValue; + + private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists; /** * Per-phone map of precise data connection state. The key of the map is the pair of transport @@ -350,6 +354,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( TelephonyCallback.EVENT_DATA_ENABLED_CHANGED); + REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add( + TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED); } private boolean isLocationPermissionRequired(Set<Integer> events) { @@ -383,7 +389,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) { return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) || events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED); + || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) + || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED); } private static final int MSG_USER_SWITCHED = 1; @@ -527,6 +534,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones); mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones); mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones); + mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones); + mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones); // ds -> ss switch. if (mNumPhones < oldNumPhones) { @@ -535,6 +544,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mPreciseDataConnectionStates, mNumPhones); cutListToSize(mBarringInfo, mNumPhones); cutListToSize(mPhysicalChannelConfigs, mNumPhones); + cutListToSize(mLinkCapacityEstimateLists, mNumPhones); return; } @@ -571,6 +581,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; + mLinkCapacityEstimateLists.add(i, new ArrayList<>()); } } @@ -630,9 +643,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo = new ArrayList<>(); mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones]; mPhysicalChannelConfigs = new ArrayList<>(); + mAllowedNetworkTypeReason = new int[numPhones]; + mAllowedNetworkTypeValue = new long[numPhones]; mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; - mAllowedNetworkTypesList = new HashMap<>(); + mLinkCapacityEstimateLists = new ArrayList<>(); + for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -665,6 +681,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; + mLinkCapacityEstimateLists.add(i, new ArrayList<>()); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -1166,9 +1185,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } if (events.contains( - TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) { + TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) { try { - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + if (mLinkCapacityEstimateLists.get(phoneId) != null) { + r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists + .get(phoneId)); + } } catch (RemoteException ex) { remove(r.binder); } @@ -2423,18 +2445,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { * * @param phoneId the phone id. * @param subId the subId. - * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's - * allowed network type values. + * @param reason the allowed network type reason. + * @param allowedNetworkType the allowed network type value. */ - public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, - Map allowedNetworkTypesList) { + public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason, + long allowedNetworkType) { if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) { return; } synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mAllowedNetworkTypesList = allowedNetworkTypesList; + mAllowedNetworkTypeReason[phoneId] = reason; + mAllowedNetworkTypeValue[phoneId] = allowedNetworkType; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( @@ -2442,10 +2465,48 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { && idMatch(r.subId, subId, phoneId)) { try { if (VDBG) { - log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= " - + mAllowedNetworkTypesList.toString()); + log("notifyAllowedNetworkTypesChanged: reason= " + reason + + ", allowed network type:" + + TelephonyManager.convertNetworkTypeBitmaskToString( + allowedNetworkType)); } - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + /** + * Notify that the link capacity estimate has changed. + * @param phoneId the phone id. + * @param subId the subscription id. + * @param linkCapacityEstimateList a list of {@link LinkCapacityEstimate} + */ + public void notifyLinkCapacityEstimateChanged(int phoneId, int subId, + List<LinkCapacityEstimate> linkCapacityEstimateList) { + if (!checkNotifyPermission("notifyLinkCapacityEstimateChanged()")) { + return; + } + + if (VDBG) { + log("notifyLinkCapacityEstimateChanged: linkCapacityEstimateList =" + + linkCapacityEstimateList); + } + + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mLinkCapacityEstimateLists.set(phoneId, linkCapacityEstimateList); + for (Record r : mRecords) { + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED) + && idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2500,6 +2561,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]); pw.println("mIsDataEnabled=" + mIsDataEnabled); pw.println("mDataEnabledReason=" + mDataEnabledReason); + pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]); + pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); + pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i)); pw.decreaseIndent(); } pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 6c18cdea51fa..d561ab96c365 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -821,8 +821,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IBinder cbBinder = callback.asBinder(); final VcnStatusCallbackInfo cbInfo = - new VcnStatusCallbackInfo( - subGroup, callback, opPkgName, mDeps.getBinderCallingUid()); + new VcnStatusCallbackInfo(subGroup, callback, opPkgName, callingUid); try { cbBinder.linkToDeath(cbInfo, 0 /* flags */); diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index 56aabc208027..d756c1ffd00f 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -352,7 +352,10 @@ public class VpnManagerService extends IVpnManager.Stub { @Override public void startLegacyVpn(VpnProfile profile) { int user = UserHandle.getUserId(mDeps.getCallingUid()); - final LinkProperties egress = mCm.getActiveLinkProperties(); + // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID), + // the code might not work well since getActiveNetwork might return null if the uid is + // blocked by NetworkPolicyManagerService. + final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork()); if (egress == null) { throw new IllegalStateException("Missing active network connection"); } diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 1c38c86d08c8..90d940939be8 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -30,6 +30,10 @@ per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS michaelwr@google.com narayan@google.com +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS + per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index b355730c6450..6776f49b7d8f 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -91,16 +91,19 @@ class HostClipboardMonitor implements Runnable { return bits; } - private void openPipe() { + private boolean openPipe() { try { - mPipe = new RandomAccessFile(PIPE_DEVICE, "rw"); - mPipe.write(createOpenHandshake()); - } catch (IOException e) { + final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw"); try { - if (mPipe != null) mPipe.close(); - } catch (IOException ee) {} - mPipe = null; + pipe.write(createOpenHandshake()); + mPipe = pipe; + return true; + } catch (IOException ignore) { + pipe.close(); + } + } catch (IOException ignore) { } + return false; } public HostClipboardMonitor(HostClipboardCallback cb) { @@ -114,8 +117,7 @@ class HostClipboardMonitor implements Runnable { // There's no guarantee that QEMU pipes will be ready at the moment // this method is invoked. We simply try to get the pipe open and // retry on failure indefinitely. - while (mPipe == null) { - openPipe(); + while ((mPipe == null) && !openPipe()) { Thread.sleep(100); } int size = mPipe.readInt(); diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java index 0fb6fecd4fe2..325a2cd7bd69 100644 --- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java +++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java @@ -18,18 +18,10 @@ package com.android.server.connectivity; /** * A class encapsulating various constants used by Connectivity. + * TODO : remove this class. * @hide */ public class ConnectivityConstants { - - // Penalty applied to scores of Networks that have not been validated. - public static final int UNVALIDATED_SCORE_PENALTY = 40; - - // Score for explicitly connected network. - // - // This ensures that a) the explicitly selected network is never trumped by anything else, and - // b) the explicitly selected network is never torn down. - public static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100; // VPNs typically have priority over other networks. Give them a score that will // let them win every single time. public static final int VPN_DEFAULT_SCORE = 101; diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/services/core/java/com/android/server/connectivity/ConnectivityResources.java deleted file mode 100644 index 45cf21e035ca..000000000000 --- a/services/core/java/com/android/server/connectivity/ConnectivityResources.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -package com.android.server.connectivity; - -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.util.Log; - -import com.android.server.ConnectivityService; - -import java.util.List; - -/** - * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the - * ServiceConnectivityResources APK. - */ -public class ConnectivityResources { - private static final String RESOURCES_APK_INTENT = - "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; - private static final String RES_PKG_DIR = "/apex/com.android.tethering/"; - - @NonNull - private final Context mContext; - - @Nullable - private Resources mResources = null; - - public ConnectivityResources(Context context) { - mContext = context; - } - - /** - * Get the {@link Resources} of the ServiceConnectivityResources APK. - */ - public synchronized Resources get() { - if (mResources != null) { - return mResources; - } - - final List<ResolveInfo> pkgs = mContext.getPackageManager() - .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY); - pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR)); - if (pkgs.size() > 1) { - Log.wtf(ConnectivityResources.class.getSimpleName(), - "More than one package found: " + pkgs); - } - if (pkgs.isEmpty()) { - throw new IllegalStateException("No connectivity resource package found"); - } - - final Context pkgContext; - try { - pkgContext = mContext.createPackageContext( - pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */); - } catch (PackageManager.NameNotFoundException e) { - throw new IllegalStateException("Resolved package not found", e); - } - - mResources = pkgContext.getResources(); - return mResources; - } -} diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 702434ba07b7..ffeb77d1d109 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -18,15 +18,15 @@ package com.android.server.connectivity; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES; +import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES; +import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; +import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE; +import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; -import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES; -import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; -import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; -import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT; -import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; -import static android.provider.Settings.Global.PRIVATE_DNS_MODE; -import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import android.annotation.NonNull; import android.content.ContentResolver; diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java new file mode 100644 index 000000000000..028cfee36593 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/FullScore.java @@ -0,0 +1,211 @@ +/* + * 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. + */ + +package com.android.server.connectivity; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkScore; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.StringJoiner; + +/** + * This class represents how desirable a network is. + * + * FullScore is very similar to NetworkScore, but it contains the bits that are managed + * by ConnectivityService. This provides static guarantee that all users must know whether + * they are handling a score that had the CS-managed bits set. + */ +public class FullScore { + // This will be removed soon. Do *NOT* depend on it for any new code that is not part of + // a migration. + private final int mLegacyInt; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"POLICY_"}, value = { + POLICY_IS_VALIDATED, + POLICY_IS_VPN, + POLICY_EVER_USER_SELECTED, + POLICY_ACCEPT_UNVALIDATED + }) + public @interface Policy { + } + + // Agent-managed policies are in NetworkScore. They start from 1. + // CS-managed policies, counting from 63 downward + // This network is validated. CS-managed because the source of truth is in NetworkCapabilities. + /** @hide */ + public static final int POLICY_IS_VALIDATED = 63; + + // This is a VPN and behaves as one for scoring purposes. + /** @hide */ + public static final int POLICY_IS_VPN = 62; + + // This network has been selected by the user manually from settings or a 3rd party app + // at least once. {@see NetworkAgentConfig#explicitlySelected}. + /** @hide */ + public static final int POLICY_EVER_USER_SELECTED = 61; + + // The user has indicated in UI that this network should be used even if it doesn't + // validate. {@see NetworkAgentConfig#acceptUnvalidated}. + /** @hide */ + public static final int POLICY_ACCEPT_UNVALIDATED = 60; + + // To help iterate when printing + @VisibleForTesting + static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED; + @VisibleForTesting + static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED; + + @VisibleForTesting + static @NonNull String policyNameOf(final int policy) { + switch (policy) { + case POLICY_IS_VALIDATED: return "IS_VALIDATED"; + case POLICY_IS_VPN: return "IS_VPN"; + case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED"; + case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED"; + } + throw new IllegalArgumentException("Unknown policy : " + policy); + } + + // Bitmask of all the policies applied to this score. + private final long mPolicies; + + FullScore(final int legacyInt, final long policies) { + mLegacyInt = legacyInt; + mPolicies = policies; + } + + /** + * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score. + * + * @param score the score supplied by the agent + * @param caps the NetworkCapabilities of the network + * @param config the NetworkAgentConfig of the network + * @return an FullScore that is appropriate to use for ranking. + */ + public static FullScore fromNetworkScore(@NonNull final NetworkScore score, + @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) { + return withPolicies(score.getLegacyInt(), caps.hasCapability(NET_CAPABILITY_VALIDATED), + caps.hasTransport(TRANSPORT_VPN), + config.explicitlySelected, + config.acceptUnvalidated); + } + + /** + * Return a new score given updated caps and config. + * + * @param caps the NetworkCapabilities of the network + * @param config the NetworkAgentConfig of the network + * @return a score with the policies from the arguments reset + */ + public FullScore mixInScore(@NonNull final NetworkCapabilities caps, + @NonNull final NetworkAgentConfig config) { + return withPolicies(mLegacyInt, caps.hasCapability(NET_CAPABILITY_VALIDATED), + caps.hasTransport(TRANSPORT_VPN), + config.explicitlySelected, + config.acceptUnvalidated); + } + + private static FullScore withPolicies(@NonNull final int legacyInt, + final boolean isValidated, + final boolean isVpn, + final boolean everUserSelected, + final boolean acceptUnvalidated) { + return new FullScore(legacyInt, + (isValidated ? 1L << POLICY_IS_VALIDATED : 0) + | (isVpn ? 1L << POLICY_IS_VPN : 0) + | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0) + | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)); + } + + /** + * For backward compatibility, get the legacy int. + * This will be removed before S is published. + */ + public int getLegacyInt() { + return getLegacyInt(false /* pretendValidated */); + } + + public int getLegacyIntAsValidated() { + return getLegacyInt(true /* pretendValidated */); + } + + // TODO : remove these two constants + // Penalty applied to scores of Networks that have not been validated. + private static final int UNVALIDATED_SCORE_PENALTY = 40; + + // Score for a network that can be used unvalidated + private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100; + + private int getLegacyInt(boolean pretendValidated) { + // If the user has chosen this network at least once, give it the maximum score when + // checking to pretend it's validated, or if it doesn't need to validate because the + // user said to use it even if it doesn't validate. + // This ensures that networks that have been selected in UI are not torn down before the + // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is + // available. + if (hasPolicy(POLICY_EVER_USER_SELECTED) + && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) { + return ACCEPT_UNVALIDATED_NETWORK_SCORE; + } + + int score = mLegacyInt; + // Except for VPNs, networks are subject to a penalty for not being validated. + // Apply the penalty unless the network is a VPN, or it's validated or pretending to be. + if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) { + score -= UNVALIDATED_SCORE_PENALTY; + } + if (score < 0) score = 0; + return score; + } + + /** + * @return whether this score has a particular policy. + */ + @VisibleForTesting + public boolean hasPolicy(final int policy) { + return 0 != (mPolicies & (1L << policy)); + } + + // Example output : + // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED) + @Override + public String toString() { + final StringJoiner sj = new StringJoiner( + "&", // delimiter + "Score(" + mLegacyInt + " ; Policies : ", // prefix + ")"); // suffix + for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY; + i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) { + if (hasPolicy(i)) sj.add(policyNameOf(i)); + } + for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) { + if (hasPolicy(i)) sj.add(policyNameOf(i)); + } + return sj.toString(); + } +} diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index e44dcf5975f1..103ab957f312 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -25,6 +25,8 @@ import android.content.Context; import android.net.CaptivePortalData; import android.net.IDnsResolver; import android.net.INetd; +import android.net.INetworkAgent; +import android.net.INetworkAgentRegistry; import android.net.INetworkMonitor; import android.net.LinkProperties; import android.net.NattKeepalivePacketData; @@ -51,8 +53,6 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import com.android.connectivity.aidl.INetworkAgent; -import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.util.WakeupMessage; import com.android.server.ConnectivityService; @@ -303,8 +303,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // validated). private boolean mInactive; - // This represents the quality of the network. - private NetworkScore mScore; + // This represents the quality of the network. As opposed to NetworkScore, FullScore includes + // the ConnectivityService-managed bits. + private FullScore mScore; // The list of NetworkRequests being satisfied by this Network. private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); @@ -356,12 +357,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { networkInfo = info; linkProperties = lp; networkCapabilities = nc; - mScore = score; + networkAgentConfig = config; + setScore(score); // uses members networkCapabilities and networkAgentConfig clatd = new Nat464Xlat(this, netd, dnsResolver, deps); mConnService = connService; mContext = context; mHandler = handler; - networkAgentConfig = config; this.factorySerialNumber = factorySerialNumber; this.creatorUid = creatorUid; mQosCallbackTracker = qosCallbackTracker; @@ -667,6 +668,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { nm.notifyNetworkCapabilitiesChanged(nc); @@ -844,30 +846,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return isVPN(); } - private int getCurrentScore(boolean pretendValidated) { - // TODO: We may want to refactor this into a NetworkScore class that takes a base score from - // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the - // score. The NetworkScore class would provide a nice place to centralize score constants - // so they are not scattered about the transports. - - // If this network is explicitly selected and the user has decided to use it even if it's - // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly - // selected and we're trying to see what its score could be. This ensures that we don't tear - // down an explicitly selected network before the user gets a chance to prefer it when - // a higher-scoring network (e.g., Ethernet) is available. - if (networkAgentConfig.explicitlySelected - && (networkAgentConfig.acceptUnvalidated || pretendValidated)) { - return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE; - } - - int score = mScore.getLegacyInt(); - if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) { - score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY; - } - if (score < 0) score = 0; - return score; - } - // Return true on devices configured to ignore score penalty for wifi networks // that become unvalidated (b/31075769). private boolean ignoreWifiUnvalidationPenalty() { @@ -880,17 +858,29 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // Get the current score for this Network. This may be modified from what the // NetworkAgent sent, as it has modifiers applied to it. public int getCurrentScore() { - return getCurrentScore(false); + return mScore.getLegacyInt(); } // Get the current score for this Network as if it was validated. This may be modified from // what the NetworkAgent sent, as it has modifiers applied to it. public int getCurrentScoreAsValidated() { - return getCurrentScore(true); + return mScore.getLegacyIntAsValidated(); } + /** + * Mix-in the ConnectivityService-managed bits in the score. + */ public void setScore(final NetworkScore score) { - mScore = score; + mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig); + } + + /** + * Update the ConnectivityService-managed bits in the score. + * + * Call this after updating the network agent config. + */ + public void updateScoreForNetworkAgentConfigUpdate() { + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); } /** diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 508739f2e1e0..0c0d45995a2b 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -28,6 +28,8 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.drawable.Icon; +import android.net.ConnectivityResources; import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; @@ -40,7 +42,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.widget.Toast; -import com.android.internal.R; +import com.android.connectivity.resources.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; @@ -82,6 +84,7 @@ public class NetworkNotificationManager { // The context is for the current user (system server) private final Context mContext; + private final Resources mResources; private final TelephonyManager mTelephonyManager; // The notification manager is created from a context for User.ALL, so notifications // will be sent to all users. @@ -96,6 +99,7 @@ public class NetworkNotificationManager { (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */) .getSystemService(Context.NOTIFICATION_SERVICE); mNotificationTypeMap = new SparseIntArray(); + mResources = new ConnectivityResources(mContext).get(); } @VisibleForTesting @@ -113,20 +117,19 @@ public class NetworkNotificationManager { return -1; } - private static String getTransportName(final int transportType) { - Resources r = Resources.getSystem(); - String[] networkTypes = r.getStringArray(R.array.network_switch_type_name); + private String getTransportName(final int transportType) { + String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name); try { return networkTypes[transportType]; } catch (IndexOutOfBoundsException e) { - return r.getString(R.string.network_switch_type_name_unknown); + return mResources.getString(R.string.network_switch_type_name_unknown); } } private static int getIcon(int transportType) { return (transportType == TRANSPORT_WIFI) - ? R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?. - R.drawable.stat_notify_rssi_in_range; + ? R.drawable.stat_notify_wifi_in_range // TODO: Distinguish ! from ?. + : R.drawable.stat_notify_rssi_in_range; } /** @@ -156,7 +159,7 @@ public class NetworkNotificationManager { final String tag = tagFor(id); final int eventId = notifyType.eventId; final int transportType; - final String name; + final CharSequence name; if (nai != null) { transportType = approximateTransportType(nai); final String extraInfo = nai.networkInfo.getExtraInfo(); @@ -194,10 +197,10 @@ public class NetworkNotificationManager { tag, nameOf(eventId), getTransportName(transportType), name, highPriority)); } - Resources r = mContext.getResources(); + final Resources r = mResources; final CharSequence title; final CharSequence details; - int icon = getIcon(transportType); + Icon icon = Icon.createWithResource(r, getIcon(transportType)); if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, name); details = r.getString(R.string.wifi_no_internet_detailed); @@ -272,8 +275,7 @@ public class NetworkNotificationManager { .setSmallIcon(icon) .setAutoCancel(true) .setTicker(title) - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)) + .setColor(mContext.getColor(android.R.color.system_notification_accent_color)) .setContentTitle(title) .setContentIntent(intent) .setLocalOnly(true) @@ -353,7 +355,7 @@ public class NetworkNotificationManager { public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) { String fromTransport = getTransportName(approximateTransportType(fromNai)); String toTransport = getTransportName(approximateTransportType(toNai)); - String text = mContext.getResources().getString( + String text = mResources.getString( R.string.network_switch_metered_toast, fromTransport, toTransport); Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); } diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index 8b9c83678777..f572b46a9b58 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -16,10 +16,10 @@ package com.android.server.connectivity; -import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST; -import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST; -import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC; -import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT; +import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_EXCLUSION_LIST; +import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_HOST; +import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PAC; +import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PORT; import static android.provider.Settings.Global.HTTP_PROXY; import android.annotation.NonNull; @@ -34,7 +34,6 @@ import android.net.ProxyInfo; import android.net.Uri; import android.os.Binder; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -105,7 +104,7 @@ public class ProxyTracker { PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent); mPacProxyManager.addPacProxyInstalledListener( - new HandlerExecutor(mConnectivityServiceHandler), listener); + mConnectivityServiceHandler::post, listener); } // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 124c3741ad57..30e0c7e9b9aa 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -19,6 +19,7 @@ package com.android.server.connectivity; import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.os.UserHandle.PER_USER_RANGE; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; @@ -68,8 +69,8 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.RouteInfo; -import android.net.UidRange; import android.net.UidRangeParcel; import android.net.UnderlyingNetworkInfo; import android.net.VpnManager; @@ -1174,11 +1175,13 @@ public class Vpn { if (!allowIPv4) { lp.addRoute(new RouteInfo(new IpPrefix( - NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE)); + NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } if (!allowIPv6) { lp.addRoute(new RouteInfo(new IpPrefix( - NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE)); + NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } // Concatenate search domains into a string. @@ -1239,7 +1242,7 @@ public class Vpn { mLegacyState = LegacyVpnInfo.STATE_CONNECTING; updateState(DetailedState.CONNECTING, "agentConnect"); - NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); + NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder().build(); networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; mNetworkCapabilities.setOwnerUid(mOwnerUID); @@ -1258,9 +1261,11 @@ public class Vpn { } mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, - mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) { + mNetworkCapabilities, lp, + new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(), + networkAgentConfig, mNetworkProvider) { @Override - public void unwanted() { + public void onNetworkUnwanted() { // We are user controlled, not driven by NetworkRequest. } }; @@ -1346,7 +1351,7 @@ public class Vpn { String oldInterface = mInterface; Connection oldConnection = mConnection; NetworkAgent oldNetworkAgent = mNetworkAgent; - Set<UidRange> oldUsers = mNetworkCapabilities.getUids(); + Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); @@ -1452,7 +1457,7 @@ public class Vpn { } /** - * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs + * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs * associated with one user, and any restricted profiles attached to that user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, @@ -1465,10 +1470,10 @@ public class Vpn { * @param disallowedApplications (optional) List of applications to deny. */ @VisibleForTesting - Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, + Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications) { - final Set<UidRange> ranges = new ArraySet<>(); + final Set<Range<Integer>> ranges = new ArraySet<>(); // Assign the top-level user to the set of ranges addUserToRanges(ranges, userId, allowedApplications, disallowedApplications); @@ -1492,20 +1497,20 @@ public class Vpn { } /** - * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs + * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs * associated with one user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs * in the user will be included. * - * @param ranges {@link Set} of {@link UidRange}s to which to add. + * @param ranges {@link Set} of {@code Range<Integer>}s to which to add. * @param userId The userId to add to {@param ranges}. * @param allowedApplications (optional) allowlist of applications to include. * @param disallowedApplications (optional) denylist of applications to exclude. */ @VisibleForTesting - void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId, + void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications) { if (allowedApplications != null) { @@ -1515,40 +1520,41 @@ public class Vpn { if (start == -1) { start = uid; } else if (uid != stop + 1) { - ranges.add(new UidRange(start, stop)); + ranges.add(new Range<Integer>(start, stop)); start = uid; } stop = uid; } - if (start != -1) ranges.add(new UidRange(start, stop)); + if (start != -1) ranges.add(new Range<Integer>(start, stop)); } else if (disallowedApplications != null) { // Add all ranges for user skipping UIDs for disallowedApplications. - final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); - int start = userRange.start; + final Range<Integer> userRange = createUidRangeForUser(userId); + int start = userRange.getLower(); for (int uid : getAppsUids(disallowedApplications, userId)) { if (uid == start) { start++; } else { - ranges.add(new UidRange(start, uid - 1)); + ranges.add(new Range<Integer>(start, uid - 1)); start = uid + 1; } } - if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); + if (start <= userRange.getUpper()) { + ranges.add(new Range<Integer>(start, userRange.getUpper())); + } } else { // Add all UIDs for the user. - ranges.add(UidRange.createForUser(UserHandle.of(userId))); + ranges.add(createUidRangeForUser(userId)); } } // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that // apply to userId. - private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) { - // UidRange#createForUser returns the entire range of UIDs available to a macro-user. - // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE} - final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); - final List<UidRange> ranges = new ArrayList<>(); - for (UidRange range : existingRanges) { - if (userRange.containsRange(range)) { + private static List<Range<Integer>> uidRangesForUser(int userId, + Set<Range<Integer>> existingRanges) { + final Range<Integer> userRange = createUidRangeForUser(userId); + final List<Range<Integer>> ranges = new ArrayList<>(); + for (Range<Integer> range : existingRanges) { + if (userRange.contains(range)) { ranges.add(range); } } @@ -1565,7 +1571,7 @@ public class Vpn { UserInfo user = mUserManager.getUserInfo(userId); if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { synchronized(Vpn.this) { - final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); + final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { try { addUserToRanges(existingRanges, userId, mConfig.allowedApplications, @@ -1593,10 +1599,10 @@ public class Vpn { UserInfo user = mUserManager.getUserInfo(userId); if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { synchronized(Vpn.this) { - final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); + final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { try { - final List<UidRange> removedRanges = + final List<Range<Integer>> removedRanges = uidRangesForUser(userId, existingRanges); existingRanges.removeAll(removedRanges); mNetworkCapabilities.setUids(existingRanges); @@ -1657,7 +1663,7 @@ public class Vpn { final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity); final Set<UidRangeParcel> rangesToAdd; if (enforce) { - final Set<UidRange> restrictedProfilesRanges = + final Set<Range<Integer>> restrictedProfilesRanges = createUserAndRestrictedProfilesRanges(mUserId, /* allowedApplications */ null, /* disallowedApplications */ exemptedPackages); @@ -1666,11 +1672,12 @@ public class Vpn { // The UID range of the first user (0-99999) would block the IPSec traffic, which comes // directly from the kernel and is marked as uid=0. So we adjust the range to allow // it through (b/69873852). - for (UidRange range : restrictedProfilesRanges) { - if (range.start == 0 && range.stop != 0) { - rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop)); - } else if (range.start != 0) { - rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop)); + for (Range<Integer> range : restrictedProfilesRanges) { + if (range.getLower() == 0 && range.getUpper() != 0) { + rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper())); + } else if (range.getLower() != 0) { + rangesThatShouldBeBlocked.add( + new UidRangeParcel(range.getLower(), range.getUpper())); } } @@ -1692,12 +1699,12 @@ public class Vpn { } /** - * Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs - * that are only allowed to make connections through sockets that have had {@code protect()} - * called on them. + * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of + * UIDs that are only allowed to make connections through sockets that have had + * {@code protect()} called on them. * * @param enforce {@code true} to add to the denylist, {@code false} to remove. - * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is + * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is * {@code true}) or to remove. * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, * including added ranges that already existed or removed ones that didn't. @@ -2696,7 +2703,8 @@ public class Vpn { mConfig.routes.clear(); for (final RouteInfo route : oldRoutes) { - mConfig.routes.add(new RouteInfo(route.getDestination(), RTN_UNREACHABLE)); + mConfig.routes.add(new RouteInfo(route.getDestination(), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } if (mNetworkAgent != null) { mNetworkAgent.sendLinkProperties(makeLinkProperties()); @@ -3035,10 +3043,12 @@ public class Vpn { // Add a throw route for the VPN server endpoint, if one was specified. if (endpointAddress instanceof Inet4Address) { mConfig.routes.add(new RouteInfo( - new IpPrefix(endpointAddress, 32), RTN_THROW)); + new IpPrefix(endpointAddress, 32), null /*gateway*/, + null /*iface*/, RTN_THROW)); } else if (endpointAddress instanceof Inet6Address) { mConfig.routes.add(new RouteInfo( - new IpPrefix(endpointAddress, 128), RTN_THROW)); + new IpPrefix(endpointAddress, 128), null /*gateway*/, + null /*iface*/, RTN_THROW)); } else { Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpointAddress); @@ -3338,4 +3348,12 @@ public class Vpn { firstChildSessionCallback); } } + + /** + * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999. + */ + @VisibleForTesting + static Range<Integer> createUidRangeForUser(int userId) { + return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); + } } diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java index fa03e59f2f2e..47eb3eb70434 100644 --- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java +++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java @@ -405,7 +405,8 @@ public class VpnIkev2Utils { for (final IkeTrafficSelector selector : trafficSelectors) { for (final IpPrefix prefix : new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) { - routes.add(new RouteInfo(prefix, null)); + routes.add(new RouteInfo(prefix, null /*gateway*/, null /*iface*/, + RouteInfo.RTN_UNICAST)); } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 294d7e257b6e..0215188bc1a4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -92,7 +92,6 @@ import android.provider.Settings.SettingNotFoundException; import android.security.AndroidKeyStoreMaintenance; import android.security.Authorization; import android.security.KeyStore; -import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; import android.security.keystore.UserNotAuthenticatedException; @@ -157,7 +156,6 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -264,13 +262,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onStart() { - Optional<Boolean> keystore2_enabled = - android.sysprop.Keystore2Properties.keystore2_enabled(); - if (keystore2_enabled.isPresent() && keystore2_enabled.get()) { - android.security.keystore2.AndroidKeyStoreProvider.install(); - } else { - AndroidKeyStoreProvider.install(); - } + android.security.keystore2.AndroidKeyStoreProvider.install(); mLockSettingsService = new LockSettingsService(getContext()); publishBinderService("lock_settings", mLockSettingsService); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index aee0947f39f9..46c80e7c44e3 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -56,6 +56,25 @@ import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_MASK; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM; +import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_ADMIN_DISABLED; +import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER; +import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_MASK; +import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_APP_STANDBY; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_DOZE; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE; +import static android.net.NetworkPolicyManager.BLOCKED_REASON_RESTRICTED_MODE; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; @@ -244,6 +263,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.StatLogger; import com.android.internal.util.XmlUtils; import com.android.net.module.util.NetworkIdentityUtils; +import com.android.net.module.util.PermissionUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.ServiceThread; @@ -414,6 +434,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20; + // TODO: Add similar docs for other messages. + /** + * Message to indicate that reasons for why an uid is blocked changed. + * arg1 = uid + * arg2 = oldBlockedReasons + * obj = newBlockedReasons + */ + private static final int MSG_BLOCKED_REASON_CHANGED = 21; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -560,7 +588,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Foreground at UID granularity. */ @GuardedBy("mUidRulesFirstLock") - final SparseArray<UidState> mUidState = new SparseArray<UidState>(); + private final SparseArray<UidState> mUidState = new SparseArray<>(); + + @GuardedBy("mUidRulesFirstLock") + private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>(); /** Map from network ID to last observed meteredness state */ @GuardedBy("mNetworkPoliciesSecondLock") @@ -2879,15 +2910,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void registerListener(INetworkPolicyListener listener) { + public void registerListener(@NonNull INetworkPolicyListener listener) { + Objects.requireNonNull(listener); // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps // have declared OBSERVE_NETWORK_POLICY. enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY); mListeners.register(listener); + // TODO: Send callbacks to the newly registered listener } @Override - public void unregisterListener(INetworkPolicyListener listener) { + public void unregisterListener(@NonNull INetworkPolicyListener listener) { + Objects.requireNonNull(listener); // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps // have declared OBSERVE_NETWORK_POLICY. enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY); @@ -3081,8 +3115,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public int getRestrictBackgroundByCaller() { mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); - final int uid = Binder.getCallingUid(); + return getRestrictBackgroundStatusInternal(Binder.getCallingUid()); + } + @Override + public int getRestrictBackgroundStatus(int uid) { + PermissionUtils.enforceNetworkStackPermission(mContext); + return getRestrictBackgroundStatusInternal(uid); + } + + private int getRestrictBackgroundStatusInternal(int uid) { synchronized (mUidRulesFirstLock) { // Must clear identity because getUidPolicy() is restricted to system. final long token = Binder.clearCallingIdentity(); @@ -3551,6 +3593,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Get multipath preference value for the given network. */ public int getMultipathPreference(Network network) { + PermissionUtils.enforceNetworkStackPermission(mContext); final Integer preference = mMultipathPolicyTracker.getMultipathPreference(network); if (preference != null) { return preference; @@ -3923,6 +3966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidRules.put(uid, newUidRule); mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget(); } + updateBlockedReasonsForRestrictedModeUL(uid); }); if (mRestrictedNetworkingMode) { // firewall rules only need to be set when this mode is being enabled. @@ -3943,6 +3987,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidRules.put(uid, newUidRule); mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget(); } + updateBlockedReasonsForRestrictedModeUL(uid); // if restricted networking mode is on, and the app has an access exemption, the uid rule // will not change, but the firewall rule will have to be updated. @@ -3954,6 +3999,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void updateBlockedReasonsForRestrictedModeUL(int uid) { + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + if (mRestrictedNetworkingMode) { + uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE; + } else { + uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; + } + if (hasRestrictedModeAccess(uid)) { + uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } else { + uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } + uidBlockedState.updateEffectiveBlockedReasons(); + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) + .sendToTarget(); + } + } + private int getNewRestrictedModeUidRule(int uid, int oldUidRule) { int newRule = oldUidRule; newRule &= ~MASK_RESTRICTED_MODE_NETWORKS; @@ -4074,11 +4144,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId); if (!deviceIdleMode) { - isWhitelisted = isWhitelisted || mPowerSaveWhitelistExceptIdleAppIds.get(appId); + isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid); } return isWhitelisted; } + /** + * Returns whether a uid is allowlisted from power saving restrictions, except Device idle + * (eg: Battery Saver and app idle). + */ + @GuardedBy("mUidRulesFirstLock") + private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) { + final int appId = UserHandle.getAppId(uid); + return mPowerSaveWhitelistExceptIdleAppIds.get(appId); + } + // NOTE: since both fw_dozable and fw_powersave uses the same map // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method. @GuardedBy("mUidRulesFirstLock") @@ -4523,6 +4603,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int oldUidRules = mUidRules.get(uid, RULE_NONE); final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; @@ -4547,6 +4632,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + int newBlockedReasons = BLOCKED_REASON_NONE; + int newAllowedReasons = ALLOWED_REASON_NONE; + newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0); + newBlockedReasons |= (mRestrictBackground ? BLOCKED_METERED_REASON_DATA_SAVER : 0); + newBlockedReasons |= (isDenied ? BLOCKED_METERED_REASON_USER_RESTRICTED : 0); + + newAllowedReasons |= (isSystem(uid) ? ALLOWED_METERED_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); + if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + ": isForeground=" +isForeground @@ -4619,6 +4714,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Dispatch changed rule to existing listeners. mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget(); } + + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons + & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons; + uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons + & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) + .sendToTarget(); + } } /** @@ -4692,6 +4799,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Copy existing uid rules and clear ALL_NETWORK rules. int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS); + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } + // First step: define the new rule based on user restrictions and foreground state. // NOTE: if statements below could be inlined, but it's easier to understand the logic @@ -4704,6 +4817,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL; } + int newBlockedReasons = BLOCKED_REASON_NONE; + int newAllowedReasons = ALLOWED_REASON_NONE; + newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0); + newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0); + newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); + newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); + + newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true) + ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) + ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); + if (LOGV) { Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")" + ", isIdle: " + isUidIdle @@ -4735,6 +4862,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget(); } + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons + & BLOCKED_METERED_REASON_MASK) | newBlockedReasons; + uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons + & ALLOWED_METERED_REASON_MASK) | newAllowedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) + .sendToTarget(); + } + return newUidRules; } @@ -4764,61 +4903,57 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { - if (listener != null) { - try { - listener.onUidRulesChanged(uid, uidRules); - } catch (RemoteException ignored) { - } + try { + listener.onUidRulesChanged(uid, uidRules); + } catch (RemoteException ignored) { } } private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener, String[] meteredIfaces) { - if (listener != null) { - try { - listener.onMeteredIfacesChanged(meteredIfaces); - } catch (RemoteException ignored) { - } + try { + listener.onMeteredIfacesChanged(meteredIfaces); + } catch (RemoteException ignored) { } } private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener, boolean restrictBackground) { - if (listener != null) { - try { - listener.onRestrictBackgroundChanged(restrictBackground); - } catch (RemoteException ignored) { - } + try { + listener.onRestrictBackgroundChanged(restrictBackground); + } catch (RemoteException ignored) { } } private void dispatchUidPoliciesChanged(INetworkPolicyListener listener, int uid, int uidPolicies) { - if (listener != null) { - try { - listener.onUidPoliciesChanged(uid, uidPolicies); - } catch (RemoteException ignored) { - } + try { + listener.onUidPoliciesChanged(uid, uidPolicies); + } catch (RemoteException ignored) { } } private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId, int overrideMask, int overrideValue, int[] networkTypes) { - if (listener != null) { - try { - listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes); - } catch (RemoteException ignored) { - } + try { + listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes); + } catch (RemoteException ignored) { } } private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, SubscriptionPlan[] plans) { - if (listener != null) { - try { - listener.onSubscriptionPlansChanged(subId, plans); - } catch (RemoteException ignored) { - } + try { + listener.onSubscriptionPlansChanged(subId, plans); + } catch (RemoteException ignored) { + } + } + + private void dispatchBlockedReasonChanged(INetworkPolicyListener listener, int uid, + int oldBlockedReasons, int newBlockedReasons) { + try { + listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons); + } catch (RemoteException ignored) { } } @@ -4975,6 +5110,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_BLOCKED_REASON_CHANGED: { + final int uid = msg.arg1; + final int newBlockedReasons = msg.arg2; + final int oldBlockedReasons = (int) msg.obj; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchBlockedReasonChanged(listener, uid, + oldBlockedReasons, newBlockedReasons); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } @@ -5706,6 +5854,56 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue; } + private class UidBlockedState { + public int blockedReasons; + public int allowedReasons; + public int effectiveBlockedReasons; + + UidBlockedState() { + blockedReasons = BLOCKED_REASON_NONE; + allowedReasons = ALLOWED_REASON_NONE; + effectiveBlockedReasons = BLOCKED_REASON_NONE; + } + + void updateEffectiveBlockedReasons() { + effectiveBlockedReasons = blockedReasons; + // If the uid is not subject to any blocked reasons, then return early + if (blockedReasons == BLOCKED_REASON_NONE) { + return; + } + if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) { + effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK); + } + if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) { + effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK); + } + if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) { + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED; + } + if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; + } + if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) { + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; + } + } + } + private class NotificationId { private final String mTag; private final int mId; diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index 9c4c5101cb6c..cc6a8243799d 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -411,8 +411,13 @@ public final class NativeTombstoneManager { processName = stream.readString(Tombstone.PROCESS_NAME); break; - case (int) Tombstone.CAUSE: - long token = stream.start(Tombstone.CAUSE); + case (int) Tombstone.CAUSES: + if (!crashReason.equals("")) { + // Causes appear in decreasing order of likelihood. For now we only + // want the most likely crash reason here, so ignore all others. + break; + } + long token = stream.start(Tombstone.CAUSES); cause: while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (stream.getFieldNumber()) { diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 06b54b5c21fc..4038bf290161 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -203,7 +203,7 @@ public class StagingManager { newSigningDetails = ApkSignatureVerifier.verify(apexPath, minSignatureScheme); } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, - "Failed to parse APEX package " + apexPath, e); + "Failed to parse APEX package " + apexPath + " : " + e, e); } // Get signing details of the existing package @@ -221,7 +221,8 @@ public class StagingManager { existingApexPkg.applicationInfo.sourceDir, SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, - "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir, e); + "Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir + + " : " + e, e); } // Verify signing details for upgrade @@ -283,7 +284,7 @@ public class StagingManager { } } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, - "Failed to parse APEX package " + apexInfo.modulePath, e); + "Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e); } final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName, ApexManager.MATCH_ACTIVE_PACKAGE); diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java index 0c8e36b75425..c8dc1b1ff562 100644 --- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -146,47 +146,11 @@ public class ArtStatsLogUtils { uid, compilationReason, compilerFilter, - ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, - getDexBytes(path), - dexMetadataType); - logger.write( - sessionId, - uid, - compilationReason, - compilerFilter, ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, compileTime, dexMetadataType); } - private static long getDexBytes(String apkPath) { - StrictJarFile jarFile = null; - long dexBytes = 0; - try { - jarFile = new StrictJarFile(apkPath, - /*verify=*/ false, - /*signatureSchemeRollbackProtectionsEnforced=*/ false); - Iterator<ZipEntry> it = jarFile.iterator(); - while (it.hasNext()) { - ZipEntry entry = it.next(); - if (entry.getName().matches("classes(\\d)*[.]dex")) { - dexBytes += entry.getSize(); - } - } - return dexBytes; - } catch (IOException ignore) { - Slog.e(TAG, "Error when parsing APK " + apkPath); - return -1L; - } finally { - try { - if (jarFile != null) { - jarFile.close(); - } - } catch (IOException ignore) { - } - } - } - private static int getDexMetadataType(String dexMetadataPath) { if (dexMetadataPath == null) { return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE; diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java index 9c3a39440054..5b48abb3e1f2 100644 --- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java +++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java @@ -24,11 +24,11 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.drawable.Drawable; import android.media.AudioManager; -import android.net.ConnectivityManager; import android.os.Build; import android.os.Handler; import android.os.Message; @@ -113,7 +113,7 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn private boolean mDeviceProvisioned = false; private ToggleAction.State mAirplaneState = ToggleAction.State.Off; private boolean mIsWaitingForEcmExit = false; - private boolean mHasTelephony; + private final boolean mHasTelephony; private boolean mHasVibrator; private final boolean mShowSilentToggle; private final EmergencyAffordanceManager mEmergencyAffordanceManager; @@ -137,9 +137,8 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); context.registerReceiver(mBroadcastReceiver, filter); - ConnectivityManager cm = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + mHasTelephony = + context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); // get notified of phone state changes TelephonyManager telephonyManager = diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index fd2d8e1b834b..0a6772bd8f6a 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -16,14 +16,18 @@ package com.android.server.recoverysystem; +import static android.os.UserHandle.USER_SYSTEM; + import android.annotation.IntDef; import android.content.Context; import android.content.IntentSender; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.boot.V1_0.IBootControl; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Binder; +import android.os.Environment; import android.os.IRecoverySystem; import android.os.IRecoverySystemProgressListener; import android.os.PowerManager; @@ -33,12 +37,14 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; +import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.RebootEscrowListener; import com.android.server.LocalServices; @@ -48,10 +54,13 @@ import libcore.io.IoUtils; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; /** * The recovery system service is responsible for coordinating recovery related @@ -81,6 +90,12 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo private static final int SOCKET_CONNECTION_MAX_RETRY = 30; + static final String REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX = "_request_lskf_timestamp"; + static final String REQUEST_LSKF_COUNT_PREF_SUFFIX = "_request_lskf_count"; + + static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp"; + static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count"; + private final Injector mInjector; private final Context mContext; @@ -121,22 +136,93 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo */ @IntDef({ ROR_NEED_PREPARATION, ROR_SKIP_PREPARATION_AND_NOTIFY, - ROR_SKIP_PREPARATION_NOT_NOTIFY }) + ROR_SKIP_PREPARATION_NOT_NOTIFY}) private @interface ResumeOnRebootActionsOnRequest {} /** * The action to perform upon resume on reboot clear request for a given client. */ - @IntDef({ROR_NOT_REQUESTED, + @IntDef({ ROR_NOT_REQUESTED, ROR_REQUESTED_NEED_CLEAR, ROR_REQUESTED_SKIP_CLEAR}) - private @interface ResumeOnRebootActionsOnClear{} + private @interface ResumeOnRebootActionsOnClear {} + + /** + * The error codes for reboots initiated by resume on reboot clients. + */ + private static final int REBOOT_ERROR_NONE = 0; + private static final int REBOOT_ERROR_UNKNOWN = 1; + private static final int REBOOT_ERROR_INVALID_PACKAGE_NAME = 2; + private static final int REBOOT_ERROR_LSKF_NOT_CAPTURED = 3; + private static final int REBOOT_ERROR_SLOT_MISMATCH = 4; + private static final int REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE = 5; + + @IntDef({ REBOOT_ERROR_NONE, + REBOOT_ERROR_UNKNOWN, + REBOOT_ERROR_INVALID_PACKAGE_NAME, + REBOOT_ERROR_LSKF_NOT_CAPTURED, + REBOOT_ERROR_SLOT_MISMATCH, + REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE}) + private @interface ResumeOnRebootRebootErrorCode {} + + /** + * Manages shared preference, i.e. the storage used for metrics reporting. + */ + public static class PreferencesManager { + private static final String METRICS_DIR = "recovery_system"; + private static final String METRICS_PREFS_FILE = "RecoverySystemMetricsPrefs.xml"; + + protected final SharedPreferences mSharedPreferences; + private final File mMetricsPrefsFile; + + PreferencesManager(Context context) { + File prefsDir = new File(Environment.getDataSystemCeDirectory(USER_SYSTEM), + METRICS_DIR); + mMetricsPrefsFile = new File(prefsDir, METRICS_PREFS_FILE); + mSharedPreferences = context.getSharedPreferences(mMetricsPrefsFile, 0); + } + + /** Reads the value of a given key with type long. **/ + public long getLong(String key, long defaultValue) { + return mSharedPreferences.getLong(key, defaultValue); + } + + /** Reads the value of a given key with type int. **/ + public int getInt(String key, int defaultValue) { + return mSharedPreferences.getInt(key, defaultValue); + } + + /** Stores the value of a given key with type long. **/ + public void putLong(String key, long value) { + mSharedPreferences.edit().putLong(key, value).commit(); + } + + /** Stores the value of a given key with type int. **/ + public void putInt(String key, int value) { + mSharedPreferences.edit().putInt(key, value).commit(); + } + + /** Increments the value of a given key with type int. **/ + public synchronized void incrementIntKey(String key, int defaultInitialValue) { + int oldValue = getInt(key, defaultInitialValue); + putInt(key, oldValue + 1); + } + + /** Delete the preference file and cleanup all metrics storage. **/ + public void deletePrefsFile() { + if (!mMetricsPrefsFile.delete()) { + Slog.w(TAG, "Failed to delete metrics prefs"); + } + } + } static class Injector { protected final Context mContext; + protected final PreferencesManager mPrefs; Injector(Context context) { mContext = context; + mPrefs = new PreferencesManager(context); } public Context getContext() { @@ -202,6 +288,43 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo public void threadSleep(long millis) throws InterruptedException { Thread.sleep(millis); } + + public int getUidFromPackageName(String packageName) { + try { + return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Failed to find uid for " + packageName); + } + return -1; + } + + public PreferencesManager getMetricsPrefs() { + return mPrefs; + } + + public long getCurrentTimeMillis() { + return System.currentTimeMillis(); + } + + public void reportRebootEscrowPreparationMetrics(int uid, + @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid, + requestResult, requestedClientCount); + } + + public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid, + requestedClientCount, requestedToLskfCapturedDurationInSeconds); + } + + public void reportRebootEscrowRebootMetrics(int errorCode, int uid, + int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode, + uid, preparedClientCount, requestCount, slotSwitch, serverBased, + lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts); + } } /** @@ -361,12 +484,28 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY) != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT) - != PackageManager.PERMISSION_GRANTED) { + != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY + " or " + android.Manifest.permission.REBOOT + " for resume on reboot."); } } + private void reportMetricsOnRequestLskf(String packageName, int requestResult) { + int uid = mInjector.getUidFromPackageName(packageName); + int pendingRequestCount; + synchronized (this) { + pendingRequestCount = mCallerPendingRequest.size(); + } + + // Save the timestamp and request count for new ror request + PreferencesManager prefs = mInjector.getMetricsPrefs(); + prefs.putLong(packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, + mInjector.getCurrentTimeMillis()); + prefs.incrementIntKey(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, 0); + + mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount); + } + @Override // Binder call public boolean requestLskf(String packageName, IntentSender intentSender) { enforcePermissionForResumeOnReboot(); @@ -378,6 +517,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo @ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest( packageName, intentSender); + reportMetricsOnRequestLskf(packageName, action); + switch (action) { case ROR_SKIP_PREPARATION_AND_NOTIFY: // We consider the preparation done if someone else has prepared. @@ -420,12 +561,42 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY; } + private void reportMetricsOnPreparedForReboot() { + long currentTimestamp = mInjector.getCurrentTimeMillis(); + + List<String> preparedClients; + synchronized (this) { + preparedClients = new ArrayList<>(mCallerPreparedForReboot); + } + + // Save the timestamp & lskf capture count for lskf capture + PreferencesManager prefs = mInjector.getMetricsPrefs(); + prefs.putLong(LSKF_CAPTURED_TIMESTAMP_PREF, currentTimestamp); + prefs.incrementIntKey(LSKF_CAPTURED_COUNT_PREF, 0); + + for (String packageName : preparedClients) { + int uid = mInjector.getUidFromPackageName(packageName); + + int durationSeconds = -1; + long requestLskfTimestamp = prefs.getLong( + packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, -1); + if (requestLskfTimestamp != -1 && currentTimestamp > requestLskfTimestamp) { + durationSeconds = (int) (currentTimestamp - requestLskfTimestamp) / 1000; + } + Slog.i(TAG, String.format("Reporting lskf captured, lskf capture takes %d seconds for" + + " package %s", durationSeconds, packageName)); + mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(), + durationSeconds); + } + } + @Override public void onPreparedForReboot(boolean ready) { if (!ready) { return; } updateRoRPreparationStateOnPreparedForReboot(); + reportMetricsOnPreparedForReboot(); } private synchronized void updateRoRPreparationStateOnPreparedForReboot() { @@ -462,6 +633,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo Slog.w(TAG, "Missing packageName when clearing lskf."); return false; } + // TODO(179105110) Clear the RoR metrics for the given packageName. @ResumeOnRebootActionsOnClear int action = updateRoRPreparationStateOnClear(packageName); switch (action) { @@ -548,25 +720,68 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return true; } - private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { + private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName, + boolean slotSwitch) { if (packageName == null) { Slog.w(TAG, "Missing packageName when rebooting with lskf."); - return false; + return REBOOT_ERROR_INVALID_PACKAGE_NAME; } if (!isLskfCaptured(packageName)) { - return false; + return REBOOT_ERROR_LSKF_NOT_CAPTURED; } if (!verifySlotForNextBoot(slotSwitch)) { - return false; + return REBOOT_ERROR_SLOT_MISMATCH; } - // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot. if (!mInjector.getLockSettingsService().armRebootEscrow()) { Slog.w(TAG, "Failure to escrow key for reboot"); + return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE; + } + + return REBOOT_ERROR_NONE; + } + + private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch, + @ResumeOnRebootRebootErrorCode int errorCode) { + int uid = mInjector.getUidFromPackageName(packageName); + boolean serverBased = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, + "server_based_ror_enabled", false); + int preparedClientCount; + synchronized (this) { + preparedClientCount = mCallerPreparedForReboot.size(); + } + + long currentTimestamp = mInjector.getCurrentTimeMillis(); + int durationSeconds = -1; + PreferencesManager prefs = mInjector.getMetricsPrefs(); + long lskfCapturedTimestamp = prefs.getLong(LSKF_CAPTURED_TIMESTAMP_PREF, -1); + if (lskfCapturedTimestamp != -1 && currentTimestamp > lskfCapturedTimestamp) { + durationSeconds = (int) (currentTimestamp - lskfCapturedTimestamp) / 1000; + } + + int requestCount = prefs.getInt(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, -1); + int lskfCapturedCount = prefs.getInt(LSKF_CAPTURED_COUNT_PREF, -1); + + Slog.i(TAG, String.format("Reporting reboot with lskf, package name %s, client count %d," + + " request count %d, lskf captured count %d, duration since lskf captured" + + " %d seconds.", packageName, preparedClientCount, requestCount, + lskfCapturedCount, durationSeconds)); + mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, + requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount); + } + + private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { + @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch); + reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode); + + if (errorCode != REBOOT_ERROR_NONE) { return false; } + // Clear the metrics prefs after a successful RoR reboot. + mInjector.getMetricsPrefs().deletePrefsFile(); + PowerManager pm = mInjector.getPowerManager(); pm.reboot(reason); return true; diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 69a153f79a1b..9589505ef251 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -42,7 +42,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; -import android.net.NetworkAgent.ValidationStatus; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; @@ -1442,17 +1441,16 @@ public class VcnGatewayConnection extends StateMachine { caps, lp, Vcn.getNetworkScore(), - new NetworkAgentConfig(), + new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override - public void unwanted() { + public void onNetworkUnwanted() { Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } @Override - public void onValidationStatus( - @ValidationStatus int status, @Nullable Uri redirectUri) { + public void onValidationStatus(int status, @Nullable Uri redirectUri) { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { clearFailedAttemptCounterAndSafeModeAlarm(); } @@ -1798,8 +1796,10 @@ public class VcnGatewayConnection extends StateMachine { lp.addDnsServer(addr); } - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); - lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); lp.setMtu(gatewayConnectionConfig.getMaxMtu()); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS index 5a4431ee8c89..5492dc8e37a3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS @@ -1,2 +1 @@ -calin@google.com -ngeoffray@google.com +include platform/art:/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java index e605d755183f..13d75a77507f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java @@ -245,14 +245,6 @@ public final class ArtStatsLogUtilsTest { UID, COMPILATION_REASON, COMPILER_FILTER, - ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, - DEX_CONTENT.length, - dexMetadataType); - inorder.verify(mockLogger).write( - SESSION_ID, - UID, - COMPILATION_REASON, - COMPILER_FILTER, ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, COMPILE_TIME, dexMetadataType); diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java index 9b8a2a82c6df..7903a90979fb 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java @@ -18,9 +18,11 @@ package com.android.server.recoverysystem; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -70,6 +72,8 @@ public class RecoverySystemServiceTest { private FileWriter mUncryptUpdateFileWriter; private LockSettingsInternal mLockSettingsInternal; private IBootControl mIBootControl; + private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter; + private RecoverySystemService.PreferencesManager mSharedPreferences; private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package"; private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package"; @@ -94,9 +98,12 @@ public class RecoverySystemServiceTest { when(mIBootControl.getCurrentSlot()).thenReturn(0); when(mIBootControl.getActiveBootSlot()).thenReturn(1); + mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class); + mSharedPreferences = mock(RecoverySystemService.PreferencesManager.class); + mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties, powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal, - mIBootControl); + mIBootControl, mMetricsReporter, mSharedPreferences); } @Test @@ -227,12 +234,35 @@ public class RecoverySystemServiceTest { } @Test + public void requestLskf_reportMetrics() throws Exception { + IntentSender intentSender = mock(IntentSender.class); + assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), + is(true)); + verify(mMetricsReporter).reportRebootEscrowPreparationMetrics( + eq(1000), eq(0) /* need preparation */, eq(1) /* client count */); + verify(mSharedPreferences).putLong(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), eq(100_000L)); + } + + + @Test public void requestLskf_success() throws Exception { IntentSender intentSender = mock(IntentSender.class); assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), is(true)); + + when(mSharedPreferences.getLong(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), anyLong())) + .thenReturn(200_000L).thenReturn(5000L); + mRecoverySystemService.onPreparedForReboot(true); + verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics( + eq(1000), eq(1) /* client count */, + eq(-1) /* invalid duration */); + mRecoverySystemService.onPreparedForReboot(true); verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any()); + verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics( + eq(1000), eq(1) /* client count */, eq(95) /* duration */); } @Test @@ -255,6 +285,8 @@ public class RecoverySystemServiceTest { assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), is(true)); verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any()); + verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics( + anyInt(), anyInt(), anyInt()); } @Test @@ -334,9 +366,19 @@ public class RecoverySystemServiceTest { public void rebootWithLskf_Success() throws Exception { assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true)); mRecoverySystemService.onPreparedForReboot(true); + + when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(3); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(40_000L); assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true), is(true)); verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); + verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000), + eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(60) /* duration */, eq(3) /* lskf capture count */); } @@ -373,6 +415,26 @@ public class RecoverySystemServiceTest { verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); } + @Test + public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception { + assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true)); + assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); + mRecoverySystemService.onPreparedForReboot(true); + + when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(1); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(60_000L); + + assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true), + is(true)); + verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); + verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000), + eq(2) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1) /* lskf capture count */); + } @Test public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception { @@ -380,16 +442,30 @@ public class RecoverySystemServiceTest { mRecoverySystemService.onPreparedForReboot(true); assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); + when(mSharedPreferences.getInt(eq(FAKE_OTHER_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(1); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(60_000L); + assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true)); assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true), is(false)); verifyNoMoreInteractions(mIPowerManager); + verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000), + eq(1) /* client count */, anyInt() /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1)/* lskf capture count */); assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); assertThat( mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true), is(true)); verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); + + verify(mMetricsReporter).reportRebootEscrowRebootMetrics((eq(0)), eq(2000), + eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1) /* lskf capture count */); } @Test diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java index 0727e5adb9ca..27e953f30fa0 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java @@ -32,11 +32,14 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { private final UncryptSocket mUncryptSocket; private final LockSettingsInternal mLockSettingsInternal; private final IBootControl mIBootControl; + private final IMetricsReporter mIMetricsReporter; + private final RecoverySystemService.PreferencesManager mSharedPreferences; MockInjector(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl) { + IBootControl bootControl, IMetricsReporter metricsReporter, + RecoverySystemService.PreferencesManager preferences) { super(context); mSystemProperties = systemProperties; mPowerManager = powerManager; @@ -44,6 +47,8 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { mUncryptSocket = uncryptSocket; mLockSettingsInternal = lockSettingsInternal; mIBootControl = bootControl; + mIMetricsReporter = metricsReporter; + mSharedPreferences = preferences; } @Override @@ -94,14 +99,58 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { public IBootControl getBootControl() { return mIBootControl; } + @Override + public int getUidFromPackageName(String packageName) { + if ("fake.ota.package".equals(packageName)) { + return 1000; + } + if ("fake.other.package".equals(packageName)) { + return 2000; + } + return 3000; + } + + @Override + public void reportRebootEscrowPreparationMetrics(int uid, int requestResult, + int requestedClientCount) { + mIMetricsReporter.reportRebootEscrowPreparationMetrics(uid, requestResult, + requestedClientCount); + } + + @Override + public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds) { + mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount, + requestedToLskfCapturedDurationInSeconds); + } + + @Override + public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, + int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { + mIMetricsReporter.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, + requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds, + lskfCapturedCounts); + } + + @Override + public long getCurrentTimeMillis() { + return 100_000; + } + + @Override + public RecoverySystemService.PreferencesManager getMetricsPrefs() { + return mSharedPreferences; + } } RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl) { + IBootControl bootControl, IMetricsReporter metricsReporter, + RecoverySystemService.PreferencesManager preferences) { super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter, - uncryptSocket, lockSettingsInternal, bootControl)); + uncryptSocket, lockSettingsInternal, bootControl, metricsReporter, preferences)); } public static class FakeSystemProperties { @@ -131,4 +180,16 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { return mCtlStart; } } + + public interface IMetricsReporter { + void reportRebootEscrowPreparationMetrics(int uid, int requestResult, + int requestedClientCount); + + void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds); + + void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, + int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts); + } } diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index ec7d4bd0d8c0..647a2a2ec53d 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -60,9 +60,9 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.service.ServiceProtoEnums; import android.service.usb.UsbPortInfoProto; import android.service.usb.UsbPortManagerProto; -import android.service.usb.UsbServiceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -992,15 +992,15 @@ public class UsbPortManager { private static int convertContaminantDetectionStatusToProto(int contaminantDetectionStatus) { switch (contaminantDetectionStatus) { case UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED: - return UsbServiceProto.CONTAMINANT_STATUS_NOT_SUPPORTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_SUPPORTED; case UsbPortStatus.CONTAMINANT_DETECTION_DISABLED: - return UsbServiceProto.CONTAMINANT_STATUS_DISABLED; + return ServiceProtoEnums.CONTAMINANT_STATUS_DISABLED; case UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED: - return UsbServiceProto.CONTAMINANT_STATUS_NOT_DETECTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_DETECTED; case UsbPortStatus.CONTAMINANT_DETECTION_DETECTED: - return UsbServiceProto.CONTAMINANT_STATUS_DETECTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_DETECTED; default: - return UsbServiceProto.CONTAMINANT_STATUS_UNKNOWN; + return ServiceProtoEnums.CONTAMINANT_STATUS_UNKNOWN; } } |