NetworkScoreService.java revision 6a4b220f1263d95fdefe6361c2bc87bbb04bbed0
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;
206a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.Context;
216a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.SharedPreferences;
226a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.content.pm.PackageManager;
236a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.INetworkScoreService;
246a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.NetworkKey;
256a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.NetworkScorerAppManager;
266a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.RssiCurve;
276a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.net.ScoredNetwork;
286a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport android.text.TextUtils;
296a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
306a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport com.android.internal.R;
316a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
326a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.FileDescriptor;
336a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.io.PrintWriter;
346a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.HashMap;
356a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonimport java.util.Map;
366a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
376a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson/**
386a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * Backing service for {@link android.net.NetworkScoreManager}.
396a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson * @hide
406a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson */
416a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidsonpublic class NetworkScoreService extends INetworkScoreService.Stub {
426a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    private static final String TAG = "NetworkScoreService";
436a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
446a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    /** SharedPreference bit set to true after the service is first initialized. */
456a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    private static final String PREF_SCORING_PROVISIONED = "is_provisioned";
466a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
476a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    private final Context mContext;
486a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
496a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    // TODO: Delete this temporary class once we have a real place for scores.
506a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    private final Map<NetworkKey, RssiCurve> mScoredNetworks;
516a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
526a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    public NetworkScoreService(Context context) {
536a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        mContext = context;
546a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        mScoredNetworks = new HashMap<>();
556a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
566a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
576a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    /** Called when the system is ready to run third-party code but before it actually does so. */
586a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    void systemReady() {
596a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE);
606a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) {
616a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            // On first run, we try to initialize the scorer to the one configured at build time.
626a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            // This will be a no-op if the scorer isn't actually valid.
636a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            String defaultPackage = mContext.getResources().getString(
646a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                    R.string.config_defaultNetworkScorerPackageName);
656a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            if (!TextUtils.isEmpty(defaultPackage)) {
666a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
676a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            }
686a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply();
696a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
706a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
716a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
726a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    @Override
736a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    public boolean updateScores(ScoredNetwork[] networks) {
746a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) {
756a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            throw new SecurityException("Caller with UID " + getCallingUid() +
766a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                    " is not the active scorer.");
776a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
786a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
796a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // TODO: Propagate these scores down to the network subsystem layer instead of just holding
806a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // them in memory.
816a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        for (ScoredNetwork network : networks) {
826a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            mScoredNetworks.put(network.networkKey, network.rssiCurve);
836a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
846a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
856a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        return true;
866a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
876a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
886a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    @Override
896a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    public boolean clearScores() {
906a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETWORKS) should
916a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // be allowed to flush all scores.
926a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
936a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
946a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                        PackageManager.PERMISSION_GRANTED) {
956a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            clearInternal();
966a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            return true;
976a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        } else {
986a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            throw new SecurityException(
996a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                    "Caller is neither the active scorer nor the scorer manager.");
1006a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
1016a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
1026a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
1036a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    @Override
1046a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    public boolean setActiveScorer(String packageName) {
1056a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
1066a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // Preemptively clear scores even though the set operation could fail. We do this for safety
1076a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // as scores should never be compared across apps; in practice, Settings should only be
1086a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // allowing valid apps to be set as scorers, so failure here should be rare.
1096a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        clearInternal();
1106a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        return NetworkScorerAppManager.setActiveScorer(mContext, packageName);
1116a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
1126a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
1136a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    /** Clear scores. Callers are responsible for checking permissions as appropriate. */
1146a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    private void clearInternal() {
1156a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        // TODO: Propagate the flush down to the network subsystem layer.
1166a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        mScoredNetworks.clear();
1176a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
1186a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson
1196a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    @Override
1206a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1216a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
1226a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        String currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
1236a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        if (currentScorer == null) {
1246a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            writer.println("Scoring is disabled.");
1256a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            return;
1266a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
1276a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        writer.println("Current scorer: " + currentScorer);
1286a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        if (mScoredNetworks.isEmpty()) {
1296a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            writer.println("No networks scored.");
1306a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        } else {
1316a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) {
1326a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson                writer.println(entry.getKey() + ": " + entry.getValue());
1336a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson            }
1346a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson        }
1356a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson    }
1366a4b220f1263d95fdefe6361c2bc87bbb04bbed0Jeff Davidson}
137