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

Commit aee0bb2d authored by Tom Macieszczak's avatar Tom Macieszczak
Browse files

Refactor TvRemoteService.

Test: manual - force-stopped the TvRemoteService.

Fix resource leak.
Remove Handlers from TvRemoteProvider and TvRemoteProviderProxy.
Remove provider list from TvRemoteService.

Change-Id: Iff83e93d6dac411c0e447bb9dfff7181f21ffee9
parent e33dcad8
Loading
Loading
Loading
Loading
+23 −103
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.content.ServiceConnection;
import android.media.tv.ITvRemoteProvider;
import android.media.tv.ITvRemoteServiceInput;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -49,7 +48,6 @@ final class TvRemoteProviderProxy implements ServiceConnection {
    private final ComponentName mComponentName;
    private final int mUserId;
    private final int mUid;
    private final Handler mHandler;

    /**
     * State guarded by mLock.
@@ -65,15 +63,14 @@ final class TvRemoteProviderProxy implements ServiceConnection {
    private boolean mRunning;
    private boolean mBound;
    private Connection mActiveConnection;
    private boolean mConnectionReady;

    public TvRemoteProviderProxy(Context context, ComponentName componentName, int userId,
                                 int uid) {
    TvRemoteProviderProxy(Context context, ProviderMethods provider,
                          ComponentName componentName, int userId, int uid) {
        mContext = context;
        mProviderMethods = provider;
        mComponentName = componentName;
        mUserId = userId;
        mUid = uid;
        mHandler = new Handler();
    }

    public void dump(PrintWriter pw, String prefix) {
@@ -82,11 +79,6 @@ final class TvRemoteProviderProxy implements ServiceConnection {
        pw.println(prefix + "  mRunning=" + mRunning);
        pw.println(prefix + "  mBound=" + mBound);
        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
    }

    public void setProviderSink(ProviderMethods provider) {
        mProviderMethods = provider;
    }

    public boolean hasComponentName(String packageName, String className) {
@@ -101,7 +93,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
            }

            mRunning = true;
            updateBinding();
            bind();
        }
    }

@@ -112,31 +104,19 @@ final class TvRemoteProviderProxy implements ServiceConnection {
            }

            mRunning = false;
            updateBinding();
            unbind();
        }
    }

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

    private void updateBinding() {
        if (shouldBind()) {
            bind();
        } else {
            unbind();
        }
    }

    private boolean shouldBind() {
        return mRunning;
    }

    private void bind() {
        if (!mBound) {
            if (DEBUG) {
@@ -208,47 +188,18 @@ final class TvRemoteProviderProxy implements ServiceConnection {
        disconnect();
    }


    private void onConnectionReady(Connection connection) {
        synchronized (mLock) {
            if (DEBUG) Slog.d(TAG, "onConnectionReady");
            if (mActiveConnection == connection) {
                if (DEBUG) Slog.d(TAG, "mConnectionReady = true");
                mConnectionReady = true;
            }
        }
    }

    private void onConnectionDied(Connection connection) {
        if (mActiveConnection == connection) {
            if (DEBUG) Slog.d(TAG, this + ": Service connection died");
            disconnect();
        }
    }

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

    // Provider helpers
    public void inputBridgeConnected(IBinder token) {
        synchronized (mLock) {
            if (DEBUG) Slog.d(TAG, this + ": inputBridgeConnected token: " + token);
            if (mConnectionReady) {
                mActiveConnection.onInputBridgeConnected(token);
            }
        }
    }

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

        void closeInputBridge(TvRemoteProviderProxy provider, IBinder token);
@@ -267,7 +218,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
        void sendPointerSync(TvRemoteProviderProxy provider, IBinder token);
    }

    private final class Connection implements IBinder.DeathRecipient {
    private final class Connection {
        private final ITvRemoteProvider mTvRemoteProvider;
        private final RemoteServiceInputProvider mServiceInputProvider;

@@ -279,24 +230,16 @@ final class TvRemoteProviderProxy implements ServiceConnection {
        public boolean register() {
            if (DEBUG) Slog.d(TAG, "Connection::register()");
            try {
                mTvRemoteProvider.asBinder().linkToDeath(this, 0);
                mTvRemoteProvider.setRemoteServiceInputSink(mServiceInputProvider);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        onConnectionReady(Connection.this);
                    }
                });
                return true;
            } catch (RemoteException ex) {
                binderDied();
            }
                dispose();
                return false;
            }
        }

        public void dispose() {
            if (DEBUG) Slog.d(TAG, "Connection::dispose()");
            mTvRemoteProvider.asBinder().unlinkToDeath(this, 0);
            mServiceInputProvider.dispose();
        }

@@ -310,16 +253,6 @@ final class TvRemoteProviderProxy implements ServiceConnection {
            }
        }

        @Override
        public void binderDied() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    onConnectionDied(Connection.this);
                }
            });
        }

        void openInputBridge(final IBinder token, final String name, final int width,
                             final int height, final int maxPointers) {
            synchronized (mLock) {
@@ -330,9 +263,9 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                            mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
                                    name, width, height, maxPointers);
                        if (mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
                                                             name, width, height, maxPointers)) {
                            onInputBridgeConnected(token);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
@@ -356,9 +289,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                        mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
@@ -381,9 +312,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                        mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
@@ -412,10 +341,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                            mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token,
                                    keyCode);
                        }
                        mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token, keyCode);
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
@@ -438,9 +364,7 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                        mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
@@ -463,10 +387,8 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                        mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token,
                                pointerId, x, y);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
@@ -489,10 +411,8 @@ final class TvRemoteProviderProxy implements ServiceConnection {
                    }
                    final long idToken = Binder.clearCallingIdentity();
                    try {
                        if (mProviderMethods != null) {
                        mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token,
                                pointerId);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(idToken);
                    }
+4 −12
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ final class TvRemoteProviderWatcher {
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);

    private final Context mContext;
    private final ProviderMethods mProvider;
    private final TvRemoteProviderProxy.ProviderMethods mProvider;
    private final Handler mHandler;
    private final PackageManager mPackageManager;
    private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>();
@@ -54,10 +54,10 @@ final class TvRemoteProviderWatcher {

    private boolean mRunning;

    public TvRemoteProviderWatcher(Context context, ProviderMethods provider, Handler handler) {
    TvRemoteProviderWatcher(Context context, TvRemoteProviderProxy.ProviderMethods provider) {
        mContext = context;
        mProvider = provider;
        mHandler = handler;
        mHandler = new Handler(true);
        mUserId = UserHandle.myUserId();
        mPackageManager = context.getPackageManager();
        mUnbundledServicePackage = context.getString(
@@ -116,12 +116,11 @@ final class TvRemoteProviderWatcher {
                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
                if (sourceIndex < 0) {
                    TvRemoteProviderProxy providerProxy =
                            new TvRemoteProviderProxy(mContext,
                            new TvRemoteProviderProxy(mContext, mProvider,
                                    new ComponentName(serviceInfo.packageName, serviceInfo.name),
                                    mUserId, serviceInfo.applicationInfo.uid);
                    providerProxy.start();
                    mProviderProxies.add(targetIndex++, providerProxy);
                    mProvider.addProvider(providerProxy);
                } else if (sourceIndex >= targetIndex) {
                    TvRemoteProviderProxy provider = mProviderProxies.get(sourceIndex);
                    provider.start(); // restart the provider if needed
@@ -135,7 +134,6 @@ final class TvRemoteProviderWatcher {
        if (targetIndex < mProviderProxies.size()) {
            for (int i = mProviderProxies.size() - 1; i >= targetIndex; i--) {
                TvRemoteProviderProxy providerProxy = mProviderProxies.get(i);
                mProvider.removeProvider(providerProxy);
                mProviderProxies.remove(providerProxy);
                providerProxy.stop();
            }
@@ -212,10 +210,4 @@ final class TvRemoteProviderWatcher {
            scanPackages();
        }
    };

    public interface ProviderMethods {
        void addProvider(TvRemoteProviderProxy providerProxy);

        void removeProvider(TvRemoteProviderProxy providerProxy);
    }
}
+18 −111
Original line number Diff line number Diff line
@@ -17,11 +17,8 @@
package com.android.server.tv;

import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Slog;

@@ -29,7 +26,6 @@ import com.android.server.SystemService;
import com.android.server.Watchdog;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

/**
@@ -44,9 +40,8 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
    private static final boolean DEBUG = false;
    private static final boolean DEBUG_KEYS = false;

    private final TvRemoteProviderWatcher mWatcher;
    private Map<IBinder, UinputBridge> mBridgeMap = new ArrayMap();
    private Map<IBinder, TvRemoteProviderProxy> mProviderMap = new ArrayMap();
    private ArrayList<TvRemoteProviderProxy> mProviderList = new ArrayList<>();

    /**
     * State guarded by mLock.
@@ -60,11 +55,10 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
     */
    private final Object mLock = new Object();

    public final UserHandler mHandler;

    public TvRemoteService(Context context) {
        super(context);
        mHandler = new UserHandler(new UserProvider(TvRemoteService.this), context);
        mWatcher = new TvRemoteProviderWatcher(context,
                                               new UserProvider(TvRemoteService.this));
        Watchdog.getInstance().addMonitor(this);
    }

@@ -80,19 +74,15 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {

    @Override
    public void onBootPhase(int phase) {
        // All lifecycle methods are called from the system server's main looper thread.
        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
            if (DEBUG) Slog.d(TAG, "PHASE_THIRD_PARTY_APPS_CAN_START");
            mHandler.sendEmptyMessage(UserHandler.MSG_START);
        }
    }

    //Outgoing calls.
    private void informInputBridgeConnected(IBinder token) {
        mHandler.obtainMessage(UserHandler.MSG_INPUT_BRIDGE_CONNECTED, 0, 0, token).sendToTarget();
            mWatcher.start(); // Also schedules the start of all providers.
        }
    }

    // Incoming calls.
    private void openInputBridgeInternalLocked(TvRemoteProviderProxy provider, final IBinder token,
    private boolean openInputBridgeInternalLocked(final IBinder token,
                                                  String name, int width, int height,
                                                  int maxPointers) {
        if (DEBUG) {
@@ -104,15 +94,11 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
            //Create a new bridge, if one does not exist already
            if (mBridgeMap.containsKey(token)) {
                if (DEBUG) Slog.d(TAG, "RemoteBridge already exists");
                // Respond back with success.
                informInputBridgeConnected(token);
                return;
                return true;
            }

            UinputBridge inputBridge = new UinputBridge(token, name, width, height, maxPointers);

            mBridgeMap.put(token, inputBridge);
            mProviderMap.put(token, provider);

            try {
                token.linkToDeath(new IBinder.DeathRecipient() {
@@ -126,15 +112,13 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
            } catch (RemoteException e) {
                if (DEBUG) Slog.d(TAG, "Token is already dead");
                closeInputBridgeInternalLocked(token);
                return;
                return false;
            }

            // Respond back with success.
            informInputBridgeConnected(token);

        } catch (IOException ioe) {
            Slog.e(TAG, "Cannot create device for " + name);
            return false;
        }
        return true;
    }

    private void closeInputBridgeInternalLocked(IBinder token) {
@@ -149,7 +133,6 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
        }

        mBridgeMap.remove(token);
        mProviderMap.remove(token);
    }

    private void clearInputBridgeInternalLocked(IBinder token) {
@@ -220,47 +203,7 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
        }
    }

    private final class UserHandler extends Handler {

        public static final int MSG_START = 1;
        public static final int MSG_INPUT_BRIDGE_CONNECTED = 2;

        private final TvRemoteProviderWatcher mWatcher;
        private boolean mRunning;

        public UserHandler(UserProvider provider, Context context) {
            super(Looper.getMainLooper(), null, true);
            mWatcher = new TvRemoteProviderWatcher(context, provider, this);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_START: {
                    start();
                    break;
                }
                case MSG_INPUT_BRIDGE_CONNECTED: {
                    IBinder token = (IBinder) msg.obj;
                    TvRemoteProviderProxy provider = mProviderMap.get(token);
                    if (provider != null) {
                        provider.inputBridgeConnected(token);
                    }
                    break;
                }
            }
        }

        private void start() {
            if (!mRunning) {
                mRunning = true;
                mWatcher.start(); // also starts all providers
            }
        }
    }

    private final class UserProvider implements TvRemoteProviderWatcher.ProviderMethods,
            TvRemoteProviderProxy.ProviderMethods {
    private final class UserProvider implements TvRemoteProviderProxy.ProviderMethods {

        private final TvRemoteService mService;

@@ -269,7 +212,7 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
        }

        @Override
        public void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
        public boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
                                       int width, int height, int maxPointers) {
            if (DEBUG) {
                Slog.d(TAG, "openInputBridge(), token: " + token +
@@ -278,10 +221,8 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
            }

            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.openInputBridgeInternalLocked(provider, token, name, width, height,
                            maxPointers);
                }
                return mService.openInputBridgeInternalLocked(token, name, width,
                               height, maxPointers);
            }
        }

@@ -289,21 +230,17 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
        public void closeInputBridge(TvRemoteProviderProxy provider, IBinder token) {
            if (DEBUG) Slog.d(TAG, "closeInputBridge(), token: " + token);
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.closeInputBridgeInternalLocked(token);
            }
        }
        }

        @Override
        public void clearInputBridge(TvRemoteProviderProxy provider, IBinder token) {
            if (DEBUG) Slog.d(TAG, "clearInputBridge(), token: " + token);
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.clearInputBridgeInternalLocked(token);
            }
        }
        }

        @Override
        public void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode) {
@@ -311,11 +248,9 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
                Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode);
            }
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.sendKeyDownInternalLocked(token, keyCode);
            }
        }
        }

        @Override
        public void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode) {
@@ -323,11 +258,9 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
                Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode);
            }
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.sendKeyUpInternalLocked(token, keyCode);
            }
        }
        }

        @Override
        public void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId,
@@ -336,11 +269,9 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
                Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + pointerId);
            }
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.sendPointerDownInternalLocked(token, pointerId, x, y);
            }
        }
        }

        @Override
        public void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId) {
@@ -348,40 +279,16 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor {
                Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId);
            }
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.sendPointerUpInternalLocked(token, pointerId);
            }
        }
        }

        @Override
        public void sendPointerSync(TvRemoteProviderProxy provider, IBinder token) {
            if (DEBUG_KEYS) Slog.d(TAG, "sendPointerSync(), token: " + token);
            synchronized (mLock) {
                if (mProviderList.contains(provider)) {
                    mService.sendPointerSyncInternalLocked(token);
            }
        }
    }

        @Override
        public void addProvider(TvRemoteProviderProxy provider) {
            if (DEBUG) Slog.d(TAG, "addProvider " + provider);
            synchronized (mLock) {
                provider.setProviderSink(this);
                mProviderList.add(provider);
                Slog.d(TAG, "provider: " + provider.toString());
            }
        }

        @Override
        public void removeProvider(TvRemoteProviderProxy provider) {
            if (DEBUG) Slog.d(TAG, "removeProvider " + provider);
            synchronized (mLock) {
                if (mProviderList.remove(provider) == false) {
                    Slog.e(TAG, "Unknown provider " + provider);
                }
            }
        }
    }
}