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

Commit 324aa3e5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Simplify SelectionToolbarManagerService" into main

parents ce2befee 0f904301
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -2993,6 +2993,11 @@ public final class SystemServer implements Dumpable {
            Slog.d(TAG, "TranslationService not defined by OEM");
        }

        // NOTE: ClipboardService depends on ContentCapture and Autofill
        t.traceBegin("StartClipboardService");
        mSystemServiceManager.startService(ClipboardService.class);
        t.traceEnd();

        if (!isTv) {
            // Selection toolbar service
            t.traceBegin("StartSelectionToolbarManagerService");
@@ -3000,11 +3005,6 @@ public final class SystemServer implements Dumpable {
            t.traceEnd();
        }

        // NOTE: ClipboardService depends on ContentCapture and Autofill
        t.traceBegin("StartClipboardService");
        mSystemServiceManager.startService(ClipboardService.class);
        t.traceEnd();

        t.traceBegin("AppServiceManager");
        mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
        t.traceEnd();
+0 −84
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.selectiontoolbar;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.service.selectiontoolbar.ISelectionToolbarRenderService;
import android.service.selectiontoolbar.SelectionToolbarRenderService;
import android.util.Slog;
import android.view.selectiontoolbar.ISelectionToolbarCallback;
import android.view.selectiontoolbar.ShowInfo;

import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.ServiceConnector;

final class RemoteSelectionToolbarRenderService extends
        ServiceConnector.Impl<ISelectionToolbarRenderService> {
    private static final String TAG = "RemoteSelectionToolbarRenderService";

    private static final long TIMEOUT_IDLE_UNBIND_MS =
            AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS;

    private final ComponentName mComponentName;
    private final IBinder mRemoteCallback;

    RemoteSelectionToolbarRenderService(Context context, ComponentName serviceName, int userId,
            IBinder callback) {
        super(context, new Intent(SelectionToolbarRenderService.SERVICE_INTERFACE).setComponent(
                serviceName), 0, userId, ISelectionToolbarRenderService.Stub::asInterface);
        mComponentName = serviceName;
        mRemoteCallback = callback;
        // Bind right away.
        connect();
    }

    @Override // from AbstractRemoteService
    protected long getAutoDisconnectTimeoutMs() {
        return TIMEOUT_IDLE_UNBIND_MS;
    }

    @Override // from ServiceConnector.Impl
    protected void onServiceConnectionStatusChanged(ISelectionToolbarRenderService service,
            boolean connected) {
        try {
            if (connected) {
                service.onConnected(mRemoteCallback);
            }
        } catch (Exception e) {
            Slog.w(TAG, "Exception calling onConnected().", e);
        }
    }

    public ComponentName getComponentName() {
        return mComponentName;
    }

    public void onShow(int callingUid, ShowInfo showInfo, ISelectionToolbarCallback callback) {
        run((s) -> s.onShow(callingUid, showInfo, callback));
    }

    public void onHide(long widgetToken) {
        run((s) -> s.onHide(widgetToken));
    }

    public void onDismiss(int callingUid, long widgetToken) {
        run((s) -> s.onDismiss(callingUid, widgetToken));
    }
}
+112 −54
Original line number Diff line number Diff line
@@ -16,95 +16,153 @@

package com.android.server.selectiontoolbar;

import static android.permission.flags.Flags.useSystemSelectionToolbarInSysui;

import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.UserHandle;
import android.service.selectiontoolbar.DefaultSelectionToolbarRenderService;
import android.service.selectiontoolbar.ISelectionToolbarRenderService;
import android.service.selectiontoolbar.ISelectionToolbarRenderServiceCallback;
import android.service.selectiontoolbar.SelectionToolbarRenderService;
import android.util.Slog;
import android.view.selectiontoolbar.ISelectionToolbarCallback;
import android.view.selectiontoolbar.ISelectionToolbarManager;
import android.view.selectiontoolbar.ShowInfo;

import com.android.internal.util.DumpUtils;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.internal.R;
import com.android.internal.infra.ServiceConnector;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.clipboard.ClipboardManagerInternal;
import com.android.server.input.InputManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * Entry point service for selection toolbar management.
 */
public final class SelectionToolbarManagerService extends
        AbstractMasterSystemService<SelectionToolbarManagerService,
                SelectionToolbarManagerServiceImpl> {
public class SelectionToolbarManagerService extends SystemService {

    private static final String LOG_TAG = SelectionToolbarManagerService.class.getSimpleName();

    private final SelectionToolbarRenderServiceRemoteCallback mRemoteServiceCallback =
            new SelectionToolbarRenderServiceRemoteCallback();
    private final RemoteRenderServiceConnector mRemoteRenderServiceConnector;

    private InputManagerInternal mInputManagerInternal;
    private ClipboardManagerInternal mClipboardManagerInternal;

    private static final String TAG = "SelectionToolbarManagerService";

    public SelectionToolbarManagerService(Context context) {
        super(context);

        String serviceName;
        if (useSystemSelectionToolbarInSysui()) {
            serviceName = context.getResources()
                    .getString(R.string.config_systemUiSelectionToolbarRenderService);
        } else {
            serviceName = new ComponentName(
                    "android", DefaultSelectionToolbarRenderService.class.getName())
                    .flattenToString();
        }
        final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
        mRemoteRenderServiceConnector = new RemoteRenderServiceConnector(context,
                serviceComponent, UserHandle.USER_SYSTEM, mRemoteServiceCallback);
    }

    @Override
    public void onStart() {
        publishBinderService(Context.SELECTION_TOOLBAR_SERVICE,
                new SelectionToolbarManagerService.SelectionToolbarManagerServiceStub());
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
        mClipboardManagerInternal = LocalServices.getService(ClipboardManagerInternal.class);

        publishBinderService(Context.SELECTION_TOOLBAR_SERVICE, new Stub());
    }

    public SelectionToolbarManagerService(Context context) {
        super(context, new SelectionToolbarServiceNameResolver(context), /* disallowProperty= */
                null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
    @Override
    public void onBootPhase(int phase) {
        super.onBootPhase(phase);

        if (phase == SystemService.PHASE_BOOT_COMPLETED) {
            mRemoteRenderServiceConnector.connect(); // Prepare the binding in advance
        }
    }

    private class Stub extends ISelectionToolbarManager.Stub {

        @Override
    protected SelectionToolbarManagerServiceImpl newServiceLocked(int resolvedUserId,
            boolean disabled) {
        return new SelectionToolbarManagerServiceImpl(this, mLock, resolvedUserId);
        public void showToolbar(ShowInfo showInfo,
                ISelectionToolbarCallback iSelectionToolbarCallback) {
            mRemoteRenderServiceConnector
                    .showToolbar(Binder.getCallingUid(), showInfo, iSelectionToolbarCallback);
        }

    @SuppressWarnings("GuardedBy") // mLock == service.mLock
    final class SelectionToolbarManagerServiceStub extends ISelectionToolbarManager.Stub {
        @Override
        public void hideToolbar(long widgetToken) {
            mRemoteRenderServiceConnector.hideToolbar(widgetToken);
        }

        @Override
        public void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback) {
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            synchronized (mLock) {
                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null) {
                    service.showToolbar(showInfo, callback);
                } else {
                    Slog.v(TAG, "showToolbar(): no service for " + userId);
        public void dismissToolbar(long widgetToken) {
            mRemoteRenderServiceConnector.dismissToolbar(Binder.getCallingUid(), widgetToken);
        }

    }

    private final class SelectionToolbarRenderServiceRemoteCallback extends
            ISelectionToolbarRenderServiceCallback.Stub {

        @Override
        public void transferTouch(IBinder source, IBinder target) {
            mInputManagerInternal.transferTouchGesture(source, target, false);
        }

        @Override
        public void hideToolbar(long widgetToken) {
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            synchronized (mLock) {
                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null) {
                    service.hideToolbar(widgetToken);
                } else {
                    Slog.v(TAG, "hideToolbar(): no service for " + userId);
        public void onPasteAction(int uid) {
            mClipboardManagerInternal.notifyUserAuthorizedClipAccess(uid);
        }
    }

    private static class RemoteRenderServiceConnector extends
            ServiceConnector.Impl<ISelectionToolbarRenderService> {
        private final IBinder mCallback;

        private RemoteRenderServiceConnector(Context context, ComponentName serviceName,
                int userId, IBinder callback) {
            super(context, new Intent(SelectionToolbarRenderService.SERVICE_INTERFACE)
                            .setComponent(serviceName), 0, userId,
                    ISelectionToolbarRenderService.Stub::asInterface);
            mCallback = callback;
        }

        @Override
        public void dismissToolbar(long widgetToken) {
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            synchronized (mLock) {
                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null) {
                    service.dismissToolbar(widgetToken);
                } else {
                    Slog.v(TAG, "dismissToolbar(): no service for " + userId);
        protected long getAutoDisconnectTimeoutMs() {
            return 0; // Never unbind
        }

        @Override
        protected void onServiceConnectionStatusChanged(
                @NonNull ISelectionToolbarRenderService service, boolean isConnected) {
            try {
                if (isConnected) {
                    service.onConnected(mCallback);
                }
            } catch (Exception e) {
                Slog.w(LOG_TAG, "Exception calling onConnected().", e);
            }
        }

        @Override
        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
        private void showToolbar(int callingUid, ShowInfo showInfo,
                ISelectionToolbarCallback callback) {
            run(s -> s.onShow(callingUid, showInfo, callback));
        }

            synchronized (mLock) {
                dumpLocked("", pw);
        private void hideToolbar(long widgetToken) {
            run(s -> s.onHide(widgetToken));
        }

        private void dismissToolbar(int callingUid, long widgetToken) {
            run(s -> s.onDismiss(callingUid, widgetToken));
        }
    }
}
+0 −172
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.selectiontoolbar;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.selectiontoolbar.ISelectionToolbarRenderServiceCallback;
import android.util.Slog;
import android.view.selectiontoolbar.ISelectionToolbarCallback;
import android.view.selectiontoolbar.ShowInfo;

import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.clipboard.ClipboardManagerInternal;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.input.InputManagerInternal;

final class SelectionToolbarManagerServiceImpl extends
        AbstractPerUserSystemService<SelectionToolbarManagerServiceImpl,
                SelectionToolbarManagerService> {

    private static final String TAG = "SelectionToolbarManagerServiceImpl";

    @GuardedBy("mLock")
    @Nullable
    private RemoteSelectionToolbarRenderService mRemoteService;

    InputManagerInternal mInputManagerInternal;
    private final SelectionToolbarRenderServiceRemoteCallback mRemoteServiceCallback =
            new SelectionToolbarRenderServiceRemoteCallback();

    SelectionToolbarManagerServiceImpl(@NonNull SelectionToolbarManagerService master,
            @NonNull Object lock, int userId) {
        super(master, lock, userId);
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
        updateRemoteServiceLocked();
    }

    @GuardedBy("mLock")
    @Override // from PerUserSystemService
    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
            throws PackageManager.NameNotFoundException {
        return getServiceInfoOrThrow(serviceComponent, mUserId);
    }

    @GuardedBy({"mLock"})
    @SuppressWarnings("GuardedBy") // mLock == super.mLock
    @Override // from PerUserSystemService
    protected boolean updateLocked(boolean disabled) {
        if (!Thread.holdsLock(super.mLock)) {
            throw new IllegalStateException("Thread does not hold super.mLock.");
        }
        final boolean enabledChanged = super.updateLocked(disabled);
        updateRemoteServiceLocked();
        return enabledChanged;
    }

    /**
     * Updates the reference to the remote service.
     */
    @GuardedBy("mLock")
    private void updateRemoteServiceLocked() {
        if (mRemoteService != null) {
            Slog.d(TAG, "updateRemoteService(): destroying old remote service");
            mRemoteService.unbind();
            mRemoteService = null;
        }
    }

    @GuardedBy("mLock")
    void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback) {
        if (!Thread.holdsLock(mLock)) {
            throw new IllegalStateException("Thread does not hold mLock.");
        }
        final RemoteSelectionToolbarRenderService remoteService = ensureRemoteServiceLocked();
        if (remoteService != null) {
            remoteService.onShow(Binder.getCallingUid(), showInfo, callback);
        }
    }

    @GuardedBy("mLock")
    void hideToolbar(long widgetToken) {
        if (!Thread.holdsLock(mLock)) {
            throw new IllegalStateException("Thread does not hold mLock.");
        }
        final RemoteSelectionToolbarRenderService remoteService = ensureRemoteServiceLocked();
        if (remoteService != null) {
            remoteService.onHide(widgetToken);
        }
    }

    @GuardedBy("mLock")
    void dismissToolbar(long widgetToken) {
        if (!Thread.holdsLock(mLock)) {
            throw new IllegalStateException("Thread does not hold mLock.");
        }
        final RemoteSelectionToolbarRenderService remoteService =
                ensureRemoteServiceLocked();
        if (remoteService != null) {
            remoteService.onDismiss(Binder.getCallingUid(), widgetToken);
        }
    }

    @GuardedBy("mLock")
    @NonNull
    private RemoteSelectionToolbarRenderService ensureRemoteServiceLocked() {
        if (mRemoteService == null) {
            final String serviceName = getComponentNameLocked();
            final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
            mRemoteService = new RemoteSelectionToolbarRenderService(getContext(), serviceComponent,
                    mUserId, mRemoteServiceCallback);
        }
        return mRemoteService;
    }

    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, @UserIdInt int userId)
            throws PackageManager.NameNotFoundException {
        int flags = PackageManager.GET_META_DATA;

        ServiceInfo si = null;
        try {
            si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
        } catch (RemoteException ignored) {
        }
        if (si == null) {
            throw new PackageManager.NameNotFoundException("Could not get serviceInfo for "
                    + comp.flattenToShortString());
        }
        return si;
    }

    private void transferTouchFocus(IBinder source, IBinder target) {
        mInputManagerInternal.transferTouchGesture(source, target, false);
    }

    private final class SelectionToolbarRenderServiceRemoteCallback extends
            ISelectionToolbarRenderServiceCallback.Stub {

        @Override
        public void transferTouch(IBinder source, IBinder target) {
            transferTouchFocus(source, target);
        }

        @Override
        public void onPasteAction(int uid) {
            LocalServices.getService(ClipboardManagerInternal.class)
                    .notifyUserAuthorizedClipAccess(uid);
        }
    }
}
+0 −62
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.selectiontoolbar;

import static android.permission.flags.Flags.useSystemSelectionToolbarInSysui;

import android.content.ComponentName;
import android.content.Context;
import android.service.selectiontoolbar.DefaultSelectionToolbarRenderService;

import com.android.internal.R;
import com.android.server.infra.ServiceNameResolver;

import java.io.PrintWriter;

final class SelectionToolbarServiceNameResolver implements ServiceNameResolver {
    private String mSystemSelectionToolbarServiceName;

    SelectionToolbarServiceNameResolver(Context context) {
        if (useSystemSelectionToolbarInSysui()) {
            mSystemSelectionToolbarServiceName = context.getResources()
                            .getString(R.string.config_systemUiSelectionToolbarRenderService);
        } else {
            mSystemSelectionToolbarServiceName = new ComponentName(
                    "android", DefaultSelectionToolbarRenderService.class.getName())
                    .flattenToString();
        }
    }

    private String getDefaultServiceName() {
        return mSystemSelectionToolbarServiceName;
    }

    @Override
    public String getDefaultServiceName(int userId) {
        return getDefaultServiceName();
    }

    @Override
    public void dumpShort(PrintWriter pw) {
        pw.print("service="); pw.print(getDefaultServiceName());
    }

    @Override
    public void dumpShort(PrintWriter pw, int userId) {
        pw.print("defaultService="); pw.print(getDefaultServiceName(userId));
    }
}