diff options
Diffstat (limited to 'services/core')
5 files changed, 390 insertions, 148 deletions
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6367ada4b336..f527da582959 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -72,8 +72,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 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; @@ -117,7 +117,6 @@ import android.net.INetd; import android.net.INetworkActivityListener; 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 +134,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; @@ -331,12 +331,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; @@ -510,16 +508,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 +584,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. */ @@ -1253,10 +1248,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); @@ -1785,7 +1780,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // 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); @@ -2237,53 +2232,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) { @@ -2757,19 +2716,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) { @@ -3694,7 +3650,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); @@ -4355,7 +4311,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". @@ -4570,11 +4526,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); @@ -5047,8 +5000,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; @@ -5781,14 +5734,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 @@ -5885,7 +5838,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) { @@ -6831,8 +6784,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) @@ -7955,8 +7908,8 @@ 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 |= NetworkPolicyManager.isUidBlocked( + mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered); callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0); } @@ -7974,16 +7927,14 @@ 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); @@ -7991,10 +7942,11 @@ public class ConnectivityService extends IConnectivityManager.Stub ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges) : oldVpnBlocked; - oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered, - oldRestrictBackground); - newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered, - newRestrictBackground); + final int blockedReasons = mUidBlockedReasons.get(nri.mUid, 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, @@ -8004,19 +7956,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; } @@ -8363,7 +8316,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; } diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index f8833071d1bf..f572b46a9b58 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -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..12a53151c30c 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -68,6 +68,7 @@ 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; @@ -1258,7 +1259,9 @@ 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() { // We are user controlled, not driven by NetworkRequest. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index aee0947f39f9..b7367e5170c6 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -56,6 +56,23 @@ 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_MASK; +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; @@ -414,6 +431,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 +585,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 +2907,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); @@ -3923,6 +3954,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 +3975,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 +3987,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 +4132,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 +4591,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 +4620,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_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); + if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + ": isForeground=" +isForeground @@ -4618,6 +4701,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 +4787,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 +4805,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 +4850,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 +4891,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 +5098,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 +5842,51 @@ 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 = BLOCKED_REASON_NONE; + } + if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + 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/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index fd2d8e1b834b..beebb3145018 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -16,6 +16,8 @@ package com.android.server.recoverysystem; +import static android.os.UserHandle.USER_SYSTEM; + import android.annotation.IntDef; import android.content.Context; import android.content.IntentSender; @@ -33,12 +35,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; @@ -52,6 +56,8 @@ 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 @@ -127,10 +133,28 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo /** * 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 code 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 {} static class Injector { protected final Context mContext; @@ -202,6 +226,35 @@ 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 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); + } } /** @@ -367,6 +420,16 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo } } + private void reportMetricsOnRequestLskf(String packageName, int requestResult) { + int uid = mInjector.getUidFromPackageName(packageName); + int pendingRequestCount; + synchronized (this) { + pendingRequestCount = mCallerPendingRequest.size(); + } + + mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount); + } + @Override // Binder call public boolean requestLskf(String packageName, IntentSender intentSender) { enforcePermissionForResumeOnReboot(); @@ -378,6 +441,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 +485,26 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY; } + private void reportMetricsOnPreparedForReboot() { + List<String> preparedClients; + synchronized (this) { + preparedClients = new ArrayList<>(mCallerPreparedForReboot); + } + + for (String packageName : preparedClients) { + int uid = mInjector.getUidFromPackageName(packageName); + mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(), + -1 /* duration */); + } + } + @Override public void onPreparedForReboot(boolean ready) { if (!ready) { return; } updateRoRPreparationStateOnPreparedForReboot(); + reportMetricsOnPreparedForReboot(); } private synchronized void updateRoRPreparationStateOnPreparedForReboot() { @@ -548,22 +627,49 @@ 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(); + } + + // TODO(b/179105110) report the true value of duration and counts + mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, + 1 /* request count */, slotSwitch, serverBased, + -1 /* duration */, 1 /* lskf capture count */); + } + + 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; } |