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

Commit 1d8b88f0 authored by Tom Chan's avatar Tom Chan
Browse files

Restart WearableSensingService process before sending connection

Restart the WearableSensingService process before sending it a new
secure wearable connection if it has not been restarted after the
previous one is provided.

Test: atest CtsWearableSensingServiceTestCases
Bug: 301427767
Change-Id: I96ffa4e19dd82f1ab863e6e78b2dd6e1b45d168c
parent 43b0f2fe
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -206,9 +206,10 @@ public class WearableSensingManager {
     * and kill the WearableSensingService process.
     *
     * <p>Before providing the secureWearableConnection, the system will restart the
     * WearableSensingService process. Other method calls into WearableSensingService may be dropped
     * during the restart. The caller is responsible for ensuring other method calls are queued
     * until a success status is returned from the {@code statusConsumer}.
     * WearableSensingService process if it has not been restarted since the last
     * secureWearableConnection was provided. Other method calls into WearableSensingService may be
     * dropped during the restart. The caller is responsible for ensuring other method calls are
     * queued until a success status is returned from the {@code statusConsumer}.
     *
     * @param wearableConnection The connection to provide
     * @param executor Executor on which to run the consumer callback
+1 −0
Original line number Diff line number Diff line
@@ -37,4 +37,5 @@ oneway interface IWearableSensingService {
            in RemoteCallback detectionResultCallback, in RemoteCallback statusCallback);
    void stopDetection(in String packageName);
    void queryServiceStatus(in int[] eventTypes, in String packageName, in RemoteCallback callback);
    void killProcess();
}
 No newline at end of file
+8 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.SharedMemory;
import android.service.ambientcontext.AmbientContextDetectionResult;
@@ -242,6 +243,13 @@ public abstract class WearableSensingService extends Service {
                    WearableSensingService.this.onQueryServiceStatus(
                            new HashSet<>(Arrays.asList(events)), packageName, consumer);
                }

                /** {@inheritDoc} */
                @Override
                public void killProcess() {
                    Slog.d(TAG, "#killProcess");
                    Process.killProcess(Process.myPid());
                }
            };
        }
        Slog.w(TAG, "Incorrect service interface, returning null.");
+102 −11
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.wearable;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.Context.BIND_INCLUDE_CAPABILITIES;

import android.app.wearable.Flags;
import android.app.wearable.WearableSensingManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +32,7 @@ import android.service.wearable.IWearableSensingService;
import android.service.wearable.WearableSensingService;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.ServiceConnector;

import java.io.IOException;
@@ -40,6 +43,17 @@ final class RemoteWearableSensingService extends ServiceConnector.Impl<IWearable
            com.android.server.wearable.RemoteWearableSensingService.class.getSimpleName();
    private final static boolean DEBUG = false;

    private final Object mSecureWearableConnectionLock = new Object();

    // mNextSecureWearableConnectionContext will only be non-null when we are waiting for the
    // WearableSensingService process to restart. It will be set to null after it is passed into
    // WearableSensingService.
    @GuardedBy("mSecureWearableConnectionLock")
    private SecureWearableConnectionContext mNextSecureWearableConnectionContext;

    @GuardedBy("mSecureWearableConnectionLock")
    private boolean mSecureWearableConnectionProvided = false;

    RemoteWearableSensingService(Context context, ComponentName serviceName,
            int userId) {
        super(context, new Intent(
@@ -66,11 +80,55 @@ final class RemoteWearableSensingService extends ServiceConnector.Impl<IWearable
    public void provideSecureWearableConnection(
            ParcelFileDescriptor secureWearableConnection, RemoteCallback callback) {
        if (DEBUG) {
            Slog.i(TAG, "Providing secure wearable connection.");
            Slog.i(TAG, "#provideSecureWearableConnection");
        }
        var unused = post(
        if (!Flags.enableRestartWssProcess()) {
            Slog.d(
                    TAG,
                    "FLAG_ENABLE_RESTART_WSS_PROCESS is disabled. Do not attempt to restart the"
                        + " WearableSensingService process");
            provideSecureWearableConnectionInternal(secureWearableConnection, callback);
            return;
        }
        synchronized (mSecureWearableConnectionLock) {
            if (mNextSecureWearableConnectionContext != null) {
                // A process restart is in progress, #binderDied is about to be called. Replace
                // the previous mNextSecureWearableConnectionContext with the current one
                Slog.i(
                        TAG,
                        "A new wearable connection is provided before the process restart triggered"
                            + " by the previous connection is complete. Discarding the previous"
                            + " connection.");
                if (Flags.enableProvideWearableConnectionApi()) {
                    WearableSensingManagerPerUserService.notifyStatusCallback(
                            mNextSecureWearableConnectionContext.mStatusCallback,
                            WearableSensingManager.STATUS_CHANNEL_ERROR);
                }
                mNextSecureWearableConnectionContext =
                        new SecureWearableConnectionContext(secureWearableConnection, callback);
                return;
            }
            if (!mSecureWearableConnectionProvided) {
                // no need to kill the process
                provideSecureWearableConnectionInternal(secureWearableConnection, callback);
                mSecureWearableConnectionProvided = true;
                return;
            }
            mNextSecureWearableConnectionContext =
                    new SecureWearableConnectionContext(secureWearableConnection, callback);
            // Killing the process causes the binder to die. #binderDied will then be triggered
            killWearableSensingServiceProcess();
        }
    }

    private void provideSecureWearableConnectionInternal(
            ParcelFileDescriptor secureWearableConnection, RemoteCallback callback) {
        Slog.d(TAG, "Providing secure wearable connection.");
        var unused =
                post(
                        service -> {
                    service.provideSecureWearableConnection(secureWearableConnection, callback);
                            service.provideSecureWearableConnection(
                                    secureWearableConnection, callback);
                            try {
                                // close the local fd after it has been sent to the WSS process
                                secureWearableConnection.close();
@@ -80,6 +138,28 @@ final class RemoteWearableSensingService extends ServiceConnector.Impl<IWearable
                        });
    }

    @Override
    public void binderDied() {
        super.binderDied();
        synchronized (mSecureWearableConnectionLock) {
            if (mNextSecureWearableConnectionContext != null) {
                // This will call #post, which will recreate the process and bind to it
                provideSecureWearableConnectionInternal(
                        mNextSecureWearableConnectionContext.mSecureWearableConnection,
                        mNextSecureWearableConnectionContext.mStatusCallback);
                mNextSecureWearableConnectionContext = null;
            } else {
                mSecureWearableConnectionProvided = false;
                Slog.w(TAG, "Binder died but there is no secure wearable connection to provide.");
            }
        }
    }

    /** Kills the WearableSensingService process. */
    public void killWearableSensingServiceProcess() {
        var unused = post(service -> service.killProcess());
    }

    /**
     * Provides the implementation a data stream to the wearable.
     *
@@ -176,4 +256,15 @@ final class RemoteWearableSensingService extends ServiceConnector.Impl<IWearable
                                        packageName,
                                        statusCallback));
    }

    private static class SecureWearableConnectionContext {
        final ParcelFileDescriptor mSecureWearableConnection;
        final RemoteCallback mStatusCallback;

        SecureWearableConnectionContext(
                ParcelFileDescriptor secureWearableConnection, RemoteCallback statusCallback) {
            this.mSecureWearableConnection = secureWearableConnection;
            this.mStatusCallback = statusCallback;
        }
    }
}
+16 −5
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.server.infra.AbstractPerUserSystemService;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Per-user manager service for managing sensing {@link AmbientContextEvent}s on Wearables.
@@ -68,7 +69,7 @@ final class WearableSensingManagerPerUserService extends
        super(master, lock, userId);
    }

    static void notifyStatusCallback(RemoteCallback statusCallback, int statusCode) {
    public static void notifyStatusCallback(RemoteCallback statusCallback, int statusCode) {
        Bundle bundle = new Bundle();
        bundle.putInt(
                WearableSensingManager.STATUS_RESPONSE_BUNDLE_KEY, statusCode);
@@ -183,11 +184,11 @@ final class WearableSensingManagerPerUserService extends
        }
        synchronized (mSecureChannelLock) {
            if (mSecureChannel != null) {
                // TODO(b/321012559): Kill the WearableSensingService process if it has not been
                // killed from onError
                mSecureChannel.close();
            }
            try {
                final AtomicReference<WearableSensingSecureChannel> currentSecureChannelRef =
                        new AtomicReference<>();
                mSecureChannel =
                        WearableSensingSecureChannel.create(
                                getContext().getSystemService(CompanionDeviceManager.class),
@@ -206,8 +207,17 @@ final class WearableSensingManagerPerUserService extends

                                    @Override
                                    public void onError() {
                                        // TODO(b/321012559): Kill the WearableSensingService
                                        // process if mSecureChannel has not been reassigned
                                        if (Flags.enableRestartWssProcess()) {
                                            synchronized (mSecureChannelLock) {
                                                if (mSecureChannel != null
                                                        && mSecureChannel
                                                                == currentSecureChannelRef.get()) {
                                                    mRemoteService
                                                            .killWearableSensingServiceProcess();
                                                    mSecureChannel = null;
                                                }
                                            }
                                        }
                                        if (Flags.enableProvideWearableConnectionApi()) {
                                            notifyStatusCallback(
                                                    callback,
@@ -215,6 +225,7 @@ final class WearableSensingManagerPerUserService extends
                                        }
                                    }
                                });
                currentSecureChannelRef.set(mSecureChannel);
            } catch (IOException ex) {
                Slog.e(TAG, "Unable to create the secure channel.", ex);
                if (Flags.enableProvideWearableConnectionApi()) {