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; 207842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidsonimport android.content.BroadcastReceiver; 2156f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidsonimport android.content.ContentResolver; 226a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.Context; 23b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidsonimport android.content.Intent; 247842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidsonimport android.content.IntentFilter; 256a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.pm.PackageManager; 2614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.net.INetworkScoreCache; 276a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.INetworkScoreService; 28b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidsonimport android.net.NetworkScoreManager; 296a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.NetworkScorerAppManager; 30c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidsonimport android.net.NetworkScorerAppManager.NetworkScorerAppData; 316a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.ScoredNetwork; 3226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidsonimport android.os.Binder; 337842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidsonimport android.os.PatternMatcher; 3414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.os.RemoteException; 35ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidsonimport android.os.UserHandle; 3656f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidsonimport android.provider.Settings; 376a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.text.TextUtils; 3814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport android.util.Log; 396a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 406a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport com.android.internal.R; 417842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidsonimport com.android.internal.annotations.GuardedBy; 426a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 436a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.FileDescriptor; 446a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.PrintWriter; 4514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.ArrayList; 466a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.HashMap; 4714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.HashSet; 4814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.List; 496a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.Map; 5014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidsonimport java.util.Set; 516a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 526a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson/** 536a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Backing service for {@link android.net.NetworkScoreManager}. 546a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * @hide 556a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson */ 566a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonpublic class NetworkScoreService extends INetworkScoreService.Stub { 576a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private static final String TAG = "NetworkScoreService"; 586a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 596a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private final Context mContext; 606a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 6114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson private final Map<Integer, INetworkScoreCache> mScoreCaches; 626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 637842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson /** Lock used to update mReceiver when scorer package changes occur. */ 647842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson private Object mReceiverLock = new Object[0]; 657842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 667842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson /** Clears scores when the active scorer package is no longer valid. */ 677842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson @GuardedBy("mReceiverLock") 687842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson private ScorerChangedReceiver mReceiver; 697842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 707842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson private class ScorerChangedReceiver extends BroadcastReceiver { 717842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson final String mRegisteredPackage; 727842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 737842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson ScorerChangedReceiver(String packageName) { 747842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson mRegisteredPackage = packageName; 757842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 767842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 777842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson @Override 787842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson public void onReceive(Context context, Intent intent) { 797842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson String action = intent.getAction(); 807842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if ((Intent.ACTION_PACKAGE_CHANGED.equals(action) || 817842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson Intent.ACTION_PACKAGE_REPLACED.equals(action) || 827842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) && 837842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson NetworkScorerAppManager.getActiveScorer(mContext) == null) { 847842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson // Package change has invalidated a scorer. 857842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson Log.i(TAG, "Package " + mRegisteredPackage + 867842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson " is no longer valid, disabling scoring"); 877842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson setScorerInternal(null); 887842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 897842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 907842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 917842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 926a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public NetworkScoreService(Context context) { 936a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson mContext = context; 9414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson mScoreCaches = new HashMap<>(); 956a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 966a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 976a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson /** Called when the system is ready to run third-party code but before it actually does so. */ 986a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson void systemReady() { 9956f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson ContentResolver cr = mContext.getContentResolver(); 10056f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson if (Settings.Global.getInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 0) == 0) { 1016a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson // On first run, we try to initialize the scorer to the one configured at build time. 1026a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson // This will be a no-op if the scorer isn't actually valid. 1036a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson String defaultPackage = mContext.getResources().getString( 1046a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson R.string.config_defaultNetworkScorerPackageName); 1056a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (!TextUtils.isEmpty(defaultPackage)) { 1066a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage); 1076a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 10856f9f73a5aad38aa777ec9a42c859e687f2d2af1Jeff Davidson Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1); 1096a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1107842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1117842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson registerPackageReceiverIfNeeded(); 1127842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1137842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1147842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson private void registerPackageReceiverIfNeeded() { 1157842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext); 1167842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson synchronized (mReceiverLock) { 1177842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson // Unregister the receiver if the current scorer has changed since last registration. 1187842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if (mReceiver != null) { 1197842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 1207842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson Log.v(TAG, "Unregistering receiver for " + mReceiver.mRegisteredPackage); 1217842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1227842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson mContext.unregisterReceiver(mReceiver); 1237842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson mReceiver = null; 1247842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1257842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson 1267842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson // Register receiver if a scorer is active. 1277842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if (scorer != null) { 1287842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson IntentFilter filter = new IntentFilter(); 1297842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1307842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 1317842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); 1327842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson filter.addDataScheme("package"); 1337842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson filter.addDataSchemeSpecificPart(scorer.mPackageName, 1347842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson PatternMatcher.PATTERN_LITERAL); 1357842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson mReceiver = new ScorerChangedReceiver(scorer.mPackageName); 1367842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson // TODO: Need to update when we support per-user scorers. 1377842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, null, null); 1387842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 1397842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson Log.v(TAG, "Registered receiver for " + scorer.mPackageName); 1407842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1417842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1427842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson } 1436a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1446a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 1456a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 1466a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean updateScores(ScoredNetwork[] networks) { 1476a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) { 1486a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson throw new SecurityException("Caller with UID " + getCallingUid() + 1496a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson " is not the active scorer."); 1506a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1516a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 15214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson // Separate networks by type. 15314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>(); 1546a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson for (ScoredNetwork network : networks) { 15514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type); 15614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (networkList == null) { 15714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networkList = new ArrayList<>(); 15814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networksByType.put(network.networkKey.type, networkList); 15914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 16014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson networkList.add(network); 16114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 16214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 16314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson // Pass the scores of each type down to the appropriate network scorer. 16414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) { 16514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey()); 16614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (scoreCache != null) { 16714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 16814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.updateScores(entry.getValue()); 16914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 17014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 17114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e); 17214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 17314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 17414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } else if (Log.isLoggable(TAG, Log.VERBOSE)) { 17514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding"); 17614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 1776a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1786a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 1796a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 1806a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1816a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 1826a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 1836a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean clearScores() { 184161977998feebf0a855ea56558464470877040cfJeff Davidson // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED) 185161977998feebf0a855ea56558464470877040cfJeff Davidson // should be allowed to flush all scores. 1866a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || 187161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) == 1886a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson PackageManager.PERMISSION_GRANTED) { 1896a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson clearInternal(); 1906a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return true; 1916a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } else { 1926a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson throw new SecurityException( 1936a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson "Caller is neither the active scorer nor the scorer manager."); 1946a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1956a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 1966a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 1976a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 1986a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson public boolean setActiveScorer(String packageName) { 199e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps 200e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // to directly set the scorer app rather than having to use the consent dialog. The 201e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to 202e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // do the right thing and not enable this feature without explaining it to the user. 203e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // In the future, should this API be opened to 3p apps, we will need to lock this down and 204e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // figure out another way to streamline the UX. 205e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson 206e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson // mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); 207e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG); 208e56f2bb5ecae624e1b6573515f855a26f756aed5Jeff Davidson 20926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson return setScorerInternal(packageName); 21026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 21126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson 21226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson @Override 21326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson public void disableScoring() { 214161977998feebf0a855ea56558464470877040cfJeff Davidson // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED) 215161977998feebf0a855ea56558464470877040cfJeff Davidson // should be allowed to disable scoring. 21626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || 217161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) == 21826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson PackageManager.PERMISSION_GRANTED) { 21926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // The return value is discarded here because at this point, the call should always 22026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // succeed. The only reason for failure is if the new package is not a valid scorer, but 22126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // we're disabling scoring altogether here. 22226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson setScorerInternal(null /* packageName */); 22326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } else { 22426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson throw new SecurityException( 22526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson "Caller is neither the active scorer nor the scorer manager."); 22626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 22726fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 22826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson 22926fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson /** Set the active scorer. Callers are responsible for checking permissions as appropriate. */ 23026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson private boolean setScorerInternal(String packageName) { 23126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson long token = Binder.clearCallingIdentity(); 23226fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson try { 23326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // Preemptively clear scores even though the set operation could fail. We do this for 23426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // safety as scores should never be compared across apps; in practice, Settings should 23526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson // only be allowing valid apps to be set as scorers, so failure here should be rare. 23626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson clearInternal(); 23726fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName); 23826fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson if (result) { 2397842f64b75282f1233b30ebdb0d876c485def9a7Jeff Davidson registerPackageReceiverIfNeeded(); 24026fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED); 24126fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName); 242ac7285dc1e13f30d59dad30fe2ad1116e5f676cbJeff Davidson mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 24326fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } 24426fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson return result; 24526fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson } finally { 24626fd143326a11c9dd7942e31acca6df56288d194Jeff Davidson Binder.restoreCallingIdentity(token); 247b096bdceaf2a4becffd2d930a870ccb57bfbe99cJeff Davidson } 2486a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2496a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 2506a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson /** Clear scores. Callers are responsible for checking permissions as appropriate. */ 2516a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson private void clearInternal() { 25214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Set<INetworkScoreCache> cachesToClear = getScoreCaches(); 25314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 25414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (INetworkScoreCache scoreCache : cachesToClear) { 25514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 25614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.clearScores(); 25714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 25814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 25914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to clear scores", e); 26014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 26114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 26214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 26314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 26414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 26514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson @Override 26614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { 267161977998feebf0a855ea56558464470877040cfJeff Davidson mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); 26814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson synchronized (mScoreCaches) { 26914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (mScoreCaches.containsKey(networkType)) { 27014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson throw new IllegalArgumentException( 27114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson "Score cache already registered for type " + networkType); 27214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 27314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson mScoreCaches.put(networkType, scoreCache); 27414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 2756a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2766a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson 2776a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson @Override 2786a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 2796a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); 280c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson NetworkScorerAppData currentScorer = NetworkScorerAppManager.getActiveScorer(mContext); 2816a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson if (currentScorer == null) { 2826a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson writer.println("Scoring is disabled."); 2836a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson return; 2846a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 285c741553644f8b19c63938ab9e36af1721c2cfa34Jeff Davidson writer.println("Current scorer: " + currentScorer.mPackageName); 28668c46fd8dd88b906cf064f0d8d0408d4f60e2a4dJeff Davidson writer.flush(); 28714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 28814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson for (INetworkScoreCache scoreCache : getScoreCaches()) { 28914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson try { 29014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson scoreCache.asBinder().dump(fd, args); 29114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } catch (RemoteException e) { 29214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson writer.println("Unable to dump score cache"); 29314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson if (Log.isLoggable(TAG, Log.VERBOSE)) { 29414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson Log.v(TAG, "Unable to dump score cache", e); 29514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 2966a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2976a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 2986a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson } 29914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson 30014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson /** 30114f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * Returns a set of all score caches that are currently active. 30214f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * 30314f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * <p>May be used to perform an action on all score caches without potentially strange behavior 30414f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson * if a new scorer is registered during that action's execution. 30514f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson */ 30614f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson private Set<INetworkScoreCache> getScoreCaches() { 30714f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson synchronized (mScoreCaches) { 30814f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson return new HashSet<>(mScoreCaches.values()); 30914f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 31014f1ec05b2add5ee051c0d2e7c7c3b36a6e77b92Jeff Davidson } 3116a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson} 312