Loading core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -5052,4 +5052,12 @@ <!-- the number of the max cached processes in the system. --> <integer name="config_customizedMaxCachedProcesses">32</integer> <!-- List of system components which are allowed to receive ServiceState entries in an un-sanitized form, even if the location toggle is off. This is intended ONLY for system components, such as the telephony stack, which require access to the full ServiceState for tasks such as network registration. --> <string-array name="config_serviceStateLocationAllowedPackages"> <item>"com.android.phone"</item> </string-array> </resources> core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4427,4 +4427,5 @@ <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" /> <java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" /> </resources> services/core/java/com/android/server/TelephonyRegistry.java +74 −28 Original line number Diff line number Diff line Loading @@ -2853,42 +2853,88 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Binder.restoreCallingIdentity(ident); } Intent intent = new Intent(Intent.ACTION_SERVICE_STATE); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Bundle data = new Bundle(); state.fillInNotifierBundle(data); intent.putExtras(data); // Pass the subscription along with the intent. intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE. // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION. // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE // get this broadcast exactly once, and we are not exposing location without permission. mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, // Send the broadcast exactly once to all possible disjoint sets of apps. // If the location master switch is on, broadcast the ServiceState 4 times: // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither // READ_PHONE_STATE nor ACCESS_FINE_LOCATION // If the location master switch is off, broadcast the ServiceState multiple times: // - Full ServiceState sent to all apps permitted to bypass the location master switch if // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not // READ_PHONE_STATE if (Binder.withCleanCallingIdentity(() -> LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) { Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}, new String[]{Manifest.permission.READ_PHONE_STATE}); // Replace bundle with location-sanitized ServiceState data = new Bundle(); state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); intent.putExtras(data); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PHONE_STATE}, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}); } else { String[] locationBypassPackages = Binder.withCleanCallingIdentity(() -> LocationAccessPolicy.getLocationBypassPackages(mContext)); for (String locationBypassPackage : locationBypassPackages) { Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); fullIntent.setPackage(locationBypassPackage); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PHONE_STATE}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE}); } Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PHONE_STATE}, new String[]{/* no excluded permissions */}, locationBypassPackages); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE}, locationBypassPackages); } } private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId, boolean sanitizeLocation) { Intent intent = new Intent(Intent.ACTION_SERVICE_STATE); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Bundle data = new Bundle(); if (sanitizeLocation) { state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); } else { state.fillInNotifierBundle(data); } intent.putExtras(data); intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); return intent; } private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId, Loading telephony/common/android/telephony/LocationAccessPolicy.java +12 −1 Original line number Diff line number Diff line Loading @@ -361,7 +361,10 @@ public final class LocationAccessPolicy { return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid); } private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { /** * @return Whether location is enabled for the given user. */ public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { LocationManager locationManager = context.getSystemService(LocationManager.class); if (locationManager == null) { Log.w(TAG, "Couldn't get location manager, denying location access"); Loading @@ -370,6 +373,14 @@ public final class LocationAccessPolicy { return locationManager.isLocationEnabledForUser(UserHandle.of(userId)); } /** * @return An array of packages that are always allowed to access location. */ public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) { return context.getResources().getStringArray( com.android.internal.R.array.config_serviceStateLocationAllowedPackages); } private static boolean checkInteractAcrossUsersFull( @NonNull Context context, int pid, int uid) { return checkManifestPermission(context, pid, uid, Loading Loading
core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -5052,4 +5052,12 @@ <!-- the number of the max cached processes in the system. --> <integer name="config_customizedMaxCachedProcesses">32</integer> <!-- List of system components which are allowed to receive ServiceState entries in an un-sanitized form, even if the location toggle is off. This is intended ONLY for system components, such as the telephony stack, which require access to the full ServiceState for tasks such as network registration. --> <string-array name="config_serviceStateLocationAllowedPackages"> <item>"com.android.phone"</item> </string-array> </resources>
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -4427,4 +4427,5 @@ <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" /> <java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> <java-symbol type="array" name="config_serviceStateLocationAllowedPackages" /> </resources>
services/core/java/com/android/server/TelephonyRegistry.java +74 −28 Original line number Diff line number Diff line Loading @@ -2853,42 +2853,88 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Binder.restoreCallingIdentity(ident); } Intent intent = new Intent(Intent.ACTION_SERVICE_STATE); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Bundle data = new Bundle(); state.fillInNotifierBundle(data); intent.putExtras(data); // Pass the subscription along with the intent. intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE. // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION. // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE // get this broadcast exactly once, and we are not exposing location without permission. mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, // Send the broadcast exactly once to all possible disjoint sets of apps. // If the location master switch is on, broadcast the ServiceState 4 times: // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE // - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and // READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE // - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION // - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither // READ_PHONE_STATE nor ACCESS_FINE_LOCATION // If the location master switch is off, broadcast the ServiceState multiple times: // - Full ServiceState sent to all apps permitted to bypass the location master switch if // they have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE // - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE // - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not // READ_PHONE_STATE if (Binder.withCleanCallingIdentity(() -> LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) { Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}, new String[]{Manifest.permission.READ_PHONE_STATE}); // Replace bundle with location-sanitized ServiceState data = new Bundle(); state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); intent.putExtras(data); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PHONE_STATE}, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION}); } else { String[] locationBypassPackages = Binder.withCleanCallingIdentity(() -> LocationAccessPolicy.getLocationBypassPackages(mContext)); for (String locationBypassPackage : locationBypassPackages) { Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false); fullIntent.setPackage(locationBypassPackage); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PHONE_STATE}); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( fullIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE}); } Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PHONE_STATE}, new String[]{/* no excluded permissions */}, locationBypassPackages); mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions( sanitizedIntent, new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, new String[]{Manifest.permission.READ_PHONE_STATE}, locationBypassPackages); } } private Intent createServiceStateIntent(ServiceState state, int subId, int phoneId, boolean sanitizeLocation) { Intent intent = new Intent(Intent.ACTION_SERVICE_STATE); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); Bundle data = new Bundle(); if (sanitizeLocation) { state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); } else { state.fillInNotifierBundle(data); } intent.putExtras(data); intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); return intent; } private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId, Loading
telephony/common/android/telephony/LocationAccessPolicy.java +12 −1 Original line number Diff line number Diff line Loading @@ -361,7 +361,10 @@ public final class LocationAccessPolicy { return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid); } private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { /** * @return Whether location is enabled for the given user. */ public static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { LocationManager locationManager = context.getSystemService(LocationManager.class); if (locationManager == null) { Log.w(TAG, "Couldn't get location manager, denying location access"); Loading @@ -370,6 +373,14 @@ public final class LocationAccessPolicy { return locationManager.isLocationEnabledForUser(UserHandle.of(userId)); } /** * @return An array of packages that are always allowed to access location. */ public static @NonNull String[] getLocationBypassPackages(@NonNull Context context) { return context.getResources().getStringArray( com.android.internal.R.array.config_serviceStateLocationAllowedPackages); } private static boolean checkInteractAcrossUsersFull( @NonNull Context context, int pid, int uid) { return checkManifestPermission(context, pid, uid, Loading