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

Commit 4e035a07 authored by Diya Bera's avatar Diya Bera Committed by Android (Google) Code Review
Browse files

Merge "Log if watch ranging is available on device" into main

parents 95fe3813 11f09ffa
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -20351,6 +20351,14 @@ public final class Settings {
         */
        public static final String MINMODE_ACTIVE = "minmode_active";
        /**
          * Indicates if watch ranging is available for the device.
         *
         * @hide
         */
        public static final String WATCH_RANGING_AVAILABLE =
                "watch_ranging_available";
        /**
         * Settings migrated from Wear OS settings provider.
         * @hide
+1 −0
Original line number Diff line number Diff line
@@ -132,5 +132,6 @@ public class GlobalSettings {
        Settings.Global.GLOBAL_ACTIONS_TIMEOUT_MILLIS,
        Settings.Global.WATCH_RANGING_SUPPORTED_BY_PRIMARY_DEVICE,
        Settings.Global.MINMODE_ACTIVE,
        Settings.Global.WATCH_RANGING_AVAILABLE,
    };
}
+1 −0
Original line number Diff line number Diff line
@@ -484,5 +484,6 @@ public class GlobalSettingsValidators {
        VALIDATORS.put(Global.WATCH_RANGING_SUPPORTED_BY_PRIMARY_DEVICE,
                new InclusiveIntegerRangeValidator(0, 1));
        VALIDATORS.put(Global.MINMODE_ACTIVE, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Global.WATCH_RANGING_AVAILABLE, BOOLEAN_VALIDATOR);
    }
}
+180 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.security.authenticationpolicy;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.proximity.IProximityProviderService;
import android.util.Slog;

import androidx.annotation.NonNull;

import java.util.function.Function;

/**
 * A {@link BroadcastReceiver} that is triggered daily by {@link AlarmManager} to
 * check and log the availability of watch ranging. This class interacts with
 * {@code ProximityProviderService} to determine if ranging is supported and updates
 * {@link Settings.Global.WATCH_RANGING_AVAILABLE}.
 *
 * @hide
 */
public class IdentityCheckWatchRangingLogger extends BroadcastReceiver {
    private static final String TAG = "IdentityCheckWatchRangingLogger";
    private static final String PROXIMITY_PROVIDER_SERVICE_BIND_INTENT_ACTION =
            "android.proximity.ProximityProviderService";
    public static final String ACTION_LOG_WATCH_RANGING_STATUS =
            "com.android.server.security.authenticationpolicy.log_watch_ranging_status";
    private static final int ALARM_REQUEST_CODE = 1001;

    private final String mProximityProviderServicePackageName;
    private final String mProximityProviderServiceClassName;
    private final Function<IBinder, IProximityProviderService> mProximityProviderServiceFunction;
    private final Handler mHandler;
    private final Context mContext;
    private ServiceConnection mServiceConnection;

    IdentityCheckWatchRangingLogger(@NonNull Context context,
            @NonNull String proximityProviderServiceClassName,
            @NonNull String proximityProviderServicePackageName,
            @NonNull Handler handler,
            @NonNull Function<IBinder, IProximityProviderService>
                    proximityProviderServiceFunction) {
        mContext = context;
        mProximityProviderServicePackageName = proximityProviderServicePackageName;
        mProximityProviderServiceClassName = proximityProviderServiceClassName;
        mProximityProviderServiceFunction = proximityProviderServiceFunction;
        mHandler = handler;
    }

    /**
     * Register this class to receive any broadcast of {@link ACTION_LOG_WATCH_RANGING_STATUS}.
     */
    public void registerReceiver() {
        final IntentFilter logWatchIntentFilter = new IntentFilter();
        logWatchIntentFilter.addAction(ACTION_LOG_WATCH_RANGING_STATUS);
        mContext.registerReceiver(this, logWatchIntentFilter, Context.RECEIVER_NOT_EXPORTED);
    }

    /**
     * Uses {@link AlarmManager} to schedule a broadcast of {@link ACTION_LOG_WATCH_RANGING_STATUS}
     * daily.
     */
    public void scheduleLogger() {
        AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
        if (alarmManager == null) {
            Slog.e(TAG, "AlarmManager not available.");
            return;
        }

        Intent intent = new Intent(ACTION_LOG_WATCH_RANGING_STATUS);
        intent.setPackage(mContext.getPackageName());
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                mContext,
                ALARM_REQUEST_CODE,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        long firstAlarmTime = System.currentTimeMillis();

        alarmManager.setRepeating(
                AlarmManager.RTC_WAKEUP,
                firstAlarmTime,
                AlarmManager.INTERVAL_DAY,
                pendingIntent
        );
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction() != null
                && intent.getAction().equals(ACTION_LOG_WATCH_RANGING_STATUS)) {
            logIfWatchRangingIsAvailable(context);
        }
    }


    private void logIfWatchRangingIsAvailable(Context context) {
        mHandler.post(() -> {
            if (mServiceConnection != null) {
                Slog.d(TAG, "Proximity provider service is already connected.");
                return;
            }
            mServiceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    if (service == null) {
                        Slog.d(TAG, "No service found for proximity provider.");

                        return;
                    }
                    final IProximityProviderService proximityProviderService =
                            mProximityProviderServiceFunction.apply(service);
                    if (proximityProviderService == null) {
                        Slog.e(TAG, "Proximity provider service is null");
                        return;
                    }
                    try {
                        final boolean isWatchRangingSupported =
                                proximityProviderService.isProximityCheckingSupported();
                        Slog.d(TAG, "Updating watch ranging available value to "
                                + isWatchRangingSupported);
                        Settings.Global.putInt(context.getContentResolver(),
                                Settings.Global.WATCH_RANGING_AVAILABLE,
                                isWatchRangingSupported ? 1 : 0);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Remote exception thrown");
                    } finally {
                        context.unbindService(mServiceConnection);
                        mServiceConnection = null;
                    }
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                    Slog.e(TAG, "Proximity provider service disconnected");
                    mServiceConnection = null;
                }
            };

            final Intent intent = new Intent(PROXIMITY_PROVIDER_SERVICE_BIND_INTENT_ACTION)
                    .setClassName(mProximityProviderServicePackageName,
                            mProximityProviderServiceClassName);
            final boolean bindSuccessful =
                    context.bindService(intent,
                            Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE /* flags */,
                            new HandlerExecutor(mHandler), mServiceConnection);

            if (!bindSuccessful) {
                Slog.d(TAG, "Couldn't find service for ProximityProviderService");
                mServiceConnection = null;
            }
        });
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ public class WatchRangingService implements WatchRangingServiceInternal {
                R.string.proximity_provider_service_package_name);
        mProximityProviderServiceClassName = mContext.getString(
                R.string.proximity_provider_service_class_name);

        initializeAndScheduleIdentityCheckWatchRangingLogger(context);
    }

    /**
@@ -234,6 +236,14 @@ public class WatchRangingService implements WatchRangingServiceInternal {
        return null;
    }

    private void initializeAndScheduleIdentityCheckWatchRangingLogger(Context context) {
        final IdentityCheckWatchRangingLogger logger = new IdentityCheckWatchRangingLogger(context,
                mProximityProviderServiceClassName, mProximityProviderServicePackageName, mHandler,
                mProximityProviderServiceFunction);
        logger.registerReceiver();
        logger.scheduleLogger();
    }

    /**
     * System service lifecycle for {@link WatchRangingService}.
     */
Loading