TvRemoteProviderWatcher.java revision b5b86c11008422ac4bf5af5fed736f04ebbaa858
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 17package com.android.server.tv; 18 19import android.Manifest; 20import android.content.BroadcastReceiver; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.content.pm.ServiceInfo; 28import android.os.Handler; 29import android.os.UserHandle; 30import android.util.Log; 31import android.util.Slog; 32 33import java.util.ArrayList; 34import 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 */ 42final 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