Merge "Update ServiceState broadcast for location permissions" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0d2e7006ce
@@ -5052,4 +5052,12 @@
|
|||||||
|
|
||||||
<!-- the number of the max cached processes in the system. -->
|
<!-- the number of the max cached processes in the system. -->
|
||||||
<integer name="config_customizedMaxCachedProcesses">32</integer>
|
<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>
|
</resources>
|
||||||
|
|||||||
@@ -4427,4 +4427,5 @@
|
|||||||
<java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
|
<java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
|
||||||
|
|
||||||
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
|
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
|
||||||
|
<java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2853,42 +2853,88 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
|||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(Intent.ACTION_SERVICE_STATE);
|
// Send the broadcast exactly once to all possible disjoint sets of apps.
|
||||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
// If the location master switch is on, broadcast the ServiceState 4 times:
|
||||||
Bundle data = new Bundle();
|
// - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and READ_PHONE_STATE
|
||||||
state.fillInNotifierBundle(data);
|
// - Full ServiceState sent to apps with ACCESS_FINE_LOCATION and
|
||||||
intent.putExtras(data);
|
// READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE
|
||||||
// Pass the subscription along with the intent.
|
// - Sanitized ServiceState sent to apps with READ_PHONE_STATE but not ACCESS_FINE_LOCATION
|
||||||
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
|
// - Sanitized ServiceState sent to apps with READ_PRIVILEGED_PHONE_STATE but neither
|
||||||
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
|
// READ_PHONE_STATE nor ACCESS_FINE_LOCATION
|
||||||
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
|
// If the location master switch is off, broadcast the ServiceState multiple times:
|
||||||
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
|
// - 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
|
||||||
// Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again
|
// - Sanitized ServiceState sent to all other apps with READ_PHONE_STATE
|
||||||
// for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE.
|
// - Sanitized ServiceState sent to all other apps with READ_PRIVILEGED_PHONE_STATE but not
|
||||||
// Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with
|
// READ_PHONE_STATE
|
||||||
// the location-sanitized service state for all apps without ACCESS_FINE_LOCATION.
|
if (Binder.withCleanCallingIdentity(() ->
|
||||||
// This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
|
LocationAccessPolicy.isLocationModeEnabled(mContext, mContext.getUserId()))) {
|
||||||
// get this broadcast exactly once, and we are not exposing location without permission.
|
Intent fullIntent = createServiceStateIntent(state, subId, phoneId, false);
|
||||||
mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
|
mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
|
||||||
|
fullIntent,
|
||||||
new String[]{Manifest.permission.READ_PHONE_STATE,
|
new String[]{Manifest.permission.READ_PHONE_STATE,
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION});
|
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,
|
new String[]{Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION},
|
Manifest.permission.ACCESS_FINE_LOCATION},
|
||||||
new String[]{Manifest.permission.READ_PHONE_STATE});
|
new String[]{Manifest.permission.READ_PHONE_STATE});
|
||||||
|
|
||||||
// Replace bundle with location-sanitized ServiceState
|
Intent sanitizedIntent = createServiceStateIntent(state, subId, phoneId, true);
|
||||||
data = new Bundle();
|
mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(
|
||||||
state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data);
|
sanitizedIntent,
|
||||||
intent.putExtras(data);
|
|
||||||
mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent,
|
|
||||||
new String[]{Manifest.permission.READ_PHONE_STATE},
|
new String[]{Manifest.permission.READ_PHONE_STATE},
|
||||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION});
|
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_PRIVILEGED_PHONE_STATE},
|
||||||
new String[]{Manifest.permission.READ_PHONE_STATE,
|
new String[]{Manifest.permission.READ_PHONE_STATE,
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION});
|
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,
|
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
|
||||||
|
|||||||
@@ -361,7 +361,10 @@ public final class LocationAccessPolicy {
|
|||||||
return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid);
|
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);
|
LocationManager locationManager = context.getSystemService(LocationManager.class);
|
||||||
if (locationManager == null) {
|
if (locationManager == null) {
|
||||||
Log.w(TAG, "Couldn't get location manager, denying location access");
|
Log.w(TAG, "Couldn't get location manager, denying location access");
|
||||||
@@ -370,6 +373,14 @@ public final class LocationAccessPolicy {
|
|||||||
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
|
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(
|
private static boolean checkInteractAcrossUsersFull(
|
||||||
@NonNull Context context, int pid, int uid) {
|
@NonNull Context context, int pid, int uid) {
|
||||||
return checkManifestPermission(context, pid, uid,
|
return checkManifestPermission(context, pid, uid,
|
||||||
|
|||||||
Reference in New Issue
Block a user