16a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson/* 26a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Copyright (C) 2014 The Android Open Source Project 36a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * 46a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Licensed under the Apache License, Version 2.0 (the "License"); 56a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * you may not use this file except in compliance with the License. 66a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * You may obtain a copy of the License at 76a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * 86a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * http://www.apache.org/licenses/LICENSE-2.0 96a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * 106a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Unless required by applicable law or agreed to in writing, software 116a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * distributed under the License is distributed on an "AS IS" BASIS, 126a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * See the License for the specific language governing permissions and 146a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * limitations under the License 156a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson */ 166a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 176a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonpackage com.android.server; 186a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 196a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.Manifest.permission; 20967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslinimport android.content.BroadcastReceiver; 21dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslinimport android.content.ComponentName; 2256f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidsonimport android.content.ContentResolver; 236a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.Context; 24b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidsonimport android.content.Intent; 25967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslinimport android.content.IntentFilter; 26dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslinimport android.content.ServiceConnection; 276a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.pm.PackageManager; 2814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.net.INetworkScoreCache; 296a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.INetworkScoreService; 30b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidsonimport android.net.NetworkScoreManager; 316a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.NetworkScorerAppManager; 32c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidsonimport android.net.NetworkScorerAppManager.NetworkScorerAppData; 336a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.ScoredNetwork; 3426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidsonimport android.os.Binder; 35dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslinimport android.os.IBinder; 3614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.os.RemoteException; 37ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidsonimport android.os.UserHandle; 3856f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidsonimport android.provider.Settings; 396a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.text.TextUtils; 4014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.util.Log; 416a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 426a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport com.android.internal.R; 437842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidsonimport com.android.internal.annotations.GuardedBy; 441ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslinimport com.android.internal.content.PackageMonitor; 456a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 466a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.FileDescriptor; 476a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.PrintWriter; 4814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.ArrayList; 496a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.HashMap; 5014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.HashSet; 5114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.List; 526a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.Map; 5314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.Set; 546a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 556a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson/** 566a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Backing service for {@link android.net.NetworkScoreManager}. 576a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * @hide 586a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson */ 596a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonpublic class NetworkScoreService extends INetworkScoreService.Stub { 606a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private static final String TAG = "NetworkScoreService"; 61dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private static final boolean DBG = false; 626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 636a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private final Context mContext; 6414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson private final Map<Integer, INetworkScoreCache> mScoreCaches; 651ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin /** Lock used to update mPackageMonitor when scorer package changes occur. */ 661ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private final Object mPackageMonitorLock = new Object[0]; 677842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 681ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin @GuardedBy("mPackageMonitorLock") 691ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private NetworkScorerPackageMonitor mPackageMonitor; 70dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private ScoringServiceConnection mServiceConnection; 717842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 72967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { 73967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin @Override 74967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin public void onReceive(Context context, Intent intent) { 75967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin final String action = intent.getAction(); 76967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 77967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin if (DBG) Log.d(TAG, "Received " + action + " for userId " + userId); 78967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin if (userId == UserHandle.USER_NULL) return; 79967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin 80967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin if (Intent.ACTION_USER_UNLOCKED.equals(action)) { 81967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin onUserUnlocked(userId); 82967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin } 83967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin } 84967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin }; 85967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin 861ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin /** 871ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin * Clears scores when the active scorer package is no longer valid and 881ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin * manages the service connection. 891ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin */ 901ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private class NetworkScorerPackageMonitor extends PackageMonitor { 917842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson final String mRegisteredPackage; 927842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 931ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private NetworkScorerPackageMonitor(String mRegisteredPackage) { 941ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin this.mRegisteredPackage = mRegisteredPackage; 951ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 961ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin 971ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin @Override 981ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin public void onPackageAdded(String packageName, int uid) { 991ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin evaluateBinding(packageName, true /* forceUnbind */); 1001ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1011ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin 1021ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin @Override 1031ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin public void onPackageRemoved(String packageName, int uid) { 1041ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin evaluateBinding(packageName, true /* forceUnbind */); 1051ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1061ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin 1071ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin @Override 1081ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin public void onPackageModified(String packageName) { 1091ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin evaluateBinding(packageName, false /* forceUnbind */); 1101ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1111ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin 1121ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin @Override 1131ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 1141ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (doit) { // "doit" means the force stop happened instead of just being queried for. 1151ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin for (String packageName : packages) { 1161ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin evaluateBinding(packageName, true /* forceUnbind */); 1171ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1181ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1191ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin return super.onHandleForceStop(intent, packages, uid, doit); 1207842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1217842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1227842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson @Override 1231ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin public void onPackageUpdateFinished(String packageName, int uid) { 1241ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin evaluateBinding(packageName, true /* forceUnbind */); 1251ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1261ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin 1271ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private void evaluateBinding(String scorerPackageName, boolean forceUnbind) { 1281ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (mRegisteredPackage.equals(scorerPackageName)) { 1291ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) { 1301ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Log.d(TAG, "Evaluating binding for: " + scorerPackageName 1311ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin + ", forceUnbind=" + forceUnbind); 1321ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 1331ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin final NetworkScorerAppData activeScorer = 134dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin NetworkScorerAppManager.getActiveScorer(mContext); 135dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (activeScorer == null) { 1361ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin // Package change has invalidated a scorer, this will also unbind any service 1371ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin // connection. 138dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin Log.i(TAG, "Package " + mRegisteredPackage + 139dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin " is no longer valid, disabling scoring."); 140dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin setScorerInternal(null); 141dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } else if (activeScorer.mScoringServiceClassName == null) { 142dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // The scoring service is not available, make sure it's unbound. 143dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin unbindFromScoringServiceIfNeeded(); 1441ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } else { // The scoring service changed in some way. 1451ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (forceUnbind) { 1461ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin unbindFromScoringServiceIfNeeded(); 1471ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 148dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin bindToScoringServiceIfNeeded(activeScorer); 149dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 1507842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1517842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1527842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1537842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1546a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public NetworkScoreService(Context context) { 1556a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson mContext = context; 15614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson mScoreCaches = new HashMap<>(); 157967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED); 158967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin // TODO: Need to update when we support per-user scorers. http://b/23422763 159967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin mContext.registerReceiverAsUser( 160967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin mUserIntentReceiver, UserHandle.SYSTEM, filter, null /* broadcastPermission*/, 161967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin null /* scheduler */); 1626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1636a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 1646a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson /** Called when the system is ready to run third-party code but before it actually does so. */ 1656a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson void systemReady() { 166dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "systemReady"); 16756f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson ContentResolver cr = mContext.getContentResolver(); 16856f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson if (Settings.Global.getInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 0) == 0) { 1696a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson // On first run, we try to initialize the scorer to the one configured at build time. 1706a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson // This will be a no-op if the scorer isn't actually valid. 1716a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson String defaultPackage = mContext.getResources().getString( 1726a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson R.string.config_defaultNetworkScorerPackageName); 1736a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (!TextUtils.isEmpty(defaultPackage)) { 1746a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage); 1756a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 17656f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1); 1776a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1787842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1791ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin registerPackageMonitorIfNeeded(); 1807842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1817842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 182dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin /** Called when the system is ready for us to start third-party code. */ 183dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin void systemRunning() { 184dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "systemRunning"); 185dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin bindToScoringServiceIfNeeded(); 186dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 187dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 188967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin private void onUserUnlocked(int userId) { 189967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin registerPackageMonitorIfNeeded(); 190967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin bindToScoringServiceIfNeeded(); 191967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin } 192967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin 1931ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private void registerPackageMonitorIfNeeded() { 1941ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded"); 1957842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext); 1961ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin synchronized (mPackageMonitorLock) { 1971ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin // Unregister the current monitor if needed. 1981ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (mPackageMonitor != null) { 1991ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) { 2001ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Log.d(TAG, "Unregistering package monitor for " 2011ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin + mPackageMonitor.mRegisteredPackage); 2027842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 2031ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mPackageMonitor.unregister(); 2041ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mPackageMonitor = null; 2057842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 2067842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 2071ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin // Create and register the monitor if a scorer is active. 2087842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if (scorer != null) { 2091ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mPackageMonitor = new NetworkScorerPackageMonitor(scorer.mPackageName); 210e4de5a0d3b6e0c897c1cea0912b58e11db962365Xiaohui Chen // TODO: Need to update when we support per-user scorers. http://b/23422763 2111ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM, 2121ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin false /* externalStorage */); 2131ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) { 2141ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Log.d(TAG, "Registered package monitor for " 2151ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin + mPackageMonitor.mRegisteredPackage); 2167842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 2177842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 2187842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 2196a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2206a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 221dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private void bindToScoringServiceIfNeeded() { 222dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded"); 223dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin NetworkScorerAppData scorerData = NetworkScorerAppManager.getActiveScorer(mContext); 224dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin bindToScoringServiceIfNeeded(scorerData); 225dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 226dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 227dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private void bindToScoringServiceIfNeeded(NetworkScorerAppData scorerData) { 228dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + scorerData + ")"); 229dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (scorerData != null && scorerData.mScoringServiceClassName != null) { 230dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin ComponentName componentName = 231dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin new ComponentName(scorerData.mPackageName, scorerData.mScoringServiceClassName); 232dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // If we're connected to a different component then drop it. 233dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (mServiceConnection != null 234dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin && !mServiceConnection.mComponentName.equals(componentName)) { 235dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin unbindFromScoringServiceIfNeeded(); 236dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 237dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 238dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // If we're not connected at all then create a new connection. 239dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (mServiceConnection == null) { 240dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mServiceConnection = new ScoringServiceConnection(componentName); 241dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 242dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 243dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // Make sure the connection is connected (idempotent) 244dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mServiceConnection.connect(mContext); 245967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin } else { // otherwise make sure it isn't bound. 246967b5815fb55e25419dcfdcf2144cce513123a61Jeremy Joslin unbindFromScoringServiceIfNeeded(); 247dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 248dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 249dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 250dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private void unbindFromScoringServiceIfNeeded() { 251dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "unbindFromScoringServiceIfNeeded"); 252dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (mServiceConnection != null) { 253dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mServiceConnection.disconnect(mContext); 254dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 255dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mServiceConnection = null; 256dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 257dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 2586a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 2596a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean updateScores(ScoredNetwork[] networks) { 2606a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) { 2616a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson throw new SecurityException("Caller with UID " + getCallingUid() + 2626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson " is not the active scorer."); 2636a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2646a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 26514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson // Separate networks by type. 26614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>(); 2676a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson for (ScoredNetwork network : networks) { 26814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type); 26914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (networkList == null) { 27014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networkList = new ArrayList<>(); 27114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networksByType.put(network.networkKey.type, networkList); 27214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 27314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networkList.add(network); 27414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 27514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 27614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson // Pass the scores of each type down to the appropriate network scorer. 27714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) { 27814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey()); 27914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (scoreCache != null) { 28014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 28114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.updateScores(entry.getValue()); 28214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 28314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 28414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e); 28514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 28614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 28714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } else if (Log.isLoggable(TAG, Log.VERBOSE)) { 28814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding"); 28914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 2906a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2916a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 2926a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 2936a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2946a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 2956a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 2966a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean clearScores() { 297161977998feebf0a855ea56558464470877040cfJeff Davidson // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED) 298161977998feebf0a855ea56558464470877040cfJeff Davidson // should be allowed to flush all scores. 2996a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || 300161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) == 3016a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson PackageManager.PERMISSION_GRANTED) { 3026a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson clearInternal(); 3036a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 3046a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } else { 3056a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson throw new SecurityException( 3066a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson "Caller is neither the active scorer nor the scorer manager."); 3076a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 3086a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 3096a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 3106a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 3116a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean setActiveScorer(String packageName) { 312e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps 313e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // to directly set the scorer app rather than having to use the consent dialog. The 314e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to 315e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // do the right thing and not enable this feature without explaining it to the user. 316e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // In the future, should this API be opened to 3p apps, we will need to lock this down and 317e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // figure out another way to streamline the UX. 318e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson 319e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); 320e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG); 321e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson 32226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson return setScorerInternal(packageName); 32326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 32426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson 32526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson @Override 32626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson public void disableScoring() { 327161977998feebf0a855ea56558464470877040cfJeff Davidson // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED) 328161977998feebf0a855ea56558464470877040cfJeff Davidson // should be allowed to disable scoring. 32926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || 330161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) == 33126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson PackageManager.PERMISSION_GRANTED) { 33226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // The return value is discarded here because at this point, the call should always 33326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // succeed. The only reason for failure is if the new package is not a valid scorer, but 33426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // we're disabling scoring altogether here. 33526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson setScorerInternal(null /* packageName */); 33626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } else { 33726fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson throw new SecurityException( 33826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson "Caller is neither the active scorer nor the scorer manager."); 33926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 34026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 34126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson 34226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson /** Set the active scorer. Callers are responsible for checking permissions as appropriate. */ 34326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson private boolean setScorerInternal(String packageName) { 344dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "setScorerInternal(" + packageName + ")"); 34526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson long token = Binder.clearCallingIdentity(); 34626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson try { 347dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin unbindFromScoringServiceIfNeeded(); 34826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // Preemptively clear scores even though the set operation could fail. We do this for 34926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // safety as scores should never be compared across apps; in practice, Settings should 35026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // only be allowing valid apps to be set as scorers, so failure here should be rare. 35126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson clearInternal(); 352da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin // Get the scorer that is about to be replaced, if any, so we can notify it directly. 353da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext); 35426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName); 355dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // Unconditionally attempt to bind to the current scorer. If setActiveScorer() failed 356dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // then we'll attempt to restore the previous binding (if any), otherwise an attempt 357dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin // will be made to bind to the new scorer. 358dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin bindToScoringServiceIfNeeded(); 359da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin if (result) { // new scorer successfully set 3601ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin registerPackageMonitorIfNeeded(); 361dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 36226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED); 363da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin if (prevScorer != null) { // Directly notify the old scorer. 364da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin intent.setPackage(prevScorer.mPackageName); 365da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin // TODO: Need to update when we support per-user scorers. http://b/23422763 366da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 367da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin } 368da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin 369da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin if (packageName != null) { // Then notify the new scorer 370da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName); 371da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin intent.setPackage(packageName); 372da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin // TODO: Need to update when we support per-user scorers. http://b/23422763 373da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 374da11f5cdf55ace0330008613fa7153993ddd943fJeremy Joslin } 37526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 37626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson return result; 37726fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } finally { 37826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson Binder.restoreCallingIdentity(token); 379b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidson } 3806a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 3816a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 3826a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson /** Clear scores. Callers are responsible for checking permissions as appropriate. */ 3836a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private void clearInternal() { 38414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Set<INetworkScoreCache> cachesToClear = getScoreCaches(); 38514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 38614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (INetworkScoreCache scoreCache : cachesToClear) { 38714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 38814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.clearScores(); 38914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 39014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 39114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to clear scores", e); 39214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 39314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 39414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 39514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 39614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 39714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson @Override 39814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { 399161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); 40014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson synchronized (mScoreCaches) { 40114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (mScoreCaches.containsKey(networkType)) { 40214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson throw new IllegalArgumentException( 40314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson "Score cache already registered for type " + networkType); 40414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 40514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson mScoreCaches.put(networkType, scoreCache); 40614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 4076a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 4086a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 4096a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 4106a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 4116a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); 412c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson NetworkScorerAppData currentScorer = NetworkScorerAppManager.getActiveScorer(mContext); 4136a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (currentScorer == null) { 4146a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson writer.println("Scoring is disabled."); 4156a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return; 4166a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 417c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson writer.println("Current scorer: " + currentScorer.mPackageName); 41814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 41914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (INetworkScoreCache scoreCache : getScoreCaches()) { 42014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 42114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.asBinder().dump(fd, args); 42214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 42314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson writer.println("Unable to dump score cache"); 42414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 42514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to dump score cache", e); 42614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 4276a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 4286a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 429dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (mServiceConnection != null) { 430dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mServiceConnection.dump(fd, writer, args); 431dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } else { 432dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin writer.println("ScoringServiceConnection: null"); 433dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 434dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin writer.flush(); 4356a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 43614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 43714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson /** 43814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * Returns a set of all score caches that are currently active. 43914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * 44014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * <p>May be used to perform an action on all score caches without potentially strange behavior 44114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * if a new scorer is registered during that action's execution. 44214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson */ 44314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson private Set<INetworkScoreCache> getScoreCaches() { 44414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson synchronized (mScoreCaches) { 44514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson return new HashSet<>(mScoreCaches.values()); 44614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 44714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 448dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 449dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private static class ScoringServiceConnection implements ServiceConnection { 450dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private final ComponentName mComponentName; 451dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin private boolean mBound = false; 4521ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin private boolean mConnected = false; 453dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 454dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin ScoringServiceConnection(ComponentName componentName) { 455dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mComponentName = componentName; 456dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 457dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 458dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin void connect(Context context) { 459dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (!mBound) { 4601ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Intent service = new Intent(); 4611ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin service.setComponent(mComponentName); 4621ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mBound = context.bindServiceAsUser(service, this, 4631ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 4641ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin UserHandle.SYSTEM); 4651ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (!mBound) { 4661ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Log.w(TAG, "Bind call failed for " + service); 4671ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } else { 4681ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) Log.d(TAG, "ScoringServiceConnection bound."); 4691ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 470dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 471dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 472dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 473dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin void disconnect(Context context) { 474dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin try { 475dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (mBound) { 476dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin mBound = false; 477dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin context.unbindService(this); 4781ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) Log.d(TAG, "ScoringServiceConnection unbound."); 479dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 480dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } catch (RuntimeException e) { 481dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin Log.e(TAG, "Unbind failed.", e); 482dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 483dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 484dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 485dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin @Override 486dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin public void onServiceConnected(ComponentName name, IBinder service) { 487dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString()); 4881ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mConnected = true; 489dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 490dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 491dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin @Override 492dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin public void onServiceDisconnected(ComponentName name) { 4931ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin if (DBG) { 4941ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin Log.d(TAG, "ScoringServiceConnection, disconnected: " + name.flattenToString()); 4951ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin } 4961ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin mConnected = false; 497dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 498dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin 499dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 5001ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound 5011ec8cd95426a22ded1ab9a13c7608ce9c699010aJeremy Joslin + ", connected: " + mConnected); 502dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 503dd251ef4952b6c7abbfe8cea49285d8cfe62f96eJeremy Joslin } 5046a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson} 505