blob: 8a30e50c9aaf79d778cca0aeb0d22538d3abfffb [file] [log] [blame]
Jeff Davidson6a4b2202014-04-16 17:29:40 -07001/*
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}