NetworkScoreService.java revision 6a4b220f1263d95fdefe6361c2bc87bbb04bbed0
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server; 18 19import android.Manifest.permission; 20import android.content.Context; 21import android.content.SharedPreferences; 22import android.content.pm.PackageManager; 23import android.net.INetworkScoreService; 24import android.net.NetworkKey; 25import android.net.NetworkScorerAppManager; 26import android.net.RssiCurve; 27import android.net.ScoredNetwork; 28import android.text.TextUtils; 29 30import com.android.internal.R; 31 32import java.io.FileDescriptor; 33import java.io.PrintWriter; 34import java.util.HashMap; 35import java.util.Map; 36 37/** 38 * Backing service for {@link android.net.NetworkScoreManager}. 39 * @hide 40 */ 41public class NetworkScoreService extends INetworkScoreService.Stub { 42 private static final String TAG = "NetworkScoreService"; 43 44 /** SharedPreference bit set to true after the service is first initialized. */ 45 private static final String PREF_SCORING_PROVISIONED = "is_provisioned"; 46 47 private final Context mContext; 48 49 // TODO: Delete this temporary class once we have a real place for scores. 50 private final Map<NetworkKey, RssiCurve> mScoredNetworks; 51 52 public NetworkScoreService(Context context) { 53 mContext = context; 54 mScoredNetworks = new HashMap<>(); 55 } 56 57 /** Called when the system is ready to run third-party code but before it actually does so. */ 58 void systemReady() { 59 SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE); 60 if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) { 61 // On first run, we try to initialize the scorer to the one configured at build time. 62 // This will be a no-op if the scorer isn't actually valid. 63 String defaultPackage = mContext.getResources().getString( 64 R.string.config_defaultNetworkScorerPackageName); 65 if (!TextUtils.isEmpty(defaultPackage)) { 66 NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage); 67 } 68 prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply(); 69 } 70 } 71 72 @Override 73 public boolean updateScores(ScoredNetwork[] networks) { 74 if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) { 75 throw new SecurityException("Caller with UID " + getCallingUid() + 76 " is not the active scorer."); 77 } 78 79 // TODO: Propagate these scores down to the network subsystem layer instead of just holding 80 // them in memory. 81 for (ScoredNetwork network : networks) { 82 mScoredNetworks.put(network.networkKey, network.rssiCurve); 83 } 84 85 return true; 86 } 87 88 @Override 89 public boolean clearScores() { 90 // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETWORKS) should 91 // be allowed to flush all scores. 92 if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) || 93 mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) == 94 PackageManager.PERMISSION_GRANTED) { 95 clearInternal(); 96 return true; 97 } else { 98 throw new SecurityException( 99 "Caller is neither the active scorer nor the scorer manager."); 100 } 101 } 102 103 @Override 104 public boolean setActiveScorer(String packageName) { 105 mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG); 106 // Preemptively clear scores even though the set operation could fail. We do this for safety 107 // as scores should never be compared across apps; in practice, Settings should only be 108 // allowing valid apps to be set as scorers, so failure here should be rare. 109 clearInternal(); 110 return NetworkScorerAppManager.setActiveScorer(mContext, packageName); 111 } 112 113 /** Clear scores. Callers are responsible for checking permissions as appropriate. */ 114 private void clearInternal() { 115 // TODO: Propagate the flush down to the network subsystem layer. 116 mScoredNetworks.clear(); 117 } 118 119 @Override 120 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 121 mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); 122 String currentScorer = NetworkScorerAppManager.getActiveScorer(mContext); 123 if (currentScorer == null) { 124 writer.println("Scoring is disabled."); 125 return; 126 } 127 writer.println("Current scorer: " + currentScorer); 128 if (mScoredNetworks.isEmpty()) { 129 writer.println("No networks scored."); 130 } else { 131 for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) { 132 writer.println(entry.getKey() + ": " + entry.getValue()); 133 } 134 } 135 } 136} 137