Home | History | Annotate | Download | only in tv
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.tv;
     18 
     19 import android.Manifest;
     20 import android.content.BroadcastReceiver;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.pm.PackageManager;
     26 import android.content.pm.ResolveInfo;
     27 import android.content.pm.ServiceInfo;
     28 import android.os.Handler;
     29 import android.os.UserHandle;
     30 import android.util.Log;
     31 import android.util.Slog;
     32 
     33 import java.util.ArrayList;
     34 import java.util.Collections;
     35 
     36 /**
     37  * Watches for emote provider services to be installed.
     38  * Adds a provider for each registered service.
     39  *
     40  * @see TvRemoteProviderProxy
     41  */
     42 final class TvRemoteProviderWatcher {
     43 
     44     private static final String TAG = "TvRemoteProvWatcher";  // max. 23 chars
     45     private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
     46 
     47     private final Context mContext;
     48     private final ProviderMethods mProvider;
     49     private final Handler mHandler;
     50     private final PackageManager mPackageManager;
     51     private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>();
     52     private final int mUserId;
     53     private final String mUnbundledServicePackage;
     54 
     55     private boolean mRunning;
     56 
     57     public TvRemoteProviderWatcher(Context context, ProviderMethods provider, Handler handler) {
     58         mContext = context;
     59         mProvider = provider;
     60         mHandler = handler;
     61         mUserId = UserHandle.myUserId();
     62         mPackageManager = context.getPackageManager();
     63         mUnbundledServicePackage = context.getString(
     64                 com.android.internal.R.string.config_tvRemoteServicePackage);
     65     }
     66 
     67     public void start() {
     68         if (DEBUG) Slog.d(TAG, "start()");
     69         if (!mRunning) {
     70             mRunning = true;
     71 
     72             IntentFilter filter = new IntentFilter();
     73             filter.addAction(Intent.ACTION_PACKAGE_ADDED);
     74             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
     75             filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
     76             filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
     77             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
     78             filter.addDataScheme("package");
     79             mContext.registerReceiverAsUser(mScanPackagesReceiver,
     80                     new UserHandle(mUserId), filter, null, mHandler);
     81 
     82             // Scan packages.
     83             // Also has the side-effect of restarting providers if needed.
     84             mHandler.post(mScanPackagesRunnable);
     85         }
     86     }
     87 
     88     public void stop() {
     89         if (mRunning) {
     90             mRunning = false;
     91 
     92             mContext.unregisterReceiver(mScanPackagesReceiver);
     93             mHandler.removeCallbacks(mScanPackagesRunnable);
     94 
     95             // Stop all providers.
     96             for (int i = mProviderProxies.size() - 1; i >= 0; i--) {
     97                 mProviderProxies.get(i).stop();
     98             }
     99         }
    100     }
    101 
    102     private void scanPackages() {
    103         if (!mRunning) {
    104             return;
    105         }
    106 
    107         if (DEBUG) Log.d(TAG, "scanPackages()");
    108         // Add providers for all new services.
    109         // Reorder the list so that providers left at the end will be the ones to remove.
    110         int targetIndex = 0;
    111         Intent intent = new Intent(TvRemoteProviderProxy.SERVICE_INTERFACE);
    112         for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
    113                 intent, 0, mUserId)) {
    114             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    115             if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) {
    116                 int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
    117                 if (sourceIndex < 0) {
    118                     TvRemoteProviderProxy providerProxy =
    119                             new TvRemoteProviderProxy(mContext,
    120                                     new ComponentName(serviceInfo.packageName, serviceInfo.name),
    121                                     mUserId, serviceInfo.applicationInfo.uid);
    122                     providerProxy.start();
    123                     mProviderProxies.add(targetIndex++, providerProxy);
    124                     mProvider.addProvider(providerProxy);
    125                 } else if (sourceIndex >= targetIndex) {
    126                     TvRemoteProviderProxy provider = mProviderProxies.get(sourceIndex);
    127                     provider.start(); // restart the provider if needed
    128                     provider.rebindIfDisconnected();
    129                     Collections.swap(mProviderProxies, sourceIndex, targetIndex++);
    130                 }
    131             }
    132         }
    133         if (DEBUG) Log.d(TAG, "scanPackages() targetIndex " + targetIndex);
    134         // Remove providers for missing services.
    135         if (targetIndex < mProviderProxies.size()) {
    136             for (int i = mProviderProxies.size() - 1; i >= targetIndex; i--) {
    137                 TvRemoteProviderProxy providerProxy = mProviderProxies.get(i);
    138                 mProvider.removeProvider(providerProxy);
    139                 mProviderProxies.remove(providerProxy);
    140                 providerProxy.stop();
    141             }
    142         }
    143     }
    144 
    145     private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
    146         if (serviceInfo.permission == null || !serviceInfo.permission.equals(
    147                 Manifest.permission.BIND_TV_REMOTE_SERVICE)) {
    148             // If the service does not require this permission then any app could
    149             // potentially bind to it and cause the atv remote provider service to
    150             // misbehave.  So we only want to trust providers that require the
    151             // correct permissions.
    152             Slog.w(TAG, "Ignoring atv remote provider service because it did not "
    153                     + "require the BIND_TV_REMOTE_SERVICE permission in its manifest: "
    154                     + serviceInfo.packageName + "/" + serviceInfo.name);
    155             return false;
    156         }
    157 
    158         // Check if package name is white-listed here.
    159         if (!serviceInfo.packageName.equals(mUnbundledServicePackage)) {
    160             Slog.w(TAG, "Ignoring atv remote provider service because the package has not "
    161                     + "been set and/or whitelisted: "
    162                     + serviceInfo.packageName + "/" + serviceInfo.name);
    163             return false;
    164         }
    165 
    166         if (!hasNecessaryPermissions(serviceInfo.packageName)) {
    167             // If the service does not have permission to be
    168             // a virtual tv remote controller, do not trust it.
    169             Slog.w(TAG, "Ignoring atv remote provider service because its package does not "
    170                     + "have TV_VIRTUAL_REMOTE_CONTROLLER permission: " + serviceInfo.packageName);
    171             return false;
    172         }
    173 
    174         // Looks good.
    175         return true;
    176     }
    177 
    178     // Returns true only if these permissions are present in calling package.
    179     // Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER : virtual remote controller on TV
    180     private boolean hasNecessaryPermissions(String packageName) {
    181         if ((mPackageManager.checkPermission(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER,
    182                         packageName) == PackageManager.PERMISSION_GRANTED)) {
    183             return true;
    184         }
    185         return false;
    186     }
    187 
    188     private int findProvider(String packageName, String className) {
    189         int count = mProviderProxies.size();
    190         for (int i = 0; i < count; i++) {
    191             TvRemoteProviderProxy provider = mProviderProxies.get(i);
    192             if (provider.hasComponentName(packageName, className)) {
    193                 return i;
    194             }
    195         }
    196         return -1;
    197     }
    198 
    199     private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
    200         @Override
    201         public void onReceive(Context context, Intent intent) {
    202             if (DEBUG) {
    203                 Slog.d(TAG, "Received package manager broadcast: " + intent);
    204             }
    205             mHandler.post(mScanPackagesRunnable);
    206         }
    207     };
    208 
    209     private final Runnable mScanPackagesRunnable = new Runnable() {
    210         @Override
    211         public void run() {
    212             scanPackages();
    213         }
    214     };
    215 
    216     public interface ProviderMethods {
    217         void addProvider(TvRemoteProviderProxy providerProxy);
    218 
    219         void removeProvider(TvRemoteProviderProxy providerProxy);
    220     }
    221 }
    222