diff options
-rw-r--r-- | core/java/android/net/INetworkScoreService.aidl | 6 | ||||
-rw-r--r-- | core/java/android/net/NetworkScoreManager.java | 14 | ||||
-rw-r--r-- | services/core/java/com/android/server/NetworkScoreService.java | 48 |
3 files changed, 58 insertions, 10 deletions
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 @@ interface INetworkScoreService 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 @@ public class NetworkScoreManager { } /** + * 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.NetworkScoreManager; 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 @@ public class NetworkScoreService extends INetworkScoreService.Stub { @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."); + } + } + + /** 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); } - return result; } /** Clear scores. Callers are responsible for checking permissions as appropriate. */ |