Clear and restore the calling ID.

Clear and restore the calling identity in IPC methods after asserting
the caller has the required permissions.

Fixed 2 tests in NetworkScoreServiceTest that were failing due to a
recent refactor.

Test: runtest frameworks-services -c com.android.server.NetworkScoreServiceTest
BUG: 33781319
Change-Id: I562713df3d9455cdc02bf80a687940fb9daecd8f
Merged-In: Icd79751d12dcfe4af8026980aaa1f7bd463468dc
This commit is contained in:
Jeremy Joslin
2016-12-20 14:36:20 -08:00
parent febd982cdd
commit 29ed4a99bf
2 changed files with 117 additions and 82 deletions

View File

@@ -40,7 +40,7 @@ import android.net.RecommendationRequest;
import android.net.RecommendationResult; import android.net.RecommendationResult;
import android.net.ScoredNetwork; import android.net.ScoredNetwork;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiConfiguration; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.IRemoteCallback; import android.os.IRemoteCallback;
@@ -319,47 +319,54 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
" is not the active scorer."); " is not the active scorer.");
} }
// Separate networks by type. final long token = Binder.clearCallingIdentity();
Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>(); try {
for (ScoredNetwork network : networks) { // Separate networks by type.
List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type); Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>();
if (networkList == null) { for (ScoredNetwork network : networks) {
networkList = new ArrayList<>(); List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
networksByType.put(network.networkKey.type, networkList); if (networkList == null) {
} networkList = new ArrayList<>();
networkList.add(network); networksByType.put(network.networkKey.type, networkList);
}
// Pass the scores of each type down to the appropriate network scorer.
for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
final RemoteCallbackList<INetworkScoreCache> callbackList;
final boolean isEmpty;
synchronized (mScoreCaches) {
callbackList = mScoreCaches.get(entry.getKey());
isEmpty = callbackList == null || callbackList.getRegisteredCallbackCount() == 0;
}
if (isEmpty) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
} }
continue; networkList.add(network);
} }
sendCallback(new Consumer<INetworkScoreCache>() { // Pass the scores of each type down to the appropriate network scorer.
@Override for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
public void accept(INetworkScoreCache networkScoreCache) { final RemoteCallbackList<INetworkScoreCache> callbackList;
try { final boolean isEmpty;
networkScoreCache.updateScores(entry.getValue()); synchronized (mScoreCaches) {
} catch (RemoteException e) { callbackList = mScoreCaches.get(entry.getKey());
if (Log.isLoggable(TAG, Log.VERBOSE)) { isEmpty = callbackList == null
Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e); || callbackList.getRegisteredCallbackCount() == 0;
}
if (isEmpty) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No scorer registered for type " + entry.getKey()
+ ", discarding");
}
continue;
}
sendCallback(new Consumer<INetworkScoreCache>() {
@Override
public void accept(INetworkScoreCache networkScoreCache) {
try {
networkScoreCache.updateScores(entry.getValue());
} catch (RemoteException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
}
} }
} }
} }, Collections.singleton(callbackList));
}, Collections.singleton(callbackList)); }
}
return true; return true;
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
@@ -369,8 +376,13 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) == mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
PackageManager.PERMISSION_GRANTED) { PackageManager.PERMISSION_GRANTED) {
clearInternal(); final long token = Binder.clearCallingIdentity();
return true; try {
clearInternal();
return true;
} finally {
Binder.restoreCallingIdentity(token);
}
} else { } else {
throw new SecurityException( throw new SecurityException(
"Caller is neither the active scorer nor the scorer manager."); "Caller is neither the active scorer nor the scorer manager.");
@@ -428,35 +440,46 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
INetworkScoreCache scoreCache, INetworkScoreCache scoreCache,
int filterType) { int filterType) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) { final long token = Binder.clearCallingIdentity();
RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType); try {
if (callbackList == null) { synchronized (mScoreCaches) {
callbackList = new RemoteCallbackList<>(); RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
mScoreCaches.put(networkType, callbackList); if (callbackList == null) {
} callbackList = new RemoteCallbackList<>();
if (!callbackList.register(scoreCache, filterType)) { mScoreCaches.put(networkType, callbackList);
if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
} }
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (!callbackList.register(scoreCache, filterType)) {
Log.v(TAG, "Unable to register NetworkScoreCache for type " + networkType); if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to register NetworkScoreCache for type " + networkType);
}
} }
} }
} finally {
Binder.restoreCallingIdentity(token);
} }
} }
@Override @Override
public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) { final long token = Binder.clearCallingIdentity();
RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType); try {
if (callbackList == null || !callbackList.unregister(scoreCache)) { synchronized (mScoreCaches) {
if (Log.isLoggable(TAG, Log.VERBOSE)) { RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
Log.v(TAG, "Unable to unregister NetworkScoreCache for type " + networkType); if (callbackList == null || !callbackList.unregister(scoreCache)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to unregister NetworkScoreCache for type "
+ networkType);
}
} else if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
} }
} else if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
} }
} finally {
Binder.restoreCallingIdentity(token);
} }
} }
@@ -464,43 +487,53 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
public RecommendationResult requestRecommendation(RecommendationRequest request) { public RecommendationResult requestRecommendation(RecommendationRequest request) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
throwIfCalledOnMainThread(); throwIfCalledOnMainThread();
final INetworkRecommendationProvider provider = getRecommendationProvider(); final long token = Binder.clearCallingIdentity();
if (provider != null) { try {
try { final INetworkRecommendationProvider provider = getRecommendationProvider();
return mRequestRecommendationCaller.getRecommendationResult(provider, request); if (provider != null) {
} catch (RemoteException | TimeoutException e) { try {
Log.w(TAG, "Failed to request a recommendation.", e); return mRequestRecommendationCaller.getRecommendationResult(provider, request);
// TODO(jjoslin): 12/15/16 - Keep track of failures. } catch (RemoteException | TimeoutException e) {
Log.w(TAG, "Failed to request a recommendation.", e);
// TODO(jjoslin): 12/15/16 - Keep track of failures.
}
} }
}
if (DBG) { if (DBG) {
Log.d(TAG, "Returning the default network recommendation."); Log.d(TAG, "Returning the default network recommendation.");
} }
if (request != null && request.getCurrentSelectedConfig() != null) { if (request != null && request.getCurrentSelectedConfig() != null) {
return RecommendationResult.createConnectRecommendation( return RecommendationResult.createConnectRecommendation(
request.getCurrentSelectedConfig()); request.getCurrentSelectedConfig());
}
return RecommendationResult.createDoNotConnectRecommendation();
} finally {
Binder.restoreCallingIdentity(token);
} }
return RecommendationResult.createDoNotConnectRecommendation();
} }
@Override @Override
public boolean requestScores(NetworkKey[] networks) { public boolean requestScores(NetworkKey[] networks) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG); mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
final INetworkRecommendationProvider provider = getRecommendationProvider(); final long token = Binder.clearCallingIdentity();
if (provider != null) { try {
try { final INetworkRecommendationProvider provider = getRecommendationProvider();
provider.requestScores(networks); if (provider != null) {
// TODO(jjoslin): 12/15/16 - Consider pushing null scores into the cache to prevent try {
// repeated requests for the same scores. provider.requestScores(networks);
return true; // TODO(jjoslin): 12/15/16 - Consider pushing null scores into the cache to
} catch (RemoteException e) { // prevent repeated requests for the same scores.
Log.w(TAG, "Failed to request scores.", e); return true;
// TODO(jjoslin): 12/15/16 - Keep track of failures. } catch (RemoteException e) {
Log.w(TAG, "Failed to request scores.", e);
// TODO(jjoslin): 12/15/16 - Keep track of failures.
}
} }
return false;
} finally {
Binder.restoreCallingIdentity(token);
} }
return false;
} }
@Override @Override

View File

@@ -122,6 +122,8 @@ public class NetworkScoreServiceTest {
when(mContext.getResources()).thenReturn(mResources); when(mContext.getResources()).thenReturn(mResources);
mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager); mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager);
WifiConfiguration configuration = new WifiConfiguration(); WifiConfiguration configuration = new WifiConfiguration();
configuration.SSID = "NetworkScoreServiceTest_SSID";
configuration.BSSID = "NetworkScoreServiceTest_BSSID";
mRecommendationRequest = new RecommendationRequest.Builder() mRecommendationRequest = new RecommendationRequest.Builder()
.setCurrentRecommendedWifiConfig(configuration).build(); .setCurrentRecommendedWifiConfig(configuration).build();
} }