169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/* 269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Copyright (C) 2013 The Android Open Source Project 369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * you may not use this file except in compliance with the License. 669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * You may obtain a copy of the License at 769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 1069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Unless required by applicable law or agreed to in writing, software 1169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 1269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * See the License for the specific language governing permissions and 1469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * limitations under the License. 1569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 1669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownpackage com.android.server.media; 1869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 19e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brownimport android.Manifest; 2069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.BroadcastReceiver; 2169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.ComponentName; 2269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Context; 2369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Intent; 2469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.IntentFilter; 2569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.pm.PackageManager; 2669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.pm.ResolveInfo; 2769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.pm.ServiceInfo; 2869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState; 2969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Handler; 3069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.UserHandle; 3169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Log; 3269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Slog; 3369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 3469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.PrintWriter; 3569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.ArrayList; 3669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.Collections; 3769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 3869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/** 3969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Watches for remote display provider services to be installed. 4069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Adds a provider to the media router for each registered service. 4169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 4269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * @see RemoteDisplayProviderProxy 4369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 4469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownpublic final class RemoteDisplayProviderWatcher { 4569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars 4669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 4769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 4869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Context mContext; 4969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Callback mCallback; 5069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Handler mHandler; 5169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final int mUserId; 5269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final PackageManager mPackageManager; 5369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 5469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<RemoteDisplayProviderProxy> mProviders = 5569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayList<RemoteDisplayProviderProxy>(); 5669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean mRunning; 5769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 5869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RemoteDisplayProviderWatcher(Context context, 5969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Callback callback, Handler handler, int userId) { 6069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mContext = context; 6169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCallback = callback; 6269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler = handler; 6369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserId = userId; 6469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mPackageManager = context.getPackageManager(); 6569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 6669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 6769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 6869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + "Watcher"); 6969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + " mUserId=" + mUserId); 7069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + " mRunning=" + mRunning); 7169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + " mProviders.size()=" + mProviders.size()); 7269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 7369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 7469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void start() { 7569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mRunning) { 7669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = true; 7769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 7869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown IntentFilter filter = new IntentFilter(); 7969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_ADDED); 8069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 8169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 8269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 8369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 8469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown filter.addDataScheme("package"); 8569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mContext.registerReceiverAsUser(mScanPackagesReceiver, 8669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new UserHandle(mUserId), filter, null, mHandler); 8769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 8869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Scan packages. 8969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Also has the side-effect of restarting providers if needed. 9069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.post(mScanPackagesRunnable); 9169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 9269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 9369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void stop() { 9569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mRunning) { 9669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = false; 9769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mContext.unregisterReceiver(mScanPackagesReceiver); 9969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.removeCallbacks(mScanPackagesRunnable); 10069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 10169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Stop all providers. 10269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = mProviders.size() - 1; i >= 0; i--) { 10369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviders.get(i).stop(); 10469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 10569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 10669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 10769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 10869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void scanPackages() { 10969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mRunning) { 11069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 11169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 11269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 11369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add providers for all new services. 11469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Reorder the list so that providers left at the end will be the ones to remove. 11569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int targetIndex = 0; 11669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Intent intent = new Intent(RemoteDisplayState.SERVICE_INTERFACE); 11769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser( 11869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown intent, 0, mUserId)) { 11969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ServiceInfo serviceInfo = resolveInfo.serviceInfo; 120e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) { 12169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); 12269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sourceIndex < 0) { 12369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy provider = 12469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new RemoteDisplayProviderProxy(mContext, 12569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ComponentName(serviceInfo.packageName, serviceInfo.name), 12669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserId); 12769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.start(); 12869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviders.add(targetIndex++, provider); 12969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCallback.addProvider(provider); 13069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (sourceIndex >= targetIndex) { 13169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy provider = mProviders.get(sourceIndex); 13269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.start(); // restart the provider if needed 13369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.rebindIfDisconnected(); 13469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Collections.swap(mProviders, sourceIndex, targetIndex++); 13569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 13669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 13769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 13869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 13969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Remove providers for missing services. 14069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (targetIndex < mProviders.size()) { 14169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = mProviders.size() - 1; i >= targetIndex; i--) { 14269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy provider = mProviders.get(i); 14369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCallback.removeProvider(provider); 14469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviders.remove(provider); 14569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.stop(); 14669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 150e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown private boolean verifyServiceTrusted(ServiceInfo serviceInfo) { 151e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown if (serviceInfo.permission == null || !serviceInfo.permission.equals( 152e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown Manifest.permission.BIND_REMOTE_DISPLAY)) { 153e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // If the service does not require this permission then any app could 154e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // potentially bind to it and cause the remote display service to 155e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // misbehave. So we only want to trust providers that require the 156e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // correct permissions. 157e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown Slog.w(TAG, "Ignoring remote display provider service because it did not " 158e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown + "require the BIND_REMOTE_DISPLAY permission in its manifest: " 159e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown + serviceInfo.packageName + "/" + serviceInfo.name); 160e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return false; 161e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 162e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown if (!hasCaptureVideoPermission(serviceInfo.packageName)) { 163e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // If the service does not have permission to capture video then it 164e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // isn't going to be terribly useful as a remote display, is it? 165e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // Kind of makes you wonder what it's doing there in the first place. 166e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown Slog.w(TAG, "Ignoring remote display provider service because it does not " 167e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT " 168e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown + "permission: " + serviceInfo.packageName + "/" + serviceInfo.name); 169e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return false; 170e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 171e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown // Looks good. 172e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return true; 173e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 174e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown 175e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown private boolean hasCaptureVideoPermission(String packageName) { 176e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT, 177e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown packageName) == PackageManager.PERMISSION_GRANTED) { 178e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return true; 179e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 180e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT, 181e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown packageName) == PackageManager.PERMISSION_GRANTED) { 182e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return true; 183e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 184e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown return false; 185e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown } 186e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown 18769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int findProvider(String packageName, String className) { 18869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int count = mProviders.size(); 18969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 19069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy provider = mProviders.get(i); 19169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (provider.hasComponentName(packageName, className)) { 19269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return i; 19369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return -1; 19669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 19869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { 19969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onReceive(Context context, Intent intent) { 20169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 20269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, "Received package manager broadcast: " + intent); 20369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 20469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scanPackages(); 20569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 20669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }; 20769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 20869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Runnable mScanPackagesRunnable = new Runnable() { 20969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 21069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 21169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scanPackages(); 21269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }; 21469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 21569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public interface Callback { 21669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void addProvider(RemoteDisplayProviderProxy provider); 21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void removeProvider(RemoteDisplayProviderProxy provider); 21869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown} 220