Adjust time zone provider permissions
Modify ther permissions system around TimeZoneProviderService discovery. Bug: 175718639 Test: Confirmed witholding the INSTALL_ permission led to a boot failure Test: build / boot / treehugger Change-Id: Id91fa7716e3ccc53cd2801aa4d7a469c01c990b6
This commit is contained in:
@@ -51,6 +51,7 @@ package android {
|
||||
field public static final String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
|
||||
field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
|
||||
field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
|
||||
field public static final String BIND_TIME_ZONE_PROVIDER_SERVICE = "android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE";
|
||||
field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
|
||||
field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
|
||||
field public static final String BRICK = "android.permission.BRICK";
|
||||
@@ -99,7 +100,7 @@ package android {
|
||||
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
|
||||
field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
|
||||
field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
|
||||
field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
|
||||
field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE";
|
||||
field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
|
||||
field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
|
||||
field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
|
||||
@@ -9776,7 +9777,6 @@ package android.service.timezone {
|
||||
method public final void reportPermanentFailure(@NonNull Throwable);
|
||||
method public final void reportSuggestion(@NonNull android.service.timezone.TimeZoneProviderSuggestion);
|
||||
method public final void reportUncertain();
|
||||
field public static final String BIND_PERMISSION = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
|
||||
field public static final String PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.PrimaryLocationTimeZoneProviderService";
|
||||
field public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.SecondaryLocationTimeZoneProviderService";
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ import java.util.Objects;
|
||||
* <p>Provider discovery:
|
||||
*
|
||||
* <p>You must declare the service in your manifest file with the
|
||||
* {@link android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER} permission,
|
||||
* {@link android.Manifest.permission#BIND_TIME_ZONE_PROVIDER_SERVICE} permission,
|
||||
* and include an intent filter with the necessary action indicating what type of provider it is.
|
||||
*
|
||||
* <p>Device configuration can influence how {@link TimeZoneProviderService}s are discovered.
|
||||
@@ -66,18 +66,29 @@ import java.util.Objects;
|
||||
*
|
||||
* <p>Provider types:
|
||||
*
|
||||
* <p>Android currently supports up to two location-derived time zone providers. These are called
|
||||
* the "primary" and "secondary" location time zone provider, configured using {@link
|
||||
* #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
|
||||
* #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} respectively. The primary location time
|
||||
* zone provider is started first and will be used until becomes uncertain or fails, at which point
|
||||
* the secondary provider will be started.
|
||||
* <p>Android supports up to two <em>location-derived</em> time zone providers. These are called the
|
||||
* "primary" and "secondary" location time zone provider. The primary location time zone provider is
|
||||
* started first and will be used until it becomes uncertain or fails, at which point the secondary
|
||||
* provider will be started.
|
||||
*
|
||||
* For example:
|
||||
* <p>Location-derived time zone providers are configured using {@link
|
||||
* #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
|
||||
* #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} intent-filter actions respectively.
|
||||
* Besides declaring the android:permission attribute mentioned above, the application supplying a
|
||||
* location provider must be granted the {@link
|
||||
* android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE} permission to be
|
||||
* accepted by the system server.
|
||||
*
|
||||
* <p>For example:
|
||||
* <pre>
|
||||
* <uses-permission
|
||||
* android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"/>
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* <service android:name=".FooTimeZoneProviderService"
|
||||
* android:exported="true"
|
||||
* android:permission="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER">
|
||||
* android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE">
|
||||
* <intent-filter>
|
||||
* <action
|
||||
* android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService"
|
||||
@@ -88,7 +99,6 @@ import java.util.Objects;
|
||||
* </service>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>Threading:
|
||||
*
|
||||
* <p>Calls to {@code report} methods can be made on on any thread and will be passed asynchronously
|
||||
@@ -120,14 +130,6 @@ public abstract class TimeZoneProviderService extends Service {
|
||||
public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE =
|
||||
"android.service.timezone.SecondaryLocationTimeZoneProviderService";
|
||||
|
||||
/**
|
||||
* The permission that a service must require to ensure that only Android system can bind to it.
|
||||
* If this permission is not enforced in the AndroidManifest of the service, the system will
|
||||
* skip that service.
|
||||
*/
|
||||
public static final String BIND_PERMISSION =
|
||||
"android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
|
||||
|
||||
private final TimeZoneProviderServiceWrapper mWrapper = new TimeZoneProviderServiceWrapper();
|
||||
|
||||
/** Set by {@link #mHandler} thread. */
|
||||
|
||||
@@ -1591,13 +1591,31 @@
|
||||
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi @hide Allows an application to install a LocationTimeZoneProvider into the
|
||||
LocationTimeZoneProviderManager.
|
||||
<!-- @SystemApi @hide Allows an application to provide location-based time zone suggestions to
|
||||
the system server. This is needed because the system server discovers time zone providers
|
||||
by exposed intent actions and metadata, without it any app could potentially register
|
||||
itself as time zone provider. The system server checks for this permission.
|
||||
<p>Not for use by third-party applications.
|
||||
-->
|
||||
<permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER"
|
||||
<permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- The system server uses this permission to install a default secondary location time zone
|
||||
provider.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"/>
|
||||
|
||||
<!-- @SystemApi @hide Allows an application to bind to a android.service.TimeZoneProviderService
|
||||
for the purpose of detecting the device's time zone. This prevents arbitrary clients
|
||||
connecting to the time zone provider service. The system server checks that the provider's
|
||||
intent service explicitly sets this permission via the android:permission attribute of the
|
||||
service.
|
||||
This is only expected to be possessed by the system server outside of tests.
|
||||
<p>Not for use by third-party applications.
|
||||
-->
|
||||
<permission android:name="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
|
||||
This should only be used by HDMI-CEC service.
|
||||
-->
|
||||
@@ -5786,6 +5804,7 @@
|
||||
data set from the com.android.geotz APEX. -->
|
||||
<service android:name="com.android.timezone.geotz.provider.OfflineLocationTimeZoneProviderService"
|
||||
android:enabled="@bool/config_enableSecondaryLocationTimeZoneProvider"
|
||||
android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService" />
|
||||
|
||||
@@ -26,6 +26,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
|
||||
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
|
||||
|
||||
import android.annotation.BoolRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringRes;
|
||||
import android.annotation.UserIdInt;
|
||||
@@ -53,6 +54,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Maintains a binding to the best service that matches the given intent information. Bind and
|
||||
@@ -68,6 +70,8 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
|
||||
private static final long RETRY_DELAY_MS = 15 * 1000;
|
||||
|
||||
private static final Predicate<ResolveInfo> DEFAULT_SERVICE_CHECK_PREDICATE = x -> true;
|
||||
|
||||
/** Function to run on binder interface. */
|
||||
public interface BinderRunner {
|
||||
/** Called to run client code with the binder. */
|
||||
@@ -184,6 +188,7 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final Intent mIntent;
|
||||
private final Predicate<ResolveInfo> mServiceCheckPredicate;
|
||||
|
||||
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
||||
@Override
|
||||
@@ -239,15 +244,24 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
@Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
|
||||
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
|
||||
this(context, FgThread.getHandler(), action, onBind, onUnbind, enableOverlayResId,
|
||||
nonOverlayPackageResId);
|
||||
nonOverlayPackageResId, DEFAULT_SERVICE_CHECK_PREDICATE);
|
||||
}
|
||||
|
||||
public ServiceWatcher(Context context, Handler handler, String action,
|
||||
@Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
|
||||
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
|
||||
this(context, handler, action, onBind, onUnbind, enableOverlayResId, nonOverlayPackageResId,
|
||||
DEFAULT_SERVICE_CHECK_PREDICATE);
|
||||
}
|
||||
|
||||
public ServiceWatcher(Context context, Handler handler, String action,
|
||||
@Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
|
||||
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId,
|
||||
@NonNull Predicate<ResolveInfo> serviceCheckPredicate) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mIntent = new Intent(Objects.requireNonNull(action));
|
||||
mServiceCheckPredicate = Objects.requireNonNull(serviceCheckPredicate);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
boolean enableOverlay = resources.getBoolean(enableOverlayResId);
|
||||
@@ -269,9 +283,16 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
* constraints.
|
||||
*/
|
||||
public boolean checkServiceResolves() {
|
||||
return !mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
|
||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
|
||||
UserHandle.USER_SYSTEM).isEmpty();
|
||||
List<ResolveInfo> resolveInfos = mContext.getPackageManager()
|
||||
.queryIntentServicesAsUser(mIntent,
|
||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
|
||||
UserHandle.USER_SYSTEM);
|
||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
if (mServiceCheckPredicate.test(resolveInfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,6 +341,9 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
|
||||
mCurrentUserId);
|
||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
if (!mServiceCheckPredicate.test(resolveInfo)) {
|
||||
continue;
|
||||
}
|
||||
ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
|
||||
if (serviceInfo.compareTo(bestServiceInfo) > 0) {
|
||||
bestServiceInfo = serviceInfo;
|
||||
|
||||
@@ -16,10 +16,18 @@
|
||||
|
||||
package com.android.server.location.timezone;
|
||||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@@ -32,6 +40,7 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.ServiceWatcher;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* System server-side proxy for ITimeZoneProvider implementations, i.e. this provides the
|
||||
@@ -57,8 +66,38 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
|
||||
super(context, threadingDomain);
|
||||
mManagerProxy = null;
|
||||
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
|
||||
|
||||
// A predicate that is used to confirm that an intent service can be used as a
|
||||
// location-based TimeZoneProvider. The service must:
|
||||
// 1) Declare android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE" - this
|
||||
// ensures that the provider will only communicate with the system server.
|
||||
// 2) Be in an application that has been granted the
|
||||
// android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE permission. This
|
||||
// ensures only trusted time zone providers will be discovered.
|
||||
final String requiredClientPermission = Manifest.permission.BIND_TIME_ZONE_PROVIDER_SERVICE;
|
||||
final String requiredPermission =
|
||||
Manifest.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE;
|
||||
Predicate<ResolveInfo> intentServiceCheckPredicate = resolveInfo -> {
|
||||
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||
|
||||
boolean hasClientPermissionRequirement =
|
||||
requiredClientPermission.equals(serviceInfo.permission);
|
||||
|
||||
String packageName = serviceInfo.packageName;
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
int checkResult = packageManager.checkPermission(requiredPermission, packageName);
|
||||
boolean hasRequiredPermission = checkResult == PERMISSION_GRANTED;
|
||||
|
||||
boolean result = hasClientPermissionRequirement && hasRequiredPermission;
|
||||
if (!result) {
|
||||
warnLog("resolveInfo=" + resolveInfo + " does not meet requirements:"
|
||||
+ " hasClientPermissionRequirement=" + hasClientPermissionRequirement
|
||||
+ ", hasRequiredPermission=" + hasRequiredPermission);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
mServiceWatcher = new ServiceWatcher(context, handler, action, this::onBind, this::onUnbind,
|
||||
enableOverlayResId, nonOverlayPackageResId);
|
||||
enableOverlayResId, nonOverlayPackageResId, intentServiceCheckPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user