Add NetworkScoreManager.disableScoring().
Allows the active scorer app to disable itself.
Change-Id: I7bcdc3aafb95af4ea0b110b01b08ab4daf7a137f
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 626bd2a..43869264 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -48,6 +48,12 @@
boolean setActiveScorer(in String packageName);
/**
+ * Disable the current active scorer and clear existing scores.
+ * @throws SecurityException if the caller is not the current scorer or the system.
+ */
+ void disableScoring();
+
+ /**
* Register a network subsystem for scoring.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index b497c6e..2fc3892 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -205,6 +205,20 @@
}
/**
+ * Turn off network scoring.
+ *
+ * <p>May only be called by the current scorer app, or the system.
+ *
+ * @throws SecurityException if the caller is neither the active scorer nor the system.
+ */
+ public void disableScoring() throws SecurityException {
+ try {
+ mService.disableScoring();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Request scoring for networks.
*
* <p>Note that this is just a helper method to assemble the broadcast, and will run in the
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 538501b..3e2f260 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -27,6 +27,7 @@
import android.net.NetworkScorerAppManager;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.net.ScoredNetwork;
+import android.os.Binder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
@@ -131,17 +132,44 @@
@Override
public boolean setActiveScorer(String packageName) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
- // Preemptively clear scores even though the set operation could fail. We do this for safety
- // as scores should never be compared across apps; in practice, Settings should only be
- // allowing valid apps to be set as scorers, so failure here should be rare.
- clearInternal();
- boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
- if (result) {
- Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
- intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
- mContext.sendBroadcast(intent);
+ return setScorerInternal(packageName);
+ }
+
+ @Override
+ public void disableScoring() {
+ // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETOWRKS) should
+ // be allowed to disable scoring.
+ if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+ mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
+ PackageManager.PERMISSION_GRANTED) {
+ // The return value is discarded here because at this point, the call should always
+ // succeed. The only reason for failure is if the new package is not a valid scorer, but
+ // we're disabling scoring altogether here.
+ setScorerInternal(null /* packageName */);
+ } else {
+ throw new SecurityException(
+ "Caller is neither the active scorer nor the scorer manager.");
}
- return result;
+ }
+
+ /** Set the active scorer. Callers are responsible for checking permissions as appropriate. */
+ private boolean setScorerInternal(String packageName) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ // Preemptively clear scores even though the set operation could fail. We do this for
+ // safety as scores should never be compared across apps; in practice, Settings should
+ // only be allowing valid apps to be set as scorers, so failure here should be rare.
+ clearInternal();
+ boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+ if (result) {
+ Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
+ intent.putExtra(NetworkScoreManager.EXTRA_NEW_SCORER, packageName);
+ mContext.sendBroadcast(intent);
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/** Clear scores. Callers are responsible for checking permissions as appropriate. */