Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa2a82b0 authored by Neil Fuller's avatar Neil Fuller Committed by Android (Google) Code Review
Browse files

Merge "Adjust time zone provider permissions"

parents 655f6cdc ad4d5d36
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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";
  }
+19 −17
Original line number Diff line number Diff line
@@ -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
 * <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.
 *
 * <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} 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.
 * #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.
 *
 * For example:
 * <p>For example:
 * <pre>
 *   &lt;uses-permission
 *       android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"/&gt;
 *
 * ...
 *
 *     &lt;service android:name=".FooTimeZoneProviderService"
 *             android:exported="true"
 *             android:permission="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER"&gt;
 *             android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"&gt;
 *         &lt;intent-filter&gt;
 *             &lt;action
 *             android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService"
@@ -88,7 +99,6 @@ import java.util.Objects;
 *     &lt;/service&gt;
 * </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. */
+22 −3
Original line number Diff line number Diff line
@@ -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" />
+28 −4
Original line number Diff line number Diff line
@@ -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,
        List<ResolveInfo> resolveInfos = mContext.getPackageManager()
                .queryIntentServicesAsUser(mIntent,
                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
                UserHandle.USER_SYSTEM).isEmpty();
                        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;
+40 −1
Original line number Diff line number Diff line
@@ -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