summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java335
-rw-r--r--services/core/java/com/android/server/MountService.java27
-rw-r--r--services/core/java/com/android/server/SystemConfig.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java53
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java1
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java85
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java50
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java8
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java1
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java255
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java13
-rw-r--r--services/core/java/com/android/server/policy/BarController.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java33
-rw-r--r--services/core/java/com/android/server/search/SearchManagerService.java26
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java319
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java364
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java62
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java5
24 files changed, 1094 insertions, 612 deletions
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7f124dc..39c2891 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -220,23 +220,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int ENABLED = 1;
private static final int DISABLED = 0;
- // Arguments to rematchNetworkAndRequests()
- private enum NascentState {
- // Indicates a network was just validated for the first time. If the network is found to
- // be unwanted (i.e. not satisfy any NetworkRequests) it is torn down.
- JUST_VALIDATED,
- // Indicates a network was not validated for the first time immediately prior to this call.
- NOT_JUST_VALIDATED
- };
private enum ReapUnvalidatedNetworks {
- // Tear down unvalidated networks that have no chance (i.e. even if validated) of becoming
- // the highest scoring network satisfying a NetworkRequest. This should be passed when it's
- // known that there may be unvalidated networks that could potentially be reaped, and when
+ // Tear down networks that have no chance (e.g. even if validated) of becoming
+ // the highest scoring network satisfying a NetworkRequest. This should be passed when
// all networks have been rematched against all NetworkRequests.
REAP,
- // Don't reap unvalidated networks. This should be passed when it's known that there are
- // no unvalidated networks that could potentially be reaped, and when some networks have
- // not yet been rematched against all NetworkRequests.
+ // Don't reap networks. This should be passed when some networks have not yet been
+ // rematched against all NetworkRequests.
DONT_REAP
};
@@ -493,10 +483,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void maybeLogBroadcast(NetworkAgentInfo nai, boolean connected, int type,
+ private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
boolean isDefaultNetwork) {
if (DBG) {
- log("Sending " + (connected ? "connected" : "disconnected") +
+ log("Sending " + state +
" broadcast for type " + type + " " + nai.name() +
" isDefaultNetwork=" + isDefaultNetwork);
}
@@ -520,8 +510,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Send a broadcast if this is the first network of its type or if it's the default.
final boolean isDefaultNetwork = isDefaultNetwork(nai);
if (list.size() == 1 || isDefaultNetwork) {
- maybeLogBroadcast(nai, true, type, isDefaultNetwork);
- sendLegacyNetworkBroadcast(nai, true, type);
+ maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
+ sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
}
}
@@ -538,17 +528,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
+ final DetailedState state = DetailedState.DISCONNECTED;
+
if (wasFirstNetwork || wasDefault) {
- maybeLogBroadcast(nai, false, type, wasDefault);
- sendLegacyNetworkBroadcast(nai, false, type);
+ maybeLogBroadcast(nai, state, type, wasDefault);
+ sendLegacyNetworkBroadcast(nai, state, type);
}
if (!list.isEmpty() && wasFirstNetwork) {
if (DBG) log("Other network available for type " + type +
", sending connected broadcast");
final NetworkAgentInfo replacement = list.get(0);
- maybeLogBroadcast(replacement, false, type, isDefaultNetwork(replacement));
- sendLegacyNetworkBroadcast(replacement, false, type);
+ maybeLogBroadcast(replacement, state, type, isDefaultNetwork(replacement));
+ sendLegacyNetworkBroadcast(replacement, state, type);
}
}
@@ -560,6 +552,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ // send out another legacy broadcast - currently only used for suspend/unsuspend
+ // toggle
+ public void update(NetworkAgentInfo nai) {
+ final boolean isDefault = isDefaultNetwork(nai);
+ final DetailedState state = nai.networkInfo.getDetailedState();
+ for (int type = 0; type < mTypeLists.length; type++) {
+ final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
+ final boolean isFirst = (list != null && list.size() > 0 && nai == list.get(0));
+ if (isFirst || isDefault) {
+ maybeLogBroadcast(nai, state, type, isDefault);
+ sendLegacyNetworkBroadcast(nai, state, type);
+ }
+ }
+ }
+
private String naiToString(NetworkAgentInfo nai) {
String name = (nai != null) ? nai.name() : "null";
String state = (nai.networkInfo != null) ?
@@ -873,7 +880,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
Network network = null;
String subscriberId = null;
- NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ NetworkAgentInfo nai = getDefaultNetwork();
final Network[] networks = getVpnUnderlyingNetworks(uid);
if (networks != null) {
@@ -1778,7 +1785,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println();
pw.println();
- NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ final NetworkAgentInfo defaultNai = getDefaultNetwork();
pw.print("Active default network: ");
if (defaultNai == null) {
pw.println("none");
@@ -1903,8 +1910,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
Slog.wtf(TAG, "BUG: " + nai + " has stateful capability.");
}
- updateCapabilities(nai, networkCapabilities,
- NascentState.NOT_JUST_VALIDATED);
+ updateCapabilities(nai, networkCapabilities);
}
break;
}
@@ -1994,11 +2000,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log(nai.name() + " validation " + (valid ? " passed" : "failed"));
if (valid != nai.lastValidated) {
final int oldScore = nai.getCurrentScore();
- final NascentState nascent = (valid && !nai.everValidated) ?
- NascentState.JUST_VALIDATED : NascentState.NOT_JUST_VALIDATED;
nai.lastValidated = valid;
nai.everValidated |= valid;
- updateCapabilities(nai, nai.networkCapabilities, nascent);
+ updateCapabilities(nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
}
@@ -2029,8 +2033,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
- updateCapabilities(nai, nai.networkCapabilities,
- NascentState.NOT_JUST_VALIDATED);
+ updateCapabilities(nai, nai.networkCapabilities);
}
if (!visible) {
setProvNotificationVisibleIntent(false, netId, null, 0, null, null, false);
@@ -2049,17 +2052,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void linger(NetworkAgentInfo nai) {
+ nai.lingering = true;
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
+ }
+
// Cancel any lingering so the linger timeout doesn't teardown a network.
// This should be called when a network begins satisfying a NetworkRequest.
// Note: depending on what state the NetworkMonitor is in (e.g.,
// if it's awaiting captive portal login, or if validation failed), this
// may trigger a re-evaluation of the network.
private void unlinger(NetworkAgentInfo nai) {
- if (VDBG) log("Canceling linger of " + nai.name());
- // If network has never been validated, it cannot have been lingered, so don't bother
- // needlessly triggering a re-evaluation.
- if (!nai.everValidated) return;
nai.networkLingered.clear();
+ if (!nai.lingering) return;
+ nai.lingering = false;
+ if (VDBG) log("Canceling linger of " + nai.name());
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
}
@@ -2130,33 +2138,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
// available until we've told netd to delete it below.
mNetworkForNetId.remove(nai.network.netId);
}
- // Since we've lost the network, go through all the requests that
- // it was satisfying and see if any other factory can satisfy them.
- // TODO: This logic may be better replaced with a call to rematchAllNetworksAndRequests
- final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
+ // Remove all previously satisfied requests.
for (int i = 0; i < nai.networkRequests.size(); i++) {
NetworkRequest request = nai.networkRequests.valueAt(i);
NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- if (DBG) {
- log("Checking for replacement network to handle request " + request );
- }
mNetworkForRequestId.remove(request.requestId);
sendUpdatedScoreToFactories(request, 0);
- NetworkAgentInfo alternative = null;
- for (NetworkAgentInfo existing : mNetworkAgentInfos.values()) {
- if (existing.satisfies(request) &&
- (alternative == null ||
- alternative.getCurrentScore() < existing.getCurrentScore())) {
- alternative = existing;
- }
- }
- if (alternative != null) {
- if (DBG) log(" found replacement in " + alternative.name());
- if (!toActivate.contains(alternative)) {
- toActivate.add(alternative);
- }
- }
}
}
if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
@@ -2165,11 +2153,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
requestNetworkTransitionWakelock(nai.name());
}
mLegacyTypeTracker.remove(nai, wasDefault);
- for (NetworkAgentInfo networkToActivate : toActivate) {
- unlinger(networkToActivate);
- rematchNetworkAndRequests(networkToActivate, NascentState.NOT_JUST_VALIDATED,
- ReapUnvalidatedNetworks.DONT_REAP);
- }
+ rematchAllNetworksAndRequests(null, 0);
if (nai.created) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
@@ -2223,49 +2207,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
mNetworkRequests.put(nri.request, nri);
-
- // TODO: This logic may be better replaced with a call to rematchNetworkAndRequests
-
- // Check for the best currently alive network that satisfies this request
- NetworkAgentInfo bestNetwork = null;
- for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
- if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
- if (network.satisfies(nri.request)) {
- if (DBG) log("apparently satisfied. currentScore=" + network.getCurrentScore());
- if (!nri.isRequest) {
- // Not setting bestNetwork here as a listening NetworkRequest may be
- // satisfied by multiple Networks. Instead the request is added to
- // each satisfying Network and notified about each.
- if (!network.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + network.name() + " already has " + nri.request);
- }
- notifyNetworkCallback(network, nri);
- } else if (bestNetwork == null ||
- bestNetwork.getCurrentScore() < network.getCurrentScore()) {
- bestNetwork = network;
- }
- }
- }
- if (bestNetwork != null) {
- if (DBG) log("using " + bestNetwork.name());
- unlinger(bestNetwork);
- if (!bestNetwork.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + bestNetwork.name() + " already has " + nri.request);
- }
- mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
- notifyNetworkCallback(bestNetwork, nri);
- if (nri.request.legacyType != TYPE_NONE) {
- mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
- }
- }
-
- if (nri.isRequest) {
- if (DBG) log("sending new NetworkRequest to factories");
- final int score = bestNetwork == null ? 0 : bestNetwork.getCurrentScore();
- for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
- 0, nri.request);
- }
+ rematchAllNetworksAndRequests(null, 0);
+ if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) {
+ sendUpdatedScoreToFactories(nri.request, 0);
}
}
@@ -2278,43 +2222,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Is nai unneeded by all NetworkRequests (and should be disconnected)?
- // For validated Networks this is simply whether it is satsifying any NetworkRequests.
- // For unvalidated Networks this is whether it is satsifying any NetworkRequests or
- // were it to become validated, would it have a chance of satisfying any NetworkRequests.
+ // This is whether it is satisfying any NetworkRequests or were it to become validated,
+ // would it have a chance of satisfying any NetworkRequests.
private boolean unneeded(NetworkAgentInfo nai) {
- if (!nai.created || nai.isVPN()) return false;
- boolean unneeded = true;
- if (nai.everValidated) {
- for (int i = 0; i < nai.networkRequests.size() && unneeded; i++) {
- final NetworkRequest nr = nai.networkRequests.valueAt(i);
- try {
- if (isRequest(nr)) unneeded = false;
- } catch (Exception e) {
- loge("Request " + nr + " not found in mNetworkRequests.");
- loge(" it came from request list of " + nai.name());
- }
- }
- } else {
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- // If this Network is already the highest scoring Network for a request, or if
- // there is hope for it to become one if it validated, then it is needed.
- if (nri.isRequest && nai.satisfies(nri.request) &&
- (nai.networkRequests.get(nri.request.requestId) != null ||
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satsifying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
- nai.getCurrentScoreAsValidated())) {
- unneeded = false;
- break;
- }
+ if (!nai.created || nai.isVPN() || nai.lingering) return false;
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ // If this Network is already the highest scoring Network for a request, or if
+ // there is hope for it to become one if it validated, then it is needed.
+ if (nri.isRequest && nai.satisfies(nri.request) &&
+ (nai.networkRequests.get(nri.request.requestId) != null ||
+ // Note that this catches two important cases:
+ // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+ // is currently satisfying the request. This is desirable when
+ // cellular ends up validating but WiFi does not.
+ // 2. Unvalidated WiFi will not be reaped when validated cellular
+ // is currently satsifying the request. This is desirable when
+ // WiFi ends up validating and out scoring cellular.
+ mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
+ nai.getCurrentScoreAsValidated())) {
+ return false;
}
}
- return unneeded;
+ return true;
}
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
@@ -2424,7 +2353,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (accept != nai.networkMisc.acceptUnvalidated) {
int oldScore = nai.getCurrentScore();
nai.networkMisc.acceptUnvalidated = accept;
- rematchAllNetworksAndRequests(nai, oldScore, NascentState.NOT_JUST_VALIDATED);
+ rematchAllNetworksAndRequests(nai, oldScore);
sendUpdatedScoreToFactories(nai);
}
@@ -2733,16 +2662,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- public void captivePortalAppResponse(Network network, int response, String actionToken) {
- if (response == ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS) {
- enforceConnectivityInternalPermission();
- }
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return;
- nai.networkMonitor.sendMessage(NetworkMonitor.CMD_CAPTIVE_PORTAL_APP_FINISHED, response, 0,
- actionToken);
- }
-
private ProxyInfo getDefaultProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
@@ -3112,11 +3031,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
* are checked in Vpn class.
*/
@Override
- public LegacyVpnInfo getLegacyVpnInfo() {
+ public LegacyVpnInfo getLegacyVpnInfo(int userId) {
+ enforceCrossUserPermission(userId);
throwIfLockdownEnabled();
- int user = UserHandle.getUserId(Binder.getCallingUid());
synchronized(mVpns) {
- return mVpns.get(user).getLegacyVpnInfo();
+ return mVpns.get(userId).getLegacyVpnInfo();
}
}
@@ -4033,7 +3952,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} catch (Exception e) {
loge("Exception in setDnsServersForNetwork: " + e);
}
- NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ final NetworkAgentInfo defaultNai = getDefaultNetwork();
if (defaultNai != null && defaultNai.network.netId == netId) {
setDefaultDnsSystemProperties(dnses);
}
@@ -4068,31 +3987,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
* augmented with any stateful capabilities implied from {@code networkAgent}
* (e.g., validated status and captive portal status).
*
- * @param networkAgent the network having its capabilities updated.
+ * @param nai the network having its capabilities updated.
* @param networkCapabilities the new network capabilities.
- * @param nascent indicates whether {@code networkAgent} was validated
- * (i.e. had everValidated set for the first time) immediately prior to this call.
*/
- private void updateCapabilities(NetworkAgentInfo networkAgent,
- NetworkCapabilities networkCapabilities, NascentState nascent) {
+ private void updateCapabilities(NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
// Don't modify caller's NetworkCapabilities.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- if (networkAgent.lastValidated) {
+ if (nai.lastValidated) {
networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
} else {
networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
}
- if (networkAgent.lastCaptivePortalDetected) {
+ if (nai.lastCaptivePortalDetected) {
networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
} else {
networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
}
- if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
- synchronized (networkAgent) {
- networkAgent.networkCapabilities = networkCapabilities;
+ if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) {
+ final int oldScore = nai.getCurrentScore();
+ synchronized (nai) {
+ nai.networkCapabilities = networkCapabilities;
}
- rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore(), nascent);
- notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ rematchAllNetworksAndRequests(nai, oldScore);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
}
@@ -4234,7 +4151,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// one or more NetworkRequests, or if it is a VPN.
//
// - Tears down newNetwork if it just became validated
- // (i.e. nascent==JUST_VALIDATED) but turns out to be unneeded.
+ // but turns out to be unneeded.
//
// - If reapUnvalidatedNetworks==REAP, tears down unvalidated
// networks that have no chance (i.e. even if validated)
@@ -4247,17 +4164,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
// as it performs better by a factor of the number of Networks.
//
// @param newNetwork is the network to be matched against NetworkRequests.
- // @param nascent indicates if newNetwork just became validated, in which case it should be
- // torn down if unneeded.
// @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
// performed to tear down unvalidated networks that have no chance (i.e. even if
// validated) of becoming the highest scoring network.
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, NascentState nascent,
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,
ReapUnvalidatedNetworks reapUnvalidatedNetworks) {
if (!newNetwork.created) return;
- if (nascent == NascentState.JUST_VALIDATED && !newNetwork.everValidated) {
- loge("ERROR: nascent network not validated.");
- }
boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
@@ -4270,7 +4182,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
if (newNetwork == currentNetwork) {
- if (DBG) {
+ if (VDBG) {
log("Network " + newNetwork.name() + " was already satisfying" +
" request " + nri.request.requestId + ". No change.");
}
@@ -4327,10 +4239,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Linger any networks that are no longer needed.
for (NetworkAgentInfo nai : affectedNetworks) {
- if (nai.everValidated && unneeded(nai)) {
- nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
+ if (nai.lingering) {
+ // Already lingered. Nothing to do. This can only happen if "nai" is in
+ // "affectedNetworks" twice. The reasoning being that to get added to
+ // "affectedNetworks", "nai" must have been satisfying a NetworkRequest
+ // (i.e. not lingered) so it could have only been lingered by this loop.
+ // unneeded(nai) will be false and we'll call unlinger() below which would
+ // be bad, so handle it here.
+ } else if (unneeded(nai)) {
+ linger(nai);
} else {
+ // Clear nai.networkLingered we might have added above.
unlinger(nai);
}
}
@@ -4364,7 +4283,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
oldDefaultNetwork, true);
}
- mDefaultInetConditionPublished = newNetwork.everValidated ? 100 : 0;
+ mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
notifyLockdownVpn(newNetwork);
}
@@ -4415,19 +4334,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (newNetwork.isVPN()) {
mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
}
- } else if (nascent == NascentState.JUST_VALIDATED) {
- // Only tear down newly validated networks here. Leave unvalidated to either become
- // validated (and get evaluated against peers, one losing here), or get reaped (see
- // reapUnvalidatedNetworks) if they have no chance of becoming the highest scoring
- // network. Networks that have been up for a while and are validated should be torn
- // down via the lingering process so communication on that network is given time to
- // wrap up.
- if (DBG) log("Validated network turns out to be unwanted. Tear it down.");
- teardownUnneededNetwork(newNetwork);
}
if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- if (!nai.everValidated && unneeded(nai)) {
+ if (unneeded(nai)) {
if (DBG) log("Reaping " + nai.name());
teardownUnneededNetwork(nai);
}
@@ -4446,10 +4356,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
* this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
* {@code changed} is {@code null}. This is because NetworkCapabilities influence a
* network's score.
- * @param nascent indicates if {@code changed} has just been validated.
*/
- private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore,
- NascentState nascent) {
+ private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
// TODO: This may get slow. The "changed" parameter is provided for future optimization
// to avoid the slowness. It is not simply enough to process just "changed", for
// example in the case where "changed"'s score decreases and another network should begin
@@ -4458,17 +4366,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Optimization: Only reprocess "changed" if its score improved. This is safe because it
// can only add more NetworkRequests satisfied by "changed", and this is exactly what
// rematchNetworkAndRequests() handles.
- if (changed != null &&
- (oldScore < changed.getCurrentScore() || nascent == NascentState.JUST_VALIDATED)) {
- rematchNetworkAndRequests(changed, nascent, ReapUnvalidatedNetworks.REAP);
+ if (changed != null && oldScore < changed.getCurrentScore()) {
+ rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP);
} else {
- for (Iterator i = mNetworkAgentInfos.values().iterator(); i.hasNext(); ) {
- rematchNetworkAndRequests((NetworkAgentInfo)i.next(),
- NascentState.NOT_JUST_VALIDATED,
+ final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
+ new NetworkAgentInfo[mNetworkAgentInfos.size()]);
+ // Rematch higher scoring networks first to prevent requests first matching a lower
+ // scoring network and then a higher scoring network, which could produce multiple
+ // callbacks and inadvertently unlinger networks.
+ Arrays.sort(nais);
+ for (NetworkAgentInfo nai : nais) {
+ rematchNetworkAndRequests(nai,
// Only reap the last time through the loop. Reaping before all rematching
// is complete could incorrectly teardown a network that hasn't yet been
// rematched.
- i.hasNext() ? ReapUnvalidatedNetworks.DONT_REAP
+ (nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP
: ReapUnvalidatedNetworks.REAP);
}
}
@@ -4502,6 +4414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
NetworkInfo.State state = newInfo.getState();
NetworkInfo oldInfo = null;
+ final int oldScore = networkAgent.getCurrentScore();
synchronized (networkAgent) {
oldInfo = networkAgent.networkInfo;
networkAgent.networkInfo = newInfo;
@@ -4555,13 +4468,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Consider network even though it is not yet validated.
- rematchNetworkAndRequests(networkAgent, NascentState.NOT_JUST_VALIDATED,
- ReapUnvalidatedNetworks.REAP);
+ rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP);
// This has to happen after matching the requests, because callbacks are just requests.
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
- } else if (state == NetworkInfo.State.DISCONNECTED ||
- state == NetworkInfo.State.SUSPENDED) {
+ } else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
synchronized (mProxyLock) {
@@ -4573,6 +4484,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
+ } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
+ state == NetworkInfo.State.SUSPENDED) {
+ // going into or coming out of SUSPEND: rescore and notify
+ if (networkAgent.getCurrentScore() != oldScore) {
+ rematchAllNetworksAndRequests(networkAgent, oldScore);
+ }
+ notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ?
+ ConnectivityManager.CALLBACK_SUSPENDED :
+ ConnectivityManager.CALLBACK_RESUMED));
+ mLegacyTypeTracker.update(networkAgent);
}
}
@@ -4587,7 +4508,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final int oldScore = nai.getCurrentScore();
nai.setCurrentScore(score);
- rematchAllNetworksAndRequests(nai, oldScore, NascentState.NOT_JUST_VALIDATED);
+ rematchAllNetworksAndRequests(nai, oldScore);
sendUpdatedScoreToFactories(nai);
}
@@ -4608,7 +4529,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
+ private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
// The NetworkInfo we actually send out has no bearing on the real
// state of affairs. For example, if the default connection is mobile,
// and a request for HIPRI has just gone away, we need to pretend that
@@ -4617,11 +4538,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
// and is still connected.
NetworkInfo info = new NetworkInfo(nai.networkInfo);
info.setType(type);
- if (connected) {
- info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo());
+ if (state != DetailedState.DISCONNECTED) {
+ info.setDetailedState(state, null, info.getExtraInfo());
sendConnectedBroadcast(info);
} else {
- info.setDetailedState(DetailedState.DISCONNECTED, info.getReason(), info.getExtraInfo());
+ info.setDetailedState(state, info.getReason(), info.getExtraInfo());
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
@@ -4637,7 +4558,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
NetworkAgentInfo newDefaultAgent = null;
if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
- newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ newDefaultAgent = getDefaultNetwork();
if (newDefaultAgent != null) {
intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
newDefaultAgent.networkInfo);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 25bd787..da552dd 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -59,6 +59,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -128,6 +129,7 @@ import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@@ -692,6 +694,15 @@ class MountService extends IMountService.Stub
}
private void waitForLatch(CountDownLatch latch, String condition) {
+ try {
+ waitForLatch(latch, condition, -1);
+ } catch (TimeoutException ignored) {
+ }
+ }
+
+ private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
+ throws TimeoutException {
+ final long startMillis = SystemClock.elapsedRealtime();
while (true) {
try {
if (latch.await(5000, TimeUnit.MILLISECONDS)) {
@@ -703,6 +714,10 @@ class MountService extends IMountService.Stub
} catch (InterruptedException e) {
Slog.w(TAG, "Interrupt while waiting for " + condition);
}
+ if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
+ throw new TimeoutException("Thread " + Thread.currentThread().getName()
+ + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
+ }
}
}
@@ -1645,10 +1660,12 @@ class MountService extends IMountService.Stub
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
try {
mConnector.execute("volume", "partition", diskId, "public");
+ waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
+ } catch (TimeoutException e) {
+ throw new IllegalStateException(e);
}
- waitForLatch(latch, "partitionPublic");
}
@Override
@@ -1660,10 +1677,12 @@ class MountService extends IMountService.Stub
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
try {
mConnector.execute("volume", "partition", diskId, "private");
+ waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
+ } catch (TimeoutException e) {
+ throw new IllegalStateException(e);
}
- waitForLatch(latch, "partitionPrivate");
}
@Override
@@ -1675,10 +1694,12 @@ class MountService extends IMountService.Stub
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
try {
mConnector.execute("volume", "partition", diskId, "mixed", ratio);
+ waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
+ } catch (TimeoutException e) {
+ throw new IllegalStateException(e);
}
- waitForLatch(latch, "partitionMixed");
}
@Override
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 4c9d7d3..ad5406c 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -90,6 +90,10 @@ public class SystemConfig {
// These are the app package names that should not allow IME switching.
final ArraySet<String> mFixedImeApps = new ArraySet<>();
+ // These are the package names of apps which should be in the 'always'
+ // URL-handling state upon factory reset.
+ final ArraySet<String> mLinkedApps = new ArraySet<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -127,6 +131,10 @@ public class SystemConfig {
return mFixedImeApps;
}
+ public ArraySet<String> getLinkedApps() {
+ return mLinkedApps;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -343,6 +351,16 @@ public class SystemConfig {
XmlUtils.skipCurrentTag(parser);
continue;
+ } else if ("app-link".equals(name)) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<app-link> without package in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else {
+ mLinkedApps.add(pkgname);
+ }
+ XmlUtils.skipCurrentTag(parser);
+
} else {
XmlUtils.skipCurrentTag(parser);
continue;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4217c59..6e94647 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -498,13 +498,11 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void run() {
Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
- synchronized (ActivityManagerService.this) {
- synchronized (this) {
- haveResult = true;
- notifyAll();
- }
- pendingAssistExtrasTimedOutLocked(this);
+ synchronized (this) {
+ haveResult = true;
+ notifyAll();
}
+ pendingAssistExtrasTimedOut(this);
}
}
@@ -1353,6 +1351,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int FOREGROUND_PROFILE_CHANGED_MSG = 53;
static final int DISPATCH_UIDS_CHANGED_MSG = 54;
static final int REPORT_TIME_TRACKER_MSG = 55;
+ static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2014,6 +2013,9 @@ public final class ActivityManagerService extends ActivityManagerNative
AppTimeTracker tracker = (AppTimeTracker)msg.obj;
tracker.deliverResult(mContext);
} break;
+ case REPORT_USER_SWITCH_COMPLETE_MSG: {
+ dispatchUserSwitchComplete(msg.arg1);
+ } break;
}
}
};
@@ -10749,9 +10751,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- void pendingAssistExtrasTimedOutLocked(PendingAssistExtras pae) {
- mPendingAssistExtras.remove(pae);
- if (pae.receiver != null) {
+ void pendingAssistExtrasTimedOut(PendingAssistExtras pae) {
+ IResultReceiver receiver;
+ synchronized (this) {
+ mPendingAssistExtras.remove(pae);
+ receiver = pae.receiver;
+ }
+ if (receiver != null) {
// Caller wants result sent back to them.
try {
pae.receiver.send(0, null);
@@ -19910,7 +19916,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- completeSwitchAndInitalize(uss, newUserId, true, false);
+ completeSwitchAndInitialize(uss, newUserId, true, false);
}
void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
@@ -19926,10 +19932,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
- completeSwitchAndInitalize(uss, newUserId, false, true);
+ completeSwitchAndInitialize(uss, newUserId, false, true);
}
- void completeSwitchAndInitalize(UserState uss, int newUserId,
+ void completeSwitchAndInitialize(UserState uss, int newUserId,
boolean clearInitializing, boolean clearSwitching) {
boolean unfrozen = false;
synchronized (this) {
@@ -19946,18 +19952,25 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (unfrozen) {
- final int N = mUserSwitchObservers.beginBroadcast();
- for (int i=0; i<N; i++) {
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
- } catch (RemoteException e) {
- }
- }
- mUserSwitchObservers.finishBroadcast();
+ mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
+ newUserId, 0));
}
stopGuestUserIfBackground();
}
+ /** Called on handler thread */
+ void dispatchUserSwitchComplete(int userId) {
+ final int observerCount = mUserSwitchObservers.beginBroadcast();
+ for (int i = 0; i < observerCount; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId);
+ } catch (RemoteException e) {
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
+ }
+
/**
* Stops the guest user if it has gone to the background.
*/
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 31cdcd5..8c3a950 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2963,7 +2963,6 @@ final class ActivityStack {
r.state = ActivityState.FINISHING;
if (mode == FINISH_IMMEDIATELY
- || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED)
|| prevState == ActivityState.STOPPED
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 51c6628..8a79430 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.content.Context;
import android.net.LinkProperties;
import android.net.Network;
@@ -31,14 +33,71 @@ import com.android.internal.util.AsyncChannel;
import com.android.server.connectivity.NetworkMonitor;
import java.util.ArrayList;
+import java.util.Comparator;
/**
* A bag class used by ConnectivityService for holding a collection of most recent
* information published by a particular NetworkAgent as well as the
* AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
- * interested in using it.
+ * interested in using it. Default sort order is descending by score.
*/
-public class NetworkAgentInfo {
+// States of a network:
+// --------------------
+// 1. registered, uncreated, disconnected, unvalidated
+// This state is entered when a NetworkFactory registers a NetworkAgent in any state except
+// the CONNECTED state.
+// 2. registered, uncreated, connected, unvalidated
+// This state is entered when a registered NetworkAgent transitions to the CONNECTED state
+// ConnectivityService will tell netd to create the network and immediately transition to
+// state #3.
+// 3. registered, created, connected, unvalidated
+// If this network can satsify the default NetworkRequest, then NetworkMonitor will
+// probe for Internet connectivity.
+// If this network cannot satisfy the default NetworkRequest, it will immediately be
+// transitioned to state #4.
+// A network may remain in this state if NetworkMonitor fails to find Internet connectivity,
+// for example:
+// a. a captive portal is present, or
+// b. a WiFi router whose Internet backhaul is down, or
+// c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator
+// or tunnel) but does not disconnect from the AP/cell tower, or
+// d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes.
+// 4. registered, created, connected, validated
+//
+// The device's default network connection:
+// ----------------------------------------
+// Networks in states #3 and #4 may be used as a device's default network connection if they
+// satisfy the default NetworkRequest.
+// A network, that satisfies the default NetworkRequest, in state #4 should always be chosen
+// in favor of a network, that satisfies the default NetworkRequest, in state #3.
+// When deciding between two networks, that both satisfy the default NetworkRequest, to select
+// for the default network connection, the one with the higher score should be chosen.
+//
+// When a network disconnects:
+// ---------------------------
+// If a network's transport disappears, for example:
+// a. WiFi turned off, or
+// b. cellular data turned off, or
+// c. airplane mode is turned on, or
+// d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range
+// of AP for an extended period of time, or switches to another AP without roaming)
+// then that network can transition from any state (#1-#4) to unregistered. This happens by
+// the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager.
+// ConnectivityService also tells netd to destroy the network.
+//
+// When ConnectivityService disconnects a network:
+// -----------------------------------------------
+// If a network has no chance of satisfying any requests (even if it were to become validated
+// and enter state #4), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
+// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been
+// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the
+// highest scoring network for any NetworkRequest, then there will be a 30s pause before
+// ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the
+// network is considered "lingering". This pause exists to allow network communication to be
+// wrapped up rather than abruptly terminated. During this pause if the network begins satisfying
+// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's
+// AsyncChannel, and the network is no longer considered "lingering".
+public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkInfo networkInfo;
// This Network object should always be used if possible, so as to encourage reuse of the
// enclosed socket factory and connection pool. Avoid creating other Network objects.
@@ -72,6 +131,13 @@ public class NetworkAgentInfo {
// Whether a captive portal was found during the last network validation attempt.
public boolean lastCaptivePortalDetected;
+ // Indicates whether the network is lingering. Networks are lingered when they become unneeded
+ // as a result of their NetworkRequests being satisfied by a different network, so as to allow
+ // communication to wrap up before the network is taken down. This usually only happens to the
+ // default network. Lingering ends with either the linger timeout expiring and the network
+ // being taken down, or the network satisfying a request again.
+ public boolean lingering;
+
// This represents the last score received from the NetworkAgent.
private int currentScore;
// Penalty applied to scores of Networks that have not been validated.
@@ -148,7 +214,12 @@ public class NetworkAgentInfo {
}
int score = currentScore;
- if (!everValidated && !pretendValidated) score -= UNVALIDATED_SCORE_PENALTY;
+ // Use NET_CAPABILITY_VALIDATED here instead of lastValidated, this allows
+ // ConnectivityService.updateCapabilities() to compute the old score prior to updating
+ // networkCapabilities (with a potentially different validated state).
+ if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) && !pretendValidated) {
+ score -= UNVALIDATED_SCORE_PENALTY;
+ }
if (score < 0) score = 0;
return score;
}
@@ -175,7 +246,7 @@ public class NetworkAgentInfo {
linkProperties + "} nc{" +
networkCapabilities + "} Score{" + getCurrentScore() + "} " +
"everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " +
- "created{" + created + "} " +
+ "created{" + created + "} lingering{" + lingering + "} " +
"explicitlySelected{" + networkMisc.explicitlySelected + "} " +
"acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
"everCaptivePortalDetected{" + everCaptivePortalDetected + "} " +
@@ -188,4 +259,10 @@ public class NetworkAgentInfo {
networkInfo.getSubtypeName() + ") - " +
(network == null ? "null" : network.toString()) + "]";
}
+
+ // Enables sorting in descending order of score.
+ @Override
+ public int compareTo(NetworkAgentInfo other) {
+ return other.getCurrentScore() - getCurrentScore();
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index e472928..2633939 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
+import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
+import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
+
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -23,7 +27,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.CaptivePortal;
import android.net.ConnectivityManager;
+import android.net.ICaptivePortal;
import android.net.NetworkRequest;
import android.net.ProxyInfo;
import android.net.TrafficStats;
@@ -160,12 +166,12 @@ public class NetworkMonitor extends StateMachine {
/**
* Message to self indicating captive portal app finished.
- * arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_DISMISSED,
- * CAPTIVE_PORTAL_APP_RETURN_UNWANTED,
- * CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS
+ * arg1 = one of: APP_RETURN_DISMISSED,
+ * APP_RETURN_UNWANTED,
+ * APP_RETURN_WANTED_AS_IS
* obj = mCaptivePortalLoggedInResponseToken as String
*/
- public static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
+ private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
/**
* Request ConnectivityService display provisioning notification.
@@ -234,7 +240,6 @@ public class NetworkMonitor extends StateMachine {
private final State mLingeringState = new LingeringState();
private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
- private String mCaptivePortalLoggedInResponseToken = null;
private final LocalLog validationLogs = new LocalLog(20); // 20 lines
@@ -268,8 +273,6 @@ public class NetworkMonitor extends StateMachine {
mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
- mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong());
-
start();
}
@@ -314,22 +317,18 @@ public class NetworkMonitor extends StateMachine {
transitionTo(mEvaluatingState);
return HANDLED;
case CMD_CAPTIVE_PORTAL_APP_FINISHED:
- if (!mCaptivePortalLoggedInResponseToken.equals((String)message.obj))
- return HANDLED;
log("CaptivePortal App responded with " + message.arg1);
- // Previous token was sent out, come up with a new one.
- mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong());
switch (message.arg1) {
- case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_DISMISSED:
+ case APP_RETURN_DISMISSED:
sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */, 0);
break;
- case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS:
+ case APP_RETURN_WANTED_AS_IS:
mDontDisplaySigninNotification = true;
// TODO: Distinguish this from a network that actually validates.
// Displaying the "!" on the system UI icon may still be a good idea.
transitionTo(mValidatedState);
break;
- case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_UNWANTED:
+ case APP_RETURN_UNWANTED:
mDontDisplaySigninNotification = true;
mUserDoesNotWant = true;
mConnectivityServiceHandler.sendMessage(obtainMessage(
@@ -380,8 +379,18 @@ public class NetworkMonitor extends StateMachine {
final Intent intent = new Intent(
ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mNetworkAgentInfo.network);
- intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN,
- mCaptivePortalLoggedInResponseToken);
+ intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
+ new CaptivePortal(new ICaptivePortal.Stub() {
+ @Override
+ public void appResponse(int response) {
+ if (response == APP_RETURN_WANTED_AS_IS) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "CaptivePortal");
+ }
+ sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
+ }
+ }));
intent.setFlags(
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -576,9 +585,12 @@ public class NetworkMonitor extends StateMachine {
switch (message.what) {
case CMD_NETWORK_CONNECTED:
log("Unlingered");
- // Go straight to active as we've already evaluated.
- transitionTo(mValidatedState);
- return HANDLED;
+ // If already validated, go straight to validated state.
+ if (mNetworkAgentInfo.lastValidated) {
+ transitionTo(mValidatedState);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
case CMD_LINGER_EXPIRED:
if (message.arg1 != mLingerToken)
return HANDLED;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 493471b..3c35f5e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -33,6 +33,7 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.io.UnsupportedEncodingException;
import java.util.List;
+import java.util.Locale;
/**
* Represent a logical device of type Playback residing in Android system.
@@ -317,6 +318,13 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
try {
String iso3Language = new String(message.getParams(), 0, 3, "US-ASCII");
+ Locale currentLocale = mService.getContext().getResources().getConfiguration().locale;
+ if (currentLocale.getISO3Language().equals(iso3Language)) {
+ // Do not switch language if the new language is the same as the current one.
+ // This helps avoid accidental country variant switching from en_US to en_AU
+ // due to the limitation of CEC. See the warning below.
+ return true;
+ }
// Don't use Locale.getAvailableLocales() since it returns a locale
// which is not available on Settings.
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 8e3334f..7a74729 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -262,7 +262,6 @@ final class DefaultPermissionGrantPolicy {
&& doesPackageSupportRuntimePermissions(setupPackage)) {
grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(setupPackage, SETTINGS_PERMISSIONS, userId);
}
// Camera
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 40e7411..6da2055 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -477,6 +477,13 @@ public class PackageManagerService extends IPackageManager.Stub {
final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
+ /**
+ * Tracks new system packages [receiving in an OTA] that we expect to
+ * find updated user-installed versions. Keys are package name, values
+ * are package location.
+ */
+ final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+
final Settings mSettings;
boolean mRestoredSettings;
@@ -709,7 +716,8 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "Updating IntentFilterVerificationInfo for verificationId:" + verificationId);
+ "Updating IntentFilterVerificationInfo for package " + packageName
+ +" verificationId:" + verificationId);
synchronized (mPackages) {
if (verified) {
@@ -794,8 +802,6 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
filter.hasDataScheme(IntentFilter.SCHEME_HTTPS);
if (!hasHTTPorHTTPS) {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "IntentFilter does not contain any HTTP or HTTPS data scheme");
return false;
}
return true;
@@ -2054,7 +2060,6 @@ public class PackageManagerService extends IPackageManager.Stub {
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
- final ArrayMap<String, File> expectingBetter = new ArrayMap<>();
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
@@ -2087,7 +2092,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
removePackageLI(ps, true);
- expectingBetter.put(ps.name, ps.codePath);
+ mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
@@ -2161,10 +2166,10 @@ public class PackageManagerService extends IPackageManager.Stub {
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
- for (int i = 0; i < expectingBetter.size(); i++) {
- final String packageName = expectingBetter.keyAt(i);
+ for (int i = 0; i < mExpectingBetter.size(); i++) {
+ final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
- final File scanFile = expectingBetter.valueAt(i);
+ final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
@@ -2199,6 +2204,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
+ mExpectingBetter.clear();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -2245,6 +2251,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!mRestoredSettings && !onlyCore) {
mSettings.applyDefaultPreferredAppsLPw(this, UserHandle.USER_OWNER);
applyFactoryDefaultBrowserLPw(UserHandle.USER_OWNER);
+ primeDomainVerificationsLPw(UserHandle.USER_OWNER);
}
// If this is first boot after an OTA, and a normal boot, then
@@ -2259,7 +2266,6 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.mFingerprint = Build.FINGERPRINT;
}
- primeDomainVerificationsLPw();
checkDefaultBrowser();
// All the changes are done during package scanning.
@@ -2412,54 +2418,56 @@ public class PackageManagerService extends IPackageManager.Stub {
return verifierComponentName;
}
- private void primeDomainVerificationsLPw() {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Start priming domain verifications");
- boolean updated = false;
- ArraySet<String> allHostsSet = new ArraySet<>();
- for (PackageParser.Package pkg : mPackages.values()) {
- final String packageName = pkg.packageName;
- if (!hasDomainURLs(pkg)) {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "No priming domain verifications for " +
- "package with no domain URLs: " + packageName);
- continue;
- }
- if (!pkg.isSystemApp()) {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "No priming domain verifications for a non system package : " +
- packageName);
- continue;
- }
- for (PackageParser.Activity a : pkg.activities) {
- for (ActivityIntentInfo filter : a.intents) {
- if (hasValidDomains(filter)) {
- allHostsSet.addAll(filter.getHostsList());
+ private void primeDomainVerificationsLPw(int userId) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Priming domain verifications in user " + userId);
+ }
+
+ SystemConfig systemConfig = SystemConfig.getInstance();
+ ArraySet<String> packages = systemConfig.getLinkedApps();
+ ArraySet<String> domains = new ArraySet<String>();
+
+ for (String packageName : packages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null) {
+ if (!pkg.isSystemApp()) {
+ Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>");
+ continue;
+ }
+
+ domains.clear();
+ for (PackageParser.Activity a : pkg.activities) {
+ for (ActivityIntentInfo filter : a.intents) {
+ if (hasValidDomains(filter)) {
+ domains.addAll(filter.getHostsList());
+ }
}
}
+
+ if (domains.size() > 0) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.v(TAG, " + " + packageName);
+ }
+ // 'Undefined' in the global IntentFilterVerificationInfo, i.e. the usual
+ // state w.r.t. the formal app-linkage "no verification attempted" state;
+ // and then 'always' in the per-user state actually used for intent resolution.
+ final IntentFilterVerificationInfo ivi;
+ ivi = mSettings.createIntentFilterVerificationIfNeededLPw(packageName,
+ new ArrayList<String>(domains));
+ ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+ mSettings.updateIntentFilterVerificationStatusLPw(packageName,
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, userId);
+ } else {
+ Slog.w(TAG, "Sysconfig <app-link> package '" + packageName
+ + "' does not handle web links");
+ }
+ } else {
+ Slog.w(TAG, "Unknown package '" + packageName + "' in sysconfig <app-link>");
}
- if (allHostsSet.size() == 0) {
- allHostsSet.add("*");
- }
- ArrayList<String> allHostsList = new ArrayList<>(allHostsSet);
- IntentFilterVerificationInfo ivi =
- mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHostsList);
- if (ivi != null) {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "Priming domain verifications for package: " + packageName +
- " with hosts:" + ivi.getDomainsString());
- ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
- updated = true;
- }
- else {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "No priming domain verifications for package: " + packageName);
- }
- allHostsSet.clear();
- }
- if (updated) {
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
- "Will need to write primed domain verifications");
}
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "End priming domain verifications");
+
+ scheduleWritePackageRestrictionsLocked(userId);
+ scheduleWriteSettingsLocked();
}
private void applyFactoryDefaultBrowserLPw(int userId) {
@@ -2467,7 +2475,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// with a product-specific overlay used for vendor customization.
String browserPkg = mContext.getResources().getString(
com.android.internal.R.string.default_browser);
- if (browserPkg != null) {
+ if (!TextUtils.isEmpty(browserPkg)) {
// non-empty string => required to be a known package
PackageSetting ps = mSettings.mPackages.get(browserPkg);
if (ps == null) {
@@ -3146,6 +3154,28 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.PERMISSION_DENIED;
}
+ @Override
+ public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId) {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "isPermissionRevokedByPolicy for user " + userId);
+ }
+
+ if (checkPermission(permission, packageName, userId)
+ == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int flags = getPermissionFlags(permission, packageName, userId);
+ return (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
/**
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
* or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
@@ -3428,8 +3458,12 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
- if (READ_EXTERNAL_STORAGE.equals(name)
- || WRITE_EXTERNAL_STORAGE.equals(name)) {
+ // Only need to do this if user is initialized. Otherwise it's a new user
+ // and there are no processes running as the user yet and there's no need
+ // to make an expensive call to remount processes for the changed permissions.
+ if ((READ_EXTERNAL_STORAGE.equals(name)
+ || WRITE_EXTERNAL_STORAGE.equals(name))
+ && sUserManager.isInitialized(userId)) {
final long token = Binder.clearCallingIdentity();
try {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
@@ -5635,7 +5669,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (pkg.mVersionCode <= ps.versionCode) {
// The system package has been updated and the code path does not match
// Ignore entry. Skip it.
- Slog.i(TAG, "Package " + ps.name + " at " + scanFile
+ if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + scanFile
+ " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
if (!updatedPkg.codePath.equals(scanFile)) {
@@ -5648,7 +5682,10 @@ public class PackageManagerService extends IPackageManager.Stub {
updatedPkg.resourcePathString = scanFile.toString();
}
updatedPkg.pkg = pkg;
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Package " + ps.name + " at " + scanFile
+ + " ignored: updated version " + ps.versionCode
+ + " better than this " + pkg.mVersionCode);
} else {
// The current app on the system partition is better than
// what we have updated to on the data partition; switch
@@ -6431,20 +6468,29 @@ public class PackageManagerService extends IPackageManager.Stub {
// scanned APK is both already known and at the path previously established
// for it. Previously unknown packages we pick up normally, but if we have an
// a priori expectation about this package's install presence, enforce it.
+ // With a singular exception for new system packages. When an OTA contains
+ // a new system package, we allow the codepath to change from a system location
+ // to the user-installed location. If we don't allow this change, any newer,
+ // user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
- if (known != null) {
- if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Examining " + pkg.codePath
- + " and requiring known paths " + known.codePathString
- + " & " + known.resourcePathString);
- }
- if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
- || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
- throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
- "Application package " + pkg.packageName
- + " found at " + pkg.applicationInfo.getCodePath()
- + " but expected at " + known.codePathString + "; ignoring.");
+ if (mExpectingBetter.containsKey(pkg.packageName)) {
+ logCriticalInfo(Log.WARN,
+ "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
+ } else {
+ PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
+ if (known != null) {
+ if (DEBUG_PACKAGE_SCANNING) {
+ Log.d(TAG, "Examining " + pkg.codePath
+ + " and requiring known paths " + known.codePathString
+ + " & " + known.resourcePathString);
+ }
+ if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
+ || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
+ throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
+ "Application package " + pkg.packageName
+ + " found at " + pkg.applicationInfo.getCodePath()
+ + " but expected at " + known.codePathString + "; ignoring.");
+ }
}
}
}
@@ -13694,6 +13740,7 @@ public class PackageManagerService extends IPackageManager.Stub {
clearPackagePreferredActivitiesLPw(null, userId);
mSettings.applyDefaultPreferredAppsLPw(this, userId);
applyFactoryDefaultBrowserLPw(userId);
+ primeDomainVerificationsLPw(userId);
scheduleWritePackageRestrictionsLocked(userId);
}
@@ -14808,7 +14855,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println();
int count = mSettings.mPackages.size();
if (count == 0) {
- pw.println("No domain preferred apps!");
+ pw.println("No applications!");
pw.println();
} else {
final String prefix = " ";
@@ -14817,45 +14864,41 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println("No domain preferred apps!");
pw.println();
} else {
- pw.println("Domain preferred apps status:");
+ pw.println("App verification status:");
pw.println();
count = 0;
for (PackageSetting ps : allPackageSettings) {
IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
if (ivi == null || ivi.getPackageName() == null) continue;
- pw.println(prefix + "Package Name: " + ivi.getPackageName());
+ pw.println(prefix + "Package: " + ivi.getPackageName());
pw.println(prefix + "Domains: " + ivi.getDomainsString());
- pw.println(prefix + "Status: " + ivi.getStatusString());
+ pw.println(prefix + "Status: " + ivi.getStatusString());
pw.println();
count++;
}
if (count == 0) {
- pw.println(prefix + "No domain preferred app status!");
+ pw.println(prefix + "No app verification established.");
pw.println();
}
for (int userId : sUserManager.getUserIds()) {
- pw.println("Domain preferred apps for User " + userId + ":");
+ pw.println("App linkages for user " + userId + ":");
pw.println();
count = 0;
for (PackageSetting ps : allPackageSettings) {
- IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
- if (ivi == null || ivi.getPackageName() == null) {
- continue;
- }
final int status = ps.getDomainVerificationStatusForUser(userId);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
continue;
}
- pw.println(prefix + "Package Name: " + ivi.getPackageName());
- pw.println(prefix + "Domains: " + ivi.getDomainsString());
+ pw.println(prefix + "Package: " + ps.name);
+ pw.println(prefix + "Domains: " + dumpDomainString(ps.name));
String statusStr = IntentFilterVerificationInfo.
getStatusStringFromValue(status);
- pw.println(prefix + "Status: " + statusStr);
+ pw.println(prefix + "Status: " + statusStr);
pw.println();
count++;
}
if (count == 0) {
- pw.println(prefix + "No domain preferred apps!");
+ pw.println(prefix + "No configured app linkages.");
pw.println();
}
}
@@ -14977,6 +15020,35 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private String dumpDomainString(String packageName) {
+ List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName);
+ List<IntentFilter> filters = getAllIntentFilters(packageName);
+
+ ArraySet<String> result = new ArraySet<>();
+ if (iviList.size() > 0) {
+ for (IntentFilterVerificationInfo ivi : iviList) {
+ for (String host : ivi.getDomains()) {
+ result.add(host);
+ }
+ }
+ }
+ if (filters != null && filters.size() > 0) {
+ for (IntentFilter filter : filters) {
+ if (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+ result.addAll(filter.getHostsList());
+ }
+ }
+ }
+
+ StringBuilder sb = new StringBuilder(result.size() * 16);
+ for (String domain : result) {
+ if (sb.length() > 0) sb.append(" ");
+ sb.append(domain);
+ }
+ return sb.toString();
+ }
+
// ------- apps on sdcard specific code -------
static final boolean DEBUG_SD_INSTALL = false;
@@ -15896,19 +15968,12 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstaller.createUserConfig(userHandle);
mSettings.createNewUserLILPw(this, mInstaller, userHandle);
applyFactoryDefaultBrowserLPw(userHandle);
+ primeDomainVerificationsLPw(userHandle);
}
}
- void newUserCreatedLILPw(final int userHandle) {
- // We cannot grant the default permissions with a lock held as
- // we query providers from other components for default handlers
- // such as enabled IMEs, etc.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mDefaultPermissionPolicy.grantDefaultPermissions(userHandle);
- }
- });
+ void newUserCreated(final int userHandle) {
+ mDefaultPermissionPolicy.grantDefaultPermissions(userHandle);
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1a79b4e..23cb767 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1220,6 +1220,7 @@ public class UserManagerService extends IUserManager.Stub {
final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
final long ident = Binder.clearCallingIdentity();
UserInfo userInfo = null;
+ final int userId;
try {
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
@@ -1240,7 +1241,7 @@ public class UserManagerService extends IUserManager.Stub {
if (isGuest && findCurrentGuestUserLocked() != null) {
return null;
}
- int userId = getNextAvailableIdLocked();
+ userId = getNextAvailableIdLocked();
userInfo = new UserInfo(userId, name, null, flags);
userInfo.serialNumber = mNextSerialNumber++;
long now = System.currentTimeMillis();
@@ -1274,9 +1275,9 @@ public class UserManagerService extends IUserManager.Stub {
updateUserIdsLocked();
Bundle restrictions = new Bundle();
mUserRestrictions.append(userId, restrictions);
- mPm.newUserCreatedLILPw(userId);
}
}
+ mPm.newUserCreated(userId);
if (userInfo != null) {
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
@@ -2015,4 +2016,12 @@ public class UserManagerService extends IUserManager.Stub {
}
}
}
+
+ /**
+ * @param userId
+ * @return whether the user has been initialized yet
+ */
+ boolean isInitialized(int userId) {
+ return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0;
+ }
}
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 5877b3e..9095f57 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -155,7 +155,7 @@ public class BarController {
}
private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
- if (win.hasDrawnLw()) {
+ if (win.isDrawnLw()) {
final boolean vis = win.isVisibleLw();
final boolean anim = win.isAnimatingLw();
if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
@@ -198,7 +198,7 @@ public class BarController {
}
public boolean checkHiddenLw() {
- if (mWin != null && mWin.hasDrawnLw()) {
+ if (mWin != null && mWin.isDrawnLw()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3393d7d..87efb8d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3048,14 +3048,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private void launchAssistAction() {
- launchAssistAction(null, Integer.MIN_VALUE);
- }
-
- private void launchAssistAction(String hint) {
- launchAssistAction(hint, Integer.MIN_VALUE);
- }
-
private void launchAssistAction(String hint, int deviceId) {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
Bundle args = null;
@@ -3063,8 +3055,29 @@ public class PhoneWindowManager implements WindowManagerPolicy {
args = new Bundle();
args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId);
}
- ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
- .launchAssistAction(hint, UserHandle.myUserId(), args);
+ if ((mContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
+ // On TV, use legacy handling until assistants are implemented in the proper way.
+ ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+ .launchLegacyAssist(hint, UserHandle.myUserId(), args);
+ } else {
+ try {
+ if (hint != null) {
+ if (args == null) {
+ args = new Bundle();
+ }
+ args.putBoolean(hint, true);
+ }
+ IStatusBarService statusbar = getStatusBarService();
+ if (statusbar != null) {
+ statusbar.startAssist(args);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when starting assist", e);
+ // re-acquire status bar service next time it is needed.
+ mStatusBarService = null;
+ }
+ }
}
private void startActivityAsUser(Intent intent, UserHandle handle) {
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index dd2286f..04b2f60 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -45,6 +45,8 @@ import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -240,16 +242,24 @@ public class SearchManagerService extends ISearchManager.Stub {
}
@Override
- public ComponentName getAssistIntent(int userHandle) {
+ public void launchAssist(Bundle args) {
+ StatusBarManagerInternal statusBarManager =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ if (statusBarManager != null) {
+ statusBarManager.startAssist(args);
+ }
+ }
+
+ private ComponentName getLegacyAssistComponent(int userHandle) {
try {
userHandle = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userHandle, true, false, "getAssistIntent", null);
+ Binder.getCallingUid(), userHandle, true, false, "getLegacyAssistComponent", null);
IPackageManager pm = AppGlobals.getPackageManager();
Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
ResolveInfo info =
pm.resolveIntent(assistIntent,
- assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY, userHandle);
+ assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY, userHandle);
if (info != null) {
return new ComponentName(
info.activityInfo.applicationInfo.packageName,
@@ -257,16 +267,16 @@ public class SearchManagerService extends ISearchManager.Stub {
}
} catch (RemoteException re) {
// Local call
- Log.e(TAG, "RemoteException in getAssistIntent: " + re);
+ Log.e(TAG, "RemoteException in getLegacyAssistComponent: " + re);
} catch (Exception e) {
- Log.e(TAG, "Exception in getAssistIntent: " + e);
+ Log.e(TAG, "Exception in getLegacyAssistComponent: " + e);
}
return null;
}
@Override
- public boolean launchAssistAction(String hint, int userHandle, Bundle args) {
- ComponentName comp = getAssistIntent(userHandle);
+ public boolean launchLegacyAssist(String hint, int userHandle, Bundle args) {
+ ComponentName comp = getLegacyAssistComponent(userHandle);
if (comp == null) {
return false;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 4692403..130815e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -16,6 +16,8 @@
package com.android.server.statusbar;
+import android.os.Bundle;
+
import com.android.server.notification.NotificationDelegate;
public interface StatusBarManagerInternal {
@@ -25,4 +27,5 @@ public interface StatusBarManagerInternal {
void notificationLightOff();
void showScreenPinningRequest();
void showAssistDisclosure();
+ void startAssist(Bundle args);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 5ceb6ad..2a817ea 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,6 +18,7 @@ package com.android.server.statusbar;
import android.app.StatusBarManager;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -165,6 +166,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
}
+
+ @Override
+ public void startAssist(Bundle args) {
+ if (mBar != null) {
+ try {
+ mBar.startAssist(args);
+ } catch (RemoteException e) {
+ }
+ }
+ }
};
// ================================================================================
@@ -526,6 +537,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
+ @Override
+ public void startAssist(Bundle args) {
+ if (mBar != null) {
+ try {
+ mBar.startAssist(args);
+ } catch (RemoteException ex) {}
+ }
+ }
+
private void enforceStatusBar() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
"StatusBarManagerService");
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 11eb572..7630178 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -349,6 +349,7 @@ public class WindowAnimator {
"Now policy hidden: " + win);
} else {
boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null
+ && !mPostKeyguardExitAnimation.hasEnded()
&& !winAnimator.mKeyguardGoingAwayAnimation
&& win.hasDrawnLw()
&& win.mAttachedWindow == null
@@ -499,8 +500,7 @@ public class WindowAnimator {
mPostKeyguardExitAnimation.getStartOffset(),
mPostKeyguardExitAnimation.getDuration());
mKeyguardGoingAway = false;
- } else if (mCurrentTime - mPostKeyguardExitAnimation.getStartTime()
- > mPostKeyguardExitAnimation.getDuration()) {
+ } else if (mPostKeyguardExitAnimation.hasEnded()) {
// Done with the animation, reset.
if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
mPostKeyguardExitAnimation = null;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ac4fea8..ec566bc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10978,6 +10978,13 @@ public class WindowManagerService extends IWindowManager.Stub
if (mLastDispatchedSystemUiVisibility == visibility) {
return;
}
+ final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
+ // We are only interested in differences of one of the
+ // clearable flags...
+ & View.SYSTEM_UI_CLEARABLE_FLAGS
+ // ...if it has actually been cleared.
+ & ~visibility;
+
mLastDispatchedSystemUiVisibility = visibility;
mInputManager.setSystemUiVisibility(visibility);
final WindowList windows = getDefaultWindowListLocked();
@@ -10986,12 +10993,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState ws = windows.get(i);
try {
int curValue = ws.mSystemUiVisibility;
- int diff = curValue ^ visibility;
- // We are only interested in differences of one of the
- // clearable flags...
- diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
- // ...if it has actually been cleared.
- diff &= ~visibility;
+ int diff = (curValue ^ visibility) & globalDiff;
int newValue = (curValue&~diff) | (visibility&diff);
if (newValue != curValue) {
ws.mSeq++;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b918a25..c2548de 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1104,6 +1104,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* Returns true if the window has a surface that it has drawn a
* complete UI in to.
*/
+ @Override
public boolean isDrawnLw() {
return mHasSurface && !mDestroying &&
(mWinAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ed4fe24..5d05f32 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -60,7 +60,6 @@ import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.hardware.usb.UsbManager;
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
@@ -5446,10 +5445,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
userHandle);
- } else if (UserManager.DISALLOW_USB_FILE_TRANSFER.equals(key)) {
- UsbManager manager =
- (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
- manager.setCurrentFunction("none");
} else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF,
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index fb8a5bb..cb9c6a7 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -20,8 +20,24 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.mockito.Matchers.anyInt;
@@ -135,6 +151,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private final NetworkInfo mNetworkInfo;
private final NetworkCapabilities mNetworkCapabilities;
private final Thread mThread;
+ private final ConditionVariable mDisconnected = new ConditionVariable();
private int mScore;
private NetworkAgent mNetworkAgent;
@@ -161,7 +178,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mNetworkAgent = new NetworkAgent(Looper.myLooper(), mServiceContext,
"Mock" + typeName, mNetworkInfo, mNetworkCapabilities,
new LinkProperties(), mScore, new NetworkMisc()) {
- public void unwanted() {}
+ public void unwanted() { mDisconnected.open(); }
};
initComplete.open();
Looper.loop();
@@ -176,8 +193,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mNetworkAgent.sendNetworkScore(mScore);
}
+ public void addCapability(int capability) {
+ mNetworkCapabilities.addCapability(capability);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void connectWithoutInternet() {
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
/**
- * Transition this NetworkAgent to CONNECTED state.
+ * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
* @param validated Indicate if network should pretend to be validated.
*/
public void connect(boolean validated) {
@@ -210,8 +237,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ connectWithoutInternet();
if (validated) {
// Wait for network to validate.
@@ -231,6 +257,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
public Network getNetwork() {
return new Network(mNetworkAgent.netId);
}
+
+ public ConditionVariable getDisconnectedCV() {
+ return mDisconnected;
+ }
}
private static class MockNetworkFactory extends NetworkFactory {
@@ -555,6 +585,34 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@LargeTest
+ public void testUnlingeringDoesNotValidate() throws Exception {
+ // Test bringing up unvalidated cellular.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mCellNetworkAgent.connect(false);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ // Test bringing up validated WiFi.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ cv = waitForConnectivityBroadcasts(2);
+ mWiFiNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ // Test WiFi disconnect.
+ cv = waitForConnectivityBroadcasts(2);
+ mWiFiNetworkAgent.disconnect();
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Unlingering a network should not cause it to be marked as validated.
+ assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ }
+
+ @LargeTest
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -582,6 +640,107 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
}
+ @LargeTest
+ public void testReapingNetwork() throws Exception {
+ // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
+ // Expect it to be torn down immediately because it satisfies no requests.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
+ mWiFiNetworkAgent.connectWithoutInternet();
+ waitFor(cv);
+ // Test bringing up cellular without NET_CAPABILITY_INTERNET.
+ // Expect it to be torn down immediately because it satisfies no requests.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ cv = mCellNetworkAgent.getDisconnectedCV();
+ mCellNetworkAgent.connectWithoutInternet();
+ waitFor(cv);
+ // Test bringing up validated WiFi.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ // Test bringing up unvalidated cellular.
+ // Expect it to be torn down because it could never be the highest scoring network
+ // satisfying the default request even if it validated.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ cv = mCellNetworkAgent.getDisconnectedCV();
+ mCellNetworkAgent.connect(false);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ cv = mWiFiNetworkAgent.getDisconnectedCV();
+ mWiFiNetworkAgent.disconnect();
+ waitFor(cv);
+ }
+
+ @LargeTest
+ public void testCellularFallback() throws Exception {
+ // Test bringing up validated cellular.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mCellNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Test bringing up validated WiFi.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ cv = waitForConnectivityBroadcasts(2);
+ mWiFiNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ // Reevaluate WiFi (it'll instantly fail DNS).
+ cv = waitForConnectivityBroadcasts(2);
+ assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
+ // Should quickly fall back to Cellular.
+ waitFor(cv);
+ assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Reevaluate cellular (it'll instantly fail DNS).
+ cv = waitForConnectivityBroadcasts(2);
+ assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
+ // Should quickly fall back to WiFi.
+ waitFor(cv);
+ assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
+ }
+
+ @LargeTest
+ public void testWiFiFallback() throws Exception {
+ // Test bringing up unvalidated WiFi.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent.connect(false);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ // Test bringing up validated cellular.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ cv = waitForConnectivityBroadcasts(2);
+ mCellNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Reevaluate cellular (it'll instantly fail DNS).
+ cv = waitForConnectivityBroadcasts(2);
+ assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
+ // Should quickly fall back to WiFi.
+ waitFor(cv);
+ assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
+ }
+
enum CallbackState {
NONE,
AVAILABLE,
@@ -736,10 +895,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
}
- @LargeTest
- public void testNetworkFactoryRequests() throws Exception {
+ private void tryNetworkFactoryRequests(int capability) throws Exception {
NetworkCapabilities filter = new NetworkCapabilities();
- filter.addCapability(NET_CAPABILITY_INTERNET);
+ filter.addCapability(capability);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -747,57 +905,91 @@ public class ConnectivityServiceTest extends AndroidTestCase {
testFactory.setScoreFilter(40);
ConditionVariable cv = testFactory.getNetworkStartedCV();
testFactory.register();
+ int expectedRequestCount = 1;
+ NetworkCallback networkCallback = null;
+ // For non-INTERNET capabilities we cannot rely on the default request being present, so
+ // add one.
+ if (capability != NET_CAPABILITY_INTERNET) {
+ testFactory.waitForNetworkRequests(1);
+ assertFalse(testFactory.getMyStartRequested());
+ NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
+ networkCallback = new NetworkCallback();
+ mCm.requestNetwork(request, networkCallback);
+ expectedRequestCount++;
+ }
waitFor(cv);
- assertEquals(1, testFactory.getMyRequestCount());
- assertEquals(true, testFactory.getMyStartRequested());
+ assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+ assertTrue(testFactory.getMyStartRequested());
- // now bring in a higher scored network
+ // Now bring in a higher scored network.
MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- cv = waitForConnectivityBroadcasts(1);
- ConditionVariable cvRelease = testFactory.getNetworkStoppedCV();
- testAgent.connect(true);
+ // Rather than create a validated network which complicates things by registering it's
+ // own NetworkRequest during startup, just bump up the score to cancel out the
+ // unvalidated penalty.
+ testAgent.adjustScore(40);
+ cv = testFactory.getNetworkStoppedCV();
+ testAgent.connect(false);
+ testAgent.addCapability(capability);
waitFor(cv);
- // part of the bringup makes another network request and then releases it
- // wait for the release
- waitFor(cvRelease);
- assertEquals(false, testFactory.getMyStartRequested());
- testFactory.waitForNetworkRequests(1);
+ assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+ assertFalse(testFactory.getMyStartRequested());
- // bring in a bunch of requests..
+ // Bring in a bunch of requests.
ConnectivityManager.NetworkCallback[] networkCallbacks =
new ConnectivityManager.NetworkCallback[10];
for (int i = 0; i< networkCallbacks.length; i++) {
networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ builder.addCapability(capability);
mCm.requestNetwork(builder.build(), networkCallbacks[i]);
}
- testFactory.waitForNetworkRequests(11);
- assertEquals(false, testFactory.getMyStartRequested());
+ testFactory.waitForNetworkRequests(10 + expectedRequestCount);
+ assertFalse(testFactory.getMyStartRequested());
- // remove the requests
+ // Remove the requests.
for (int i = 0; i < networkCallbacks.length; i++) {
mCm.unregisterNetworkCallback(networkCallbacks[i]);
}
- testFactory.waitForNetworkRequests(1);
- assertEquals(false, testFactory.getMyStartRequested());
+ testFactory.waitForNetworkRequests(expectedRequestCount);
+ assertFalse(testFactory.getMyStartRequested());
- // drop the higher scored network
- cv = waitForConnectivityBroadcasts(1);
+ // Drop the higher scored network.
+ cv = testFactory.getNetworkStartedCV();
testAgent.disconnect();
waitFor(cv);
- assertEquals(1, testFactory.getMyRequestCount());
- assertEquals(true, testFactory.getMyStartRequested());
+ assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+ assertTrue(testFactory.getMyStartRequested());
testFactory.unregister();
+ if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
handlerThread.quit();
}
@LargeTest
+ public void testNetworkFactoryRequests() throws Exception {
+ tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
+ tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
+ tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
+ tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
+ tryNetworkFactoryRequests(NET_CAPABILITY_IA);
+ tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
+ tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
+ tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
+ tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
+ tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
+ // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
+ }
+
+ @LargeTest
public void testNoMutableNetworkRequests() throws Exception {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ builder.addCapability(NET_CAPABILITY_VALIDATED);
try {
mCm.requestNetwork(builder.build(), new NetworkCallback());
fail();
@@ -807,7 +999,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
fail();
} catch (IllegalArgumentException expected) {}
builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ builder.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
try {
mCm.requestNetwork(builder.build(), new NetworkCallback());
fail();
@@ -818,6 +1010,71 @@ public class ConnectivityServiceTest extends AndroidTestCase {
} catch (IllegalArgumentException expected) {}
}
+ @LargeTest
+ public void testMMSonWiFi() throws Exception {
+ // Test bringing up cellular without MMS NetworkRequest gets reaped
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
+ ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
+ mCellNetworkAgent.connectWithoutInternet();
+ waitFor(cv);
+ waitFor(new Criteria() {
+ public boolean get() { return mCm.getAllNetworks().length == 0; } });
+ verifyNoNetwork();
+ // Test bringing up validated WiFi.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent.connect(true);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ // Register MMS NetworkRequest
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(builder.build(), networkCallback);
+ // Test bringing up unvalidated cellular with MMS
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
+ cv = networkCallback.getConditionVariable();
+ mCellNetworkAgent.connectWithoutInternet();
+ waitFor(cv);
+ assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ // Test releasing NetworkRequest disconnects cellular with MMS
+ cv = mCellNetworkAgent.getDisconnectedCV();
+ mCm.unregisterNetworkCallback(networkCallback);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_WIFI);
+ }
+
+ @LargeTest
+ public void testMMSonCell() throws Exception {
+ // Test bringing up cellular without MMS
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ mCellNetworkAgent.connect(false);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Register MMS NetworkRequest
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.requestNetwork(builder.build(), networkCallback);
+ // Test bringing up MMS cellular network
+ cv = networkCallback.getConditionVariable();
+ MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
+ mmsNetworkAgent.connectWithoutInternet();
+ waitFor(cv);
+ assertEquals(CallbackState.AVAILABLE, networkCallback.getLastCallback());
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
+ cv = mmsNetworkAgent.getDisconnectedCV();
+ mCm.unregisterNetworkCallback(networkCallback);
+ waitFor(cv);
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ }
+
// @Override
// public void tearDown() throws Exception {
// super.tearDown();
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index e7716c2..81b4857 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -19,12 +19,10 @@ package com.android.server.usb;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -54,7 +52,6 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -67,9 +64,25 @@ import java.util.Scanner;
*/
public class UsbDeviceManager {
- private static final String TAG = UsbDeviceManager.class.getSimpleName();
+ private static final String TAG = "UsbDeviceManager";
private static final boolean DEBUG = false;
+ /**
+ * The persistent property which stores whether adb is enabled or not.
+ * May also contain vendor-specific default functions for testing purposes.
+ */
+ private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
+
+ /**
+ * The non-persistent property which stores the current USB settings.
+ */
+ private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
+
+ /**
+ * The non-persistent property which stores the current USB actual state.
+ */
+ private static final String USB_STATE_PROPERTY = "sys.usb.state";
+
private static final String USB_STATE_MATCH =
"DEVPATH=/devices/virtual/android_usb/android0";
private static final String ACCESSORY_START_MATCH =
@@ -92,6 +105,7 @@ public class UsbDeviceManager {
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
+ private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -184,12 +198,6 @@ public class UsbDeviceManager {
}
}
- public void setCurrentSettings(UsbSettingsManager settings) {
- synchronized (mLock) {
- mCurrentSettings = settings;
- }
- }
-
private UsbSettingsManager getCurrentSettings() {
synchronized (mLock) {
return mCurrentSettings;
@@ -221,6 +229,22 @@ public class UsbDeviceManager {
mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
}
+ public void bootCompleted() {
+ if (DEBUG) Slog.d(TAG, "boot completed");
+ mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
+ }
+
+ public void setCurrentUser(int userId, UsbSettingsManager settings) {
+ synchronized (mLock) {
+ mCurrentSettings = settings;
+ mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
+ }
+ }
+
+ public void updateUserRestrictions() {
+ mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS);
+ }
+
private void startAccessoryMode() {
if (!mHasUsbAccessory) return;
@@ -270,46 +294,6 @@ public class UsbDeviceManager {
}
}
- private static String addFunction(String functions, String function) {
- if ("none".equals(functions)) {
- return function;
- }
- if (!containsFunction(functions, function)) {
- if (functions.length() > 0) {
- functions += ",";
- }
- functions += function;
- }
- return functions;
- }
-
- private static String removeFunction(String functions, String function) {
- String[] split = functions.split(",");
- for (int i = 0; i < split.length; i++) {
- if (function.equals(split[i])) {
- split[i] = null;
- }
- }
- if (split.length == 1 && split[0] == null) {
- return "none";
- }
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < split.length; i++) {
- String s = split[i];
- if (s != null) {
- if (builder.length() > 0) {
- builder.append(",");
- }
- builder.append(s);
- }
- }
- return builder.toString();
- }
-
- private static boolean containsFunction(String functions, String function) {
- return Arrays.asList(functions.split(",")).contains(function);
- }
-
private final class UsbHandler extends Handler {
// current USB state
@@ -317,49 +301,24 @@ public class UsbDeviceManager {
private boolean mConfigured;
private boolean mUsbDataUnlocked;
private String mCurrentFunctions;
+ private boolean mCurrentFunctionsApplied;
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
- private String mDefaultFunctions;
private boolean mAdbNotificationShown;
private int mCurrentUser = UserHandle.USER_NULL;
- private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Slog.d(TAG, "boot completed");
- mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
- }
- };
-
- private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
- }
- };
-
public UsbHandler(Looper looper) {
super(looper);
try {
- // TODO: rename persist.sys.usb.config to something more descriptive.
- // persist.sys.usb.config should never be unset. But if it is, set it to "adb"
- // so we have a chance of debugging what happened.
- mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
-
- // sanity check the sys.usb.config system property
- // this may be necessary if we crashed while switching USB configurations
- String config = SystemProperties.get("sys.usb.config", "none");
- if (!config.equals(mDefaultFunctions)) {
- Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
- SystemProperties.set("sys.usb.config", mDefaultFunctions);
- }
-
- mAdbEnabled = containsFunction(
- SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY, "adb"),
+ // Restore default functions.
+ mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
+ UsbManager.USB_FUNCTION_NONE);
+ mCurrentFunctionsApplied = mCurrentFunctions.equals(
+ SystemProperties.get(USB_STATE_PROPERTY));
+ mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
UsbManager.USB_FUNCTION_ADB);
+ setEnabledFunctions(null, false);
- mCurrentFunctions = getDefaultFunctions();
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
@@ -371,12 +330,6 @@ public class UsbDeviceManager {
// Watch for USB configuration changes
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mBootCompletedReceiver, filter);
- mContext.registerReceiver(
- mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
@@ -420,34 +373,26 @@ public class UsbDeviceManager {
sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
}
- private void updatePersistentProperty() {
- String newValue = getDefaultFunctions();
- String value = SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY);
- if (DEBUG) { Slog.d(TAG, "updatePersistentProperty newValue=" + newValue + " value=" + value); }
- if (!newValue.equals(value)) {
- SystemProperties.set(UsbManager.ADB_PERSISTENT_PROPERTY, getDefaultFunctions());
- }
- waitForState(newValue);
- }
-
private boolean waitForState(String state) {
// wait for the transition to complete.
// give up after 1 second.
+ String value = null;
for (int i = 0; i < 20; i++) {
// State transition is done when sys.usb.state is set to the new configuration
- if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
+ value = SystemProperties.get(USB_STATE_PROPERTY);
+ if (state.equals(value)) return true;
SystemClock.sleep(50);
}
- Slog.e(TAG, "waitForState(" + state + ") FAILED");
+ Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
return false;
}
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
- String oldConfig = SystemProperties.get(UsbManager.USB_SETTINGS_PROPERTY);
+ String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY);
if (!config.equals(oldConfig)) {
- SystemProperties.set(UsbManager.USB_SETTINGS_PROPERTY, config);
+ SystemProperties.set(USB_CONFIG_PROPERTY, config);
}
return waitForState(config);
}
@@ -456,54 +401,110 @@ public class UsbDeviceManager {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
+
// Due to the persist.sys.usb.config property trigger, changing adb state requires
// persisting default function
- updatePersistentProperty();
+ String oldFunctions = getDefaultFunctions();
+ String newFunctions = applyAdbFunction(oldFunctions);
+ if (!oldFunctions.equals(newFunctions)) {
+ SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
+ }
+
// After persisting them use the lock-down aware function set
- setEnabledFunctions(getDefaultFunctions());
+ setEnabledFunctions(mCurrentFunctions, false);
updateAdbNotification();
}
+
if (mDebuggingManager != null) {
mDebuggingManager.setAdbEnabled(mAdbEnabled);
}
}
/**
- * Stop and start the USB driver. This is needed to close all outstanding
- * USB connections.
+ * Evaluates USB function policies and applies the change accordingly.
*/
- private void restartCurrentFunction() {
- setUsbConfig("none");
- setUsbConfig(mCurrentFunctions);
- }
+ private void setEnabledFunctions(String functions, boolean forceRestart) {
+ if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ + "forceRestart=" + forceRestart);
+
+ // Try to set the enabled functions.
+ final String oldFunctions = mCurrentFunctions;
+ final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
+ if (trySetEnabledFunctions(functions, forceRestart)) {
+ return;
+ }
- private void setEnabledFunctions(String functions) {
- if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions);
+ // Didn't work. Try to revert changes.
+ // We always reapply the policy in case certain constraints changed such as
+ // user restrictions independently of any other new functions we were
+ // trying to activate.
+ if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
+ Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
+ if (trySetEnabledFunctions(oldFunctions, false)) {
+ return;
+ }
+ }
+ // Still didn't work. Try to restore the default functions.
+ Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
+ if (trySetEnabledFunctions(null, false)) {
+ return;
+ }
+
+ // Now we're desperate. Ignore the default functions.
+ // Try to get ADB working if enabled.
+ Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
+ if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
+ return;
+ }
+
+ // Ouch.
+ Slog.e(TAG, "Unable to set any USB functions!");
+ }
+
+ private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
if (functions == null) {
functions = getDefaultFunctions();
}
+ functions = applyAdbFunction(functions);
+ functions = applyUserRestrictions(functions);
+
+ if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied
+ || forceRestart) {
+ Slog.i(TAG, "Setting USB config to " + functions);
+ mCurrentFunctions = functions;
+ mCurrentFunctionsApplied = false;
+
+ // Kick the USB stack to close existing connections.
+ setUsbConfig(UsbManager.USB_FUNCTION_NONE);
+
+ // Set the new USB configuration.
+ if (!setUsbConfig(functions)) {
+ Slog.e(TAG, "Failed to switch USB config to " + functions);
+ return false;
+ }
+
+ mCurrentFunctionsApplied = true;
+ }
+ return true;
+ }
+ private String applyAdbFunction(String functions) {
if (mAdbEnabled) {
- functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
+ functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
- functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
+ functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
- if (!mCurrentFunctions.equals(functions)) {
- if (!setUsbConfig("none")) {
- Slog.e(TAG, "Failed to disable USB");
- // revert to previous configuration if we fail
- setUsbConfig(mCurrentFunctions);
- return;
- }
- if (setUsbConfig(functions)) {
- mCurrentFunctions = functions;
- } else {
- Slog.e(TAG, "Failed to switch USB config to " + functions);
- // revert to previous configuration if we fail
- setUsbConfig(mCurrentFunctions);
- }
+ return functions;
+ }
+
+ private String applyUserRestrictions(String functions) {
+ UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
+ functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_MTP);
+ functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_PTP);
}
+ return functions;
}
private void updateCurrentAccessory() {
@@ -523,7 +524,7 @@ public class UsbDeviceManager {
// defer accessoryAttached if system is not ready
if (mBootCompleted) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
- } // else handle in mBootCompletedReceiver
+ } // else handle in boot completed
} else {
Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
@@ -531,7 +532,7 @@ public class UsbDeviceManager {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(getDefaultFunctions());
+ setEnabledFunctions(null, false);
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -543,10 +544,11 @@ public class UsbDeviceManager {
}
}
- private void updateUsbState() {
+ private void updateUsbStateBroadcast() {
// send a sticky broadcast containing current USB state
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
intent.putExtra(UsbManager.USB_DATA_UNLOCKED, mUsbDataUnlocked);
@@ -563,8 +565,13 @@ public class UsbDeviceManager {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void updateUsbFunctions() {
+ updateAudioSourceFunction();
+ updateMidiFunction();
+ }
+
private void updateAudioSourceFunction() {
- boolean enabled = containsFunction(mCurrentFunctions,
+ boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_AUDIO_SOURCE);
if (enabled != mAudioSourceEnabled) {
int card = -1;
@@ -590,7 +597,8 @@ public class UsbDeviceManager {
}
private void updateMidiFunction() {
- boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
+ boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MIDI);
if (enabled != mMidiEnabled) {
if (enabled) {
Scanner scanner = null;
@@ -624,17 +632,16 @@ public class UsbDeviceManager {
}
updateUsbNotification();
updateAdbNotification();
- if (containsFunction(mCurrentFunctions,
+ if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
} else if (!mConnected) {
// restore defaults when USB is disconnected
- setEnabledFunctions(getDefaultFunctions());
+ setEnabledFunctions(null, false);
}
if (mBootCompleted) {
- updateUsbState();
- updateAudioSourceFunction();
- updateMidiFunction();
+ updateUsbStateBroadcast();
+ updateUsbFunctions();
}
break;
case MSG_ENABLE_ADB:
@@ -642,26 +649,25 @@ public class UsbDeviceManager {
break;
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String)msg.obj;
- setEnabledFunctions(functions);
+ setEnabledFunctions(functions, false);
+ break;
+ case MSG_UPDATE_USER_RESTRICTIONS:
+ setEnabledFunctions(mCurrentFunctions, false);
break;
case MSG_SET_USB_DATA_UNLOCKED:
mUsbDataUnlocked = (msg.arg1 == 1);
updateUsbNotification();
- updateUsbState();
- restartCurrentFunction();
+ updateUsbStateBroadcast();
+ setEnabledFunctions(mCurrentFunctions, true);
break;
case MSG_SYSTEM_READY:
- setUsbConfig(mCurrentFunctions);
- updatePersistentProperty();
updateUsbNotification();
updateAdbNotification();
- updateUsbState();
- updateAudioSourceFunction();
- updateMidiFunction();
+ updateUsbStateBroadcast();
+ updateUsbFunctions();
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
- setUsbConfig(mCurrentFunctions);
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
}
@@ -670,27 +676,19 @@ public class UsbDeviceManager {
}
break;
case MSG_USER_SWITCHED: {
- UserManager userManager =
- (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- UserHandle userHandle = new UserHandle(msg.arg1);
- if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
- userHandle)) {
- Slog.v(TAG, "Switched to user " + msg.arg1 +
- " with DISALLOW_USB_FILE_TRANSFER restriction; disabling USB.");
- setUsbConfig("none");
+ if (mCurrentUser != msg.arg1) {
+ // Restart the USB stack and re-apply user restrictions for MTP or PTP.
+ final boolean active = UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_PTP);
+ if (active && mCurrentUser != UserHandle.USER_NULL) {
+ Slog.v(TAG, "Current user switched to " + mCurrentUser
+ + "; resetting USB host stack for MTP or PTP");
+ setEnabledFunctions(mCurrentFunctions, true);
+ }
mCurrentUser = msg.arg1;
- break;
- }
-
- final boolean mtpActive =
- containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
- || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
- if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
- Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
- setUsbConfig("none");
- setUsbConfig(mCurrentFunctions);
}
- mCurrentUser = msg.arg1;
break;
}
}
@@ -707,16 +705,17 @@ public class UsbDeviceManager {
if (mConnected) {
if (!mUsbDataUnlocked) {
id = com.android.internal.R.string.usb_charging_notification_title;
- } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
+ } else if (UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MTP)) {
id = com.android.internal.R.string.usb_mtp_notification_title;
- } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
+ } else if (UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_PTP)) {
id = com.android.internal.R.string.usb_ptp_notification_title;
- } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI)) {
+ } else if (UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MIDI)) {
id = com.android.internal.R.string.usb_midi_notification_title;
- } else if (containsFunction(mCurrentFunctions,
- UsbManager.USB_FUNCTION_MASS_STORAGE)) {
- id = com.android.internal.R.string.usb_cd_installer_notification_title;
- } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
+ } else if (UsbManager.containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_ACCESSORY)) {
id = com.android.internal.R.string.usb_accessory_notification_title;
} else {
id = com.android.internal.R.string.usb_charging_notification_title;
@@ -804,17 +803,14 @@ public class UsbDeviceManager {
}
private String getDefaultFunctions() {
- UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE);
- if(userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
- new UserHandle(mCurrentUser))) {
- return "none";
- }
- return mDefaultFunctions;
+ return SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY,
+ UsbManager.USB_FUNCTION_ADB);
}
public void dump(FileDescriptor fd, PrintWriter pw) {
pw.println(" USB Device State:");
- pw.println(" Current Functions: " + mCurrentFunctions);
+ pw.println(" mCurrentFunctions: " + mCurrentFunctions);
+ pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
pw.println(" mConnected: " + mConnected);
pw.println(" mConfigured: " + mConfigured);
pw.println(" mCurrentAccessory: " + mCurrentAccessory);
@@ -850,6 +846,10 @@ public class UsbDeviceManager {
return nativeOpenAccessory();
}
+ public boolean isFunctionEnabled(String function) {
+ return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
+ }
+
public void setCurrentFunctions(String functions) {
if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 987a79f..c8b4226 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -17,6 +17,7 @@
package com.android.server.usb;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -25,10 +26,12 @@ import android.content.pm.PackageManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -63,6 +66,8 @@ public class UsbService extends IUsbManager.Stub {
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mUsbService.systemReady();
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ mUsbService.bootCompleted();
}
}
}
@@ -108,13 +113,15 @@ public class UsbService extends IUsbManager.Stub {
setCurrentUser(UserHandle.USER_OWNER);
- final IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_SWITCHED);
- userFilter.addAction(Intent.ACTION_USER_STOPPED);
- mContext.registerReceiver(mUserReceiver, userFilter, null, null);
+ final IntentFilter filter = new IntentFilter();
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_STOPPED);
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter, null, null);
}
- private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
@@ -125,6 +132,11 @@ public class UsbService extends IUsbManager.Stub {
synchronized (mLock) {
mSettingsByUser.remove(userId);
}
+ } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+ .equals(action)) {
+ if (mDeviceManager != null) {
+ mDeviceManager.updateUserRestrictions();
+ }
}
}
};
@@ -135,7 +147,7 @@ public class UsbService extends IUsbManager.Stub {
mHostManager.setCurrentSettings(userSettings);
}
if (mDeviceManager != null) {
- mDeviceManager.setCurrentSettings(userSettings);
+ mDeviceManager.setCurrentUser(userId, userSettings);
}
}
@@ -150,6 +162,12 @@ public class UsbService extends IUsbManager.Stub {
}
}
+ public void bootCompleted() {
+ if (mDeviceManager != null) {
+ mDeviceManager.bootCompleted();
+ }
+ }
+
/* Returns a list of all currently attached USB devices (host mdoe) */
@Override
public void getDeviceList(Bundle devices) {
@@ -252,15 +270,19 @@ public class UsbService extends IUsbManager.Stub {
}
@Override
+ public boolean isFunctionEnabled(String function) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ return mDeviceManager != null && mDeviceManager.isFunctionEnabled(function);
+ }
+
+ @Override
public void setCurrentFunction(String function) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- // If attempt to change USB function while file transfer is restricted, ensure that
- // the current function is set to "none", and return.
- UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
- if (mDeviceManager != null) mDeviceManager.setCurrentFunctions("none");
- return;
+ if (!isSupportedCurrentFunction(function)) {
+ Slog.w(TAG, "Caller of setCurrentFunction() requested unsupported USB function: "
+ + function);
+ function = UsbManager.USB_FUNCTION_NONE;
}
if (mDeviceManager != null) {
@@ -270,6 +292,22 @@ public class UsbService extends IUsbManager.Stub {
}
}
+ private static boolean isSupportedCurrentFunction(String function) {
+ if (function == null) return true;
+
+ switch (function) {
+ case UsbManager.USB_FUNCTION_NONE:
+ case UsbManager.USB_FUNCTION_AUDIO_SOURCE:
+ case UsbManager.USB_FUNCTION_MIDI:
+ case UsbManager.USB_FUNCTION_MTP:
+ case UsbManager.USB_FUNCTION_PTP:
+ case UsbManager.USB_FUNCTION_RNDIS:
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public void setUsbDataUnlocked(boolean unlocked) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 61ae1c0..36478da 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -761,7 +761,8 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
- public void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback) {
+ public void showSessionForActiveService(Bundle args,
+ IVoiceInteractionSessionShowCallback showCallback) {
enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
synchronized (this) {
if (mImpl == null) {
@@ -771,7 +772,7 @@ public class VoiceInteractionManagerService extends SystemService {
}
final long caller = Binder.clearCallingIdentity();
try {
- mImpl.showSessionLocked(new Bundle() /* sessionArgs */,
+ mImpl.showSessionLocked(args,
VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE
| VoiceInteractionSession.SHOW_WITH_ASSIST
| VoiceInteractionSession.SHOW_WITH_SCREENSHOT,