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

Commit 86e2a20d authored by Tom Macieszczak's avatar Tom Macieszczak Committed by Android (Google) Code Review
Browse files

Merge "Additional refactoring of TvRemoteService"

parents a219bddf 34ba4b1a
Loading
Loading
Loading
Loading
+25 −406
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.tv.ITvRemoteProvider;
import android.media.tv.ITvRemoteServiceInput;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -30,44 +28,33 @@ import android.util.Log;
import android.util.Slog;

import java.io.PrintWriter;
import java.lang.ref.WeakReference;

/**
 * Maintains a connection to a tv remote provider service.
 */
final class TvRemoteProviderProxy implements ServiceConnection {
    private static final String TAG = "TvRemoteProvProxy";  // max. 23 chars
    private static final String TAG = "TvRemoteProviderProxy";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
    private static final boolean DEBUG_KEY = false;


    // This should match TvRemoteProvider.ACTION_TV_REMOTE_PROVIDER
    protected static final String SERVICE_INTERFACE =
            "com.android.media.tv.remoteprovider.TvRemoteProvider";
    private final Context mContext;
    private final Object mLock;
    private final ComponentName mComponentName;
    private final int mUserId;
    private final int mUid;

    /**
     * State guarded by mLock.
     *  This is the first lock in sequence for an incoming call.
     *  The second lock is always {@link TvRemoteService#mLock}
     *
     *  There are currently no methods that break this sequence.
     */
    private final Object mLock = new Object();

    private ProviderMethods mProviderMethods;
    // Connection state
    // State changes happen only in the main thread, hence no lock is needed
    private boolean mRunning;
    private boolean mBound;
    private Connection mActiveConnection;
    private boolean mConnected;

    TvRemoteProviderProxy(Context context, ProviderMethods provider,
    TvRemoteProviderProxy(Context context, Object lock,
                          ComponentName componentName, int userId, int uid) {
        mContext = context;
        mProviderMethods = provider;
        mLock = lock;
        mComponentName = componentName;
        mUserId = userId;
        mUid = uid;
@@ -78,7 +65,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
        pw.println(prefix + "  mUserId=" + mUserId);
        pw.println(prefix + "  mRunning=" + mRunning);
        pw.println(prefix + "  mBound=" + mBound);
        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
        pw.println(prefix + "  mConnected=" + mConnected);
    }

    public boolean hasComponentName(String packageName, String className) {
@@ -109,13 +96,11 @@ final class TvRemoteProviderProxy implements ServiceConnection {
    }

    public void rebindIfDisconnected() {
        synchronized (mLock) {
            if (mActiveConnection == null && mRunning) {
        if (mRunning && !mConnected) {
            unbind();
            bind();
        }
    }
    }

    private void bind() {
        if (!mBound) {
@@ -129,7 +114,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                mBound = mContext.bindServiceAsUser(service, this,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                        new UserHandle(mUserId));
                if (!mBound && DEBUG) {
                if (DEBUG && !mBound) {
                    Slog.d(TAG, this + ": Bind failed");
                }
            } catch (SecurityException ex) {
@@ -147,7 +132,6 @@ final class TvRemoteProviderProxy implements ServiceConnection {
            }

            mBound = false;
            disconnect();
            mContext.unbindService(this);
        }
    }
@@ -158,392 +142,27 @@ final class TvRemoteProviderProxy implements ServiceConnection {
            Slog.d(TAG, this + ": onServiceConnected()");
        }

        if (mBound) {
            disconnect();

            ITvRemoteProvider provider = ITvRemoteProvider.Stub.asInterface(service);
            if (provider != null) {
                Connection connection = new Connection(provider);
                if (connection.register()) {
                    synchronized (mLock) {
                        mActiveConnection = connection;
                    }
                    if (DEBUG) {
                        Slog.d(TAG, this + ": Connected successfully.");
                    }
                } else {
                    if (DEBUG) {
                        Slog.d(TAG, this + ": Registration failed");
                    }
                }
            } else {
                Slog.e(TAG, this + ": Service returned invalid remote-control provider binder");
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        if (DEBUG) Slog.d(TAG, this + ": Service disconnected");
        disconnect();
    }

    private void disconnect() {
        synchronized (mLock) {
            if (mActiveConnection != null) {
                mActiveConnection.dispose();
                mActiveConnection = null;
            }
        }
    }

    interface ProviderMethods {
        // InputBridge
        boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
                                int width, int height, int maxPointers);

        void closeInputBridge(TvRemoteProviderProxy provider, IBinder token);

        void clearInputBridge(TvRemoteProviderProxy provider, IBinder token);

        void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode);

        void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode);

        void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId, int x,
                             int y);

        void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId);

        void sendPointerSync(TvRemoteProviderProxy provider, IBinder token);
    }

    private final class Connection {
        private final ITvRemoteProvider mTvRemoteProvider;
        private final RemoteServiceInputProvider mServiceInputProvider;

        public Connection(ITvRemoteProvider provider) {
            mTvRemoteProvider = provider;
            mServiceInputProvider = new RemoteServiceInputProvider(this);
        }

        public boolean register() {
            if (DEBUG) Slog.d(TAG, "Connection::register()");
            try {
                mTvRemoteProvider.setRemoteServiceInputSink(mServiceInputProvider);
                return true;
            } catch (RemoteException ex) {
                dispose();
                return false;
            }
        }

        public void dispose() {
            if (DEBUG) Slog.d(TAG, "Connection::dispose()");
            mServiceInputProvider.dispose();
        }


        public void onInputBridgeConnected(IBinder token) {
            if (DEBUG) Slog.d(TAG, this + ": onInputBridgeConnected");
            try {
                mTvRemoteProvider.onInputBridgeConnected(token);
            } catch (RemoteException ex) {
                Slog.e(TAG, "Failed to deliver onInputBridgeConnected. ", ex);
            }
        }

        void openInputBridge(final IBinder token, final String name, final int width,
                             final int height, final int maxPointers) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG) {
                        Slog.d(TAG, this + ": openInputBridge," +
                                " token=" + token + ", name=" + name);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
                                                             name, width, height, maxPointers)) {
                            onInputBridgeConnected(token);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "openInputBridge, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        }

        void closeInputBridge(final IBinder token) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG) {
                        Slog.d(TAG, this + ": closeInputBridge," +
                                " token=" + token);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "closeInputBridge, Invalid connection or incorrect uid: " +
                                        Binder.getCallingUid());
                    }
                }
            }
        }

        void clearInputBridge(final IBinder token) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG) {
                        Slog.d(TAG, this + ": clearInputBridge," +
                                " token=" + token);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "clearInputBridge, Invalid connection or incorrect uid: " +
                                        Binder.getCallingUid());
                    }
                }
            }
        }

        void sendTimestamp(final IBinder token, final long timestamp) {
            if (DEBUG) {
                Slog.e(TAG, "sendTimestamp is deprecated, please remove all usages of this API.");
            }
        }

        void sendKeyDown(final IBinder token, final int keyCode) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG_KEY) {
                        Slog.d(TAG, this + ": sendKeyDown," +
                                " token=" + token + ", keyCode=" + keyCode);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token, keyCode);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "sendKeyDown, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        }
        mConnected = true;

        void sendKeyUp(final IBinder token, final int keyCode) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG_KEY) {
                        Slog.d(TAG, this + ": sendKeyUp," +
                                " token=" + token + ", keyCode=" + keyCode);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "sendKeyUp, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        final ITvRemoteProvider provider = ITvRemoteProvider.Stub.asInterface(service);
        if (provider == null) {
            Slog.e(TAG, this + ": Invalid binder");
            return;
        }

        void sendPointerDown(final IBinder token, final int pointerId, final int x, final int y) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG_KEY) {
                        Slog.d(TAG, this + ": sendPointerDown," +
                                " token=" + token + ", pointerId=" + pointerId);
                    }
                    final long idToken = Binder.clearCallingIdentity();
        try {
                        mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token,
                                pointerId, x, y);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "sendPointerDown, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        }

        void sendPointerUp(final IBinder token, final int pointerId) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG_KEY) {
                        Slog.d(TAG, this + ": sendPointerUp," +
                                " token=" + token + ", pointerId=" + pointerId);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token,
                                pointerId);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "sendPointerUp, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        }

        void sendPointerSync(final IBinder token) {
            synchronized (mLock) {
                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
                    if (DEBUG_KEY) {
                        Slog.d(TAG, this + ": sendPointerSync," +
                                " token=" + token);
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                            mProviderMethods.sendPointerSync(TvRemoteProviderProxy.this, token);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
                } else {
                    if (DEBUG) {
                        Slog.w(TAG,
                                "sendPointerSync, Invalid connection or incorrect uid: " + Binder
                                        .getCallingUid());
                    }
                }
            }
        }
    }

    /**
     * Receives events from the connected provider.
     * <p>
     * This inner class is static and only retains a weak reference to the connection
     * to prevent the client from being leaked in case the service is holding an
     * active reference to the client's callback.
     * </p>
     */
    private static final class RemoteServiceInputProvider extends ITvRemoteServiceInput.Stub {
        private final WeakReference<Connection> mConnectionRef;

        public RemoteServiceInputProvider(Connection connection) {
            mConnectionRef = new WeakReference<Connection>(connection);
        }

        public void dispose() {
            // Terminate the connection.
            mConnectionRef.clear();
        }

        @Override
        public void openInputBridge(IBinder token, String name, int width,
                                    int height, int maxPointers) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.openInputBridge(token, name, width, height, maxPointers);
            provider.setRemoteServiceInputSink(new TvRemoteServiceInput(mLock, provider));
        } catch (RemoteException e) {
            Slog.e(TAG, this + ": Failed remote call to setRemoteServiceInputSink");
        }
    }

    @Override
        public void closeInputBridge(IBinder token) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.closeInputBridge(token);
            }
        }

        @Override
        public void clearInputBridge(IBinder token) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.clearInputBridge(token);
            }
        }

        @Override
        public void sendTimestamp(IBinder token, long timestamp) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendTimestamp(token, timestamp);
            }
        }

        @Override
        public void sendKeyDown(IBinder token, int keyCode) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendKeyDown(token, keyCode);
            }
        }

        @Override
        public void sendKeyUp(IBinder token, int keyCode) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendKeyUp(token, keyCode);
            }
        }

        @Override
        public void sendPointerDown(IBinder token, int pointerId, int x, int y)
                throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendPointerDown(token, pointerId, x, y);
            }
        }

        @Override
        public void sendPointerUp(IBinder token, int pointerId) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendPointerUp(token, pointerId);
            }
        }
    public void onServiceDisconnected(ComponentName name) {
        mConnected = false;

        @Override
        public void sendPointerSync(IBinder token) throws RemoteException {
            Connection connection = mConnectionRef.get();
            if (connection != null) {
                connection.sendPointerSync(token);
            }
        if (DEBUG) {
            Slog.d(TAG, this + ": onServiceDisconnected()");
        }
    }
}
+5 −5
Original line number Diff line number Diff line
@@ -41,27 +41,27 @@ import java.util.Collections;
 */
final class TvRemoteProviderWatcher {

    private static final String TAG = "TvRemoteProvWatcher";  // max. 23 chars
    private static final String TAG = "TvRemoteProviderWatcher";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);

    private final Context mContext;
    private final TvRemoteProviderProxy.ProviderMethods mProvider;
    private final Handler mHandler;
    private final PackageManager mPackageManager;
    private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>();
    private final int mUserId;
    private final String mUnbundledServicePackage;
    private final Object mLock;

    private boolean mRunning;

    TvRemoteProviderWatcher(Context context, TvRemoteProviderProxy.ProviderMethods provider) {
    TvRemoteProviderWatcher(Context context, Object lock) {
        mContext = context;
        mProvider = provider;
        mHandler = new Handler(true);
        mUserId = UserHandle.myUserId();
        mPackageManager = context.getPackageManager();
        mUnbundledServicePackage = context.getString(
                com.android.internal.R.string.config_tvRemoteServicePackage);
        mLock = lock;
    }

    public void start() {
@@ -116,7 +116,7 @@ final class TvRemoteProviderWatcher {
                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
                if (sourceIndex < 0) {
                    TvRemoteProviderProxy providerProxy =
                            new TvRemoteProviderProxy(mContext, mProvider,
                            new TvRemoteProviderProxy(mContext, mLock,
                                    new ComponentName(serviceInfo.packageName, serviceInfo.name),
                                    mUserId, serviceInfo.applicationInfo.uid);
                    providerProxy.start();
+4 −230

File changed.

Preview size limit exceeded, changes collapsed.

+244 −0

File added.

Preview size limit exceeded, changes collapsed.