summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java91
-rw-r--r--services/core/java/com/android/server/AppOpsService.java16
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java164
-rw-r--r--services/core/java/com/android/server/PersistentDataBlockService.java7
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java128
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java30
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java49
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java16
9 files changed, 352 insertions, 152 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 083aa9b..f6e2e67 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1234,6 +1234,7 @@ public class BackupManagerService extends IBackupManager.Stub {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
// Register for events related to sdcard installation.
@@ -1688,11 +1689,12 @@ public class BackupManagerService extends IBackupManager.Stub {
String action = intent.getAction();
boolean replacing = false;
boolean added = false;
- boolean rebind = false;
+ boolean changed = false;
Bundle extras = intent.getExtras();
String pkgList[] = null;
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
- Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+ Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
Uri uri = intent.getData();
if (uri == null) {
return;
@@ -1701,7 +1703,43 @@ public class BackupManagerService extends IBackupManager.Stub {
if (pkgName != null) {
pkgList = new String[] { pkgName };
}
- rebind = added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+ changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
+
+ // At package-changed we only care about looking at new transport states
+ if (changed) {
+ try {
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+ }
+ // unbind existing possibly-stale connections to that package's transports
+ synchronized (mTransports) {
+ TransportConnection conn = mTransportConnections.get(pkgName);
+ if (conn != null) {
+ final ServiceInfo svc = conn.mTransport;
+ ComponentName svcName =
+ new ComponentName(svc.packageName, svc.name);
+ String flatName = svcName.flattenToShortString();
+ Slog.i(TAG, "Unbinding " + svcName);
+
+ mContext.unbindService(conn);
+ mTransportConnections.remove(pkgName);
+ mTransports.remove(mTransportNames.get(flatName));
+ mTransportNames.remove(flatName);
+ }
+ }
+ // and then (re)bind as appropriate
+ PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
+ checkForTransportAndBind(app);
+ } catch (NameNotFoundException e) {
+ // Nope, can't find it - just ignore
+ if (MORE_DEBUG) {
+ Slog.w(TAG, "Can't find changed package " + pkgName);
+ }
+ }
+ return; // nothing more to do in the PACKAGE_CHANGED case
+ }
+
+ added = Intent.ACTION_PACKAGE_ADDED.equals(action);
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
added = true;
@@ -1737,17 +1775,15 @@ public class BackupManagerService extends IBackupManager.Stub {
// Transport maintenance: rebind to known existing transports that have
// just been updated; and bind to any newly-installed transport services.
- if (rebind) {
- synchronized (mTransportConnections) {
- final TransportConnection conn = mTransportConnections.get(packageName);
- if (conn != null) {
- if (DEBUG) {
- Slog.i(TAG, "Transport package changed; rebinding");
- }
- bindTransport(conn.mTransport);
- } else {
- checkForTransportAndBind(app);
+ synchronized (mTransports) {
+ final TransportConnection conn = mTransportConnections.get(packageName);
+ if (conn != null) {
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Transport package changed; rebinding");
}
+ bindTransport(conn.mTransport);
+ } else {
+ checkForTransportAndBind(app);
}
}
@@ -1840,7 +1876,7 @@ public class BackupManagerService extends IBackupManager.Stub {
intent.setComponent(svcName);
TransportConnection connection;
- synchronized (mTransportConnections) {
+ synchronized (mTransports) {
connection = mTransportConnections.get(transport.packageName);
if (null == connection) {
connection = new TransportConnection(transport);
@@ -8462,31 +8498,24 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
return list;
}
- // Select which transport to use for the next backup operation. If the given
- // name is not one of the available transports, no action is taken and the method
- // returns null.
+ // Select which transport to use for the next backup operation.
public String selectBackupTransport(String transport) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"selectBackupTransport");
synchronized (mTransports) {
- String prevTransport = null;
- if (mTransports.get(transport) != null) {
- final long oldId = Binder.clearCallingIdentity();
- try {
- prevTransport = mCurrentTransport;
- mCurrentTransport = transport;
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, transport);
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ String prevTransport = mCurrentTransport;
+ mCurrentTransport = transport;
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT, transport);
Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ " returning " + prevTransport);
- } else {
- Slog.w(TAG, "Attempt to select unavailable transport " + transport);
+ return prevTransport;
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- return prevTransport;
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ef6e07c..c3465d1 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -631,7 +631,7 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public int checkPackage(int uid, String packageName) {
synchronized (this) {
- if (getOpsLocked(uid, packageName, true) != null) {
+ if (getOpsRawLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
} else {
return AppOpsManager.MODE_ERRORED;
@@ -769,6 +769,15 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private Ops getOpsLocked(int uid, String packageName, boolean edit) {
+ if (uid == 0) {
+ packageName = "root";
+ } else if (uid == Process.SHELL_UID) {
+ packageName = "com.android.shell";
+ }
+ return getOpsRawLocked(uid, packageName, edit);
+ }
+
+ private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
if (!edit) {
@@ -777,11 +786,6 @@ public class AppOpsService extends IAppOpsService.Stub {
pkgOps = new HashMap<String, Ops>();
mUidOps.put(uid, pkgOps);
}
- if (uid == 0) {
- packageName = "root";
- } else if (uid == Process.SHELL_UID) {
- packageName = "com.android.shell";
- }
Ops ops = pkgOps.get(packageName);
if (ops == null) {
if (!edit) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 75090db..55d8c09 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -251,7 +251,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private Context mContext;
private int mNetworkPreference;
- private int mActiveDefaultNetwork = -1;
+ private int mActiveDefaultNetwork = TYPE_NONE;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -886,15 +886,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return getNetworkInfo(mActiveDefaultNetwork, uid);
}
- // only called when the default request is satisfied
- private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
- if (nai != null) {
- mActiveDefaultNetwork = nai.networkInfo.getType();
- } else {
- mActiveDefaultNetwork = TYPE_NONE;
- }
- }
-
/**
* Find the first Provisioning network.
*
@@ -1794,6 +1785,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
private boolean isLiveNetworkAgent(NetworkAgentInfo nai, String msg) {
+ if (nai.network == null) return false;
final NetworkAgentInfo officialNai;
synchronized (mNetworkForNetId) {
officialNai = mNetworkForNetId.get(nai.network.netId);
@@ -1933,10 +1925,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
break;
}
- case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
+ case NetworkMonitor.EVENT_NETWORK_TESTED: {
NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
- handleConnectionValidated(nai);
+ boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+ if (valid) {
+ if (DBG) log("Validated " + nai.name());
+ nai.validated = true;
+ rematchNetworkAndRequests(nai);
+ }
+ updateInetCondition(nai, valid);
}
break;
}
@@ -2057,7 +2055,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (nri.isRequest == false) continue;
NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.currentScore : 0), 0, nri.request);
+ (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
}
} else {
loge("Error connecting NetworkFactory");
@@ -2136,7 +2134,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
request.networkCapabilities.satisfiedByNetworkCapabilities(
existing.networkCapabilities) &&
(alternative == null ||
- alternative.currentScore < existing.currentScore)) {
+ alternative.getCurrentScore() < existing.getCurrentScore())) {
alternative = existing;
}
}
@@ -2169,8 +2167,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
- if (DBG) log("apparently satisfied. currentScore=" + network.currentScore);
- if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
+ if (DBG) log("apparently satisfied. currentScore=" + network.getCurrentScore());
+ if ((bestNetwork == null) ||
+ bestNetwork.getCurrentScore() < 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
@@ -2194,7 +2193,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
bestNetwork.addRequest(nri.request);
mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
notifyNetworkCallback(bestNetwork, nri);
- score = bestNetwork.currentScore;
+ score = bestNetwork.getCurrentScore();
if (nri.request.legacyType != TYPE_NONE) {
mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
}
@@ -4516,19 +4515,34 @@ public class ConnectivityService extends IConnectivityManager.Stub {
updateTcpBufferSizes(newNetwork);
}
- private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
- if (newNetwork == null) {
- loge("Unknown NetworkAgentInfo in handleConnectionValidated");
- return;
- }
- if (newNetwork.validated) return;
- newNetwork.validated = true;
+ // Handles a network appearing or improving its score.
+ //
+ // - Evaluates all current NetworkRequests that can be
+ // satisfied by newNetwork, and reassigns to newNetwork
+ // any such requests for which newNetwork is the best.
+ //
+ // - Tears down any Networks that as a result are no longer
+ // needed. A network is needed if it is the best network for
+ // one or more NetworkRequests, or if it is a VPN.
+ //
+ // - Tears down newNetwork if it is validated but turns out to be
+ // unneeded. Does not tear down newNetwork if it is
+ // unvalidated, because future validation may improve
+ // newNetwork's score enough that it is needed.
+ //
+ // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
+ // it does not remove NetworkRequests that other Networks could better satisfy.
+ // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
+ // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
+ // as it performs better by a factor of the number of Networks.
+ private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork) {
boolean keep = newNetwork.isVPN();
boolean isNewDefault = false;
- if (DBG) log("handleConnectionValidated for "+newNetwork.name());
- // check if any NetworkRequest wants this NetworkAgent
+ if (DBG) log("rematching " + newNetwork.name());
+ // Find and migrate to this Network any NetworkRequests for
+ // which this network is now the best.
ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
- if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
+ if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
if (newNetwork == currentNetwork) {
@@ -4543,18 +4557,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
newNetwork.networkCapabilities)) {
if (!nri.isRequest) {
+ // This is not a request, it's a callback listener.
+ // Add it to newNetwork regardless of score.
newNetwork.addRequest(nri.request);
continue;
}
+
// next check if it's better than any current network we're using for
// this request
if (VDBG) {
log("currentScore = " +
- (currentNetwork != null ? currentNetwork.currentScore : 0) +
- ", newScore = " + newNetwork.currentScore);
+ (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
+ ", newScore = " + newNetwork.getCurrentScore());
}
if (currentNetwork == null ||
- currentNetwork.currentScore < newNetwork.currentScore) {
+ currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
if (currentNetwork != null) {
if (DBG) log(" accepting network in place of " + currentNetwork.name());
currentNetwork.networkRequests.remove(nri.request.requestId);
@@ -4569,13 +4586,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
}
keep = true;
+ // Tell NetworkFactories about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have alot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
+ sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
if (mDefaultRequest.requestId == nri.request.requestId) {
isNewDefault = true;
- updateActiveDefaultNetwork(newNetwork);
+ // TODO: Remove following line. It's redundant with makeDefault call.
+ mActiveDefaultNetwork = newNetwork.networkInfo.getType();
if (newNetwork.linkProperties != null) {
updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(
@@ -4591,12 +4611,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
currentNetwork);
}
- mDefaultInetConditionPublished = 100;
+ mDefaultInetConditionPublished = newNetwork.validated ? 100 : 0;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
}
}
}
}
+ // Linger any networks that are no longer needed.
for (NetworkAgentInfo nai : affectedNetworks) {
boolean teardown = !nai.isVPN();
for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
@@ -4624,6 +4645,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
if (keep) {
if (isNewDefault) {
+ // Notify system services that this network is up.
makeDefault(newNetwork);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in
@@ -4640,6 +4662,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// Notify battery stats service about this network, both the normal
// interface and any stacked links.
+ // TODO: Avoid redoing this; this must only be done once when a network comes online.
try {
final IBatteryStats bs = BatteryStatsService.getService();
final int type = newNetwork.networkInfo.getType();
@@ -4655,7 +4678,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
- } else {
+ } else if (newNetwork.validated) {
+ // Only tear down validated networks here. Leave unvalidated to either become
+ // validated (and get evaluated against peers, one losing here) or
+ // NetworkMonitor reports a bad network and we tear it down then.
+ // TODO: Could teardown unvalidated networks when their NetworkCapabilities
+ // satisfy no NetworkRequests.
if (DBG && newNetwork.networkRequests.size() != 0) {
loge("tearing down network with live requests:");
for (int i=0; i < newNetwork.networkRequests.size(); i++) {
@@ -4667,6 +4695,46 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ // Attempt to rematch all Networks with NetworkRequests. This may result in Networks
+ // being disconnected.
+ // If only one Network's score or capabilities have been modified since the last time
+ // this function was called, pass this Network in via the "changed" arugment, otherwise
+ // pass null.
+ // If only one Network has been changed but its NetworkCapabilities have not changed,
+ // pass in the Network's score (from getCurrentScore()) prior to the change via
+ // "oldScore", otherwise pass changed.getCurrentScore() or 0 if "changed" is null.
+ 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
+ // satifying a NetworkRequest that "changed" currently satisfies.
+
+ // 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()) {
+ rematchNetworkAndRequests(changed);
+ } else {
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ rematchNetworkAndRequests(nai);
+ }
+ }
+ }
+
+ private void updateInetCondition(NetworkAgentInfo nai, boolean valid) {
+ // Don't bother updating until we've graduated to validated at least once.
+ if (!nai.validated) return;
+ // For now only update icons for default connection.
+ // TODO: Update WiFi and cellular icons separately. b/17237507
+ if (!isDefaultNetwork(nai)) return;
+
+ int newInetCondition = valid ? 100 : 0;
+ // Don't repeat publish.
+ if (newInetCondition == mDefaultInetConditionPublished) return;
+
+ mDefaultInetConditionPublished = newInetCondition;
+ sendInetConditionBroadcast(nai.networkInfo);
+ }
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
NetworkInfo.State state = newInfo.getState();
@@ -4721,12 +4789,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
// TODO: support proxy per network.
}
- // Make default network if we have no default. Any network is better than no network.
+ // Consider network even though it is not yet validated.
+ // TODO: All the if-statement conditions can be removed now that validation only confers
+ // a score increase.
if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
networkAgent.isVPN() == false &&
mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
networkAgent.networkCapabilities)) {
- makeDefault(networkAgent);
+ rematchNetworkAndRequests(networkAgent);
}
} else if (state == NetworkInfo.State.DISCONNECTED ||
state == NetworkInfo.State.SUSPENDED) {
@@ -4752,23 +4822,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
score = 0;
}
- nai.currentScore = score;
-
- // TODO - This will not do the right thing if this network is lowering
- // its score and has requests that can be served by other
- // currently-active networks, or if the network is increasing its
- // score and other networks have requests that can be better served
- // by this network.
- //
- // Really we want to see if any of our requests migrate to other
- // active/lingered networks and if any other requests migrate to us (depending
- // on increasing/decreasing currentScore. That's a bit of work and probably our
- // score checking/network allocation code needs to be modularized so we can understand
- // (see handleConnectionValided for an example).
- //
- // As a first order approx, lets just advertise the new score to factories. If
- // somebody can beat it they will nominate a network and our normal net replacement
- // code will fire.
+ final int oldScore = nai.getCurrentScore();
+ nai.setCurrentScore(score);
+
+ if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);
+
for (int i = 0; i < nai.networkRequests.size(); i++) {
NetworkRequest nr = nai.networkRequests.valueAt(i);
// Don't send listening requests to factories. b/17393458
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 2896f60..6f378fd 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.Manifest;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -26,7 +27,9 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.persistentdata.IPersistentDataBlockService;
import android.util.Slog;
+
import com.android.internal.R;
+
import libcore.io.IoUtils;
import java.io.DataInputStream;
@@ -241,6 +244,10 @@ public class PersistentDataBlockService extends SystemService {
@Override
public void setOemUnlockEnabled(boolean enabled) {
+ // do not allow monkey to flip the flag
+ if (ActivityManager.isUserAMonkey()) {
+ return;
+ }
enforceOemUnlockPermission();
FileOutputStream outputStream;
try {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2885b83..2c39691 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -413,7 +413,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* List of intents that were used to start the most recent tasks.
*/
ArrayList<TaskRecord> mRecentTasks;
- ArraySet<TaskRecord> mTmpRecents = new ArraySet<TaskRecord>();
+ ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
/**
* For addAppTask: cached of the last activity component that was added.
@@ -3857,6 +3857,86 @@ public final class ActivityManagerService extends ActivityManagerNative
mTaskPersister.wakeup(null, true);
}
+ // Sort by taskId
+ private Comparator<TaskRecord> mTaskRecordComparator = new Comparator<TaskRecord>() {
+ @Override
+ public int compare(TaskRecord lhs, TaskRecord rhs) {
+ return rhs.taskId - lhs.taskId;
+ }
+ };
+
+ // Extract the affiliates of the chain containing mRecentTasks[start].
+ private int processNextAffiliateChain(int start) {
+ final TaskRecord startTask = mRecentTasks.get(start);
+ final int affiliateId = startTask.mAffiliatedTaskId;
+
+ // Quick identification of isolated tasks. I.e. those not launched behind.
+ if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
+ startTask.mNextAffiliate == null) {
+ // There is still a slim chance that there are other tasks that point to this task
+ // and that the chain is so messed up that this task no longer points to them but
+ // the gain of this optimization outweighs the risk.
+ startTask.inRecents = true;
+ return start + 1;
+ }
+
+ // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
+ mTmpRecents.clear();
+ for (int i = mRecentTasks.size() - 1; i >= start; --i) {
+ final TaskRecord task = mRecentTasks.get(i);
+ if (task.mAffiliatedTaskId == affiliateId) {
+ mRecentTasks.remove(i);
+ mTmpRecents.add(task);
+ }
+ }
+
+ // Sort them all by taskId. That is the order they were create in and that order will
+ // always be correct.
+ Collections.sort(mTmpRecents, mTaskRecordComparator);
+
+ // Go through and fix up the linked list.
+ // The first one is the end of the chain and has no next.
+ final TaskRecord first = mTmpRecents.get(0);
+ first.inRecents = true;
+ if (first.mNextAffiliate != null) {
+ Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
+ first.setNextAffiliate(null);
+ mTaskPersister.wakeup(first, false);
+ }
+ // Everything in the middle is doubly linked from next to prev.
+ final int tmpSize = mTmpRecents.size();
+ for (int i = 0; i < tmpSize - 1; ++i) {
+ final TaskRecord next = mTmpRecents.get(i);
+ final TaskRecord prev = mTmpRecents.get(i + 1);
+ if (next.mPrevAffiliate != prev) {
+ Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
+ " setting prev=" + prev);
+ next.setPrevAffiliate(prev);
+ mTaskPersister.wakeup(next, false);
+ }
+ if (prev.mNextAffiliate != next) {
+ Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
+ " setting next=" + next);
+ prev.setNextAffiliate(next);
+ mTaskPersister.wakeup(prev, false);
+ }
+ prev.inRecents = true;
+ }
+ // The last one is the beginning of the list and has no prev.
+ final TaskRecord last = mTmpRecents.get(tmpSize - 1);
+ if (last.mPrevAffiliate != null) {
+ Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
+ last.setPrevAffiliate(null);
+ mTaskPersister.wakeup(last, false);
+ }
+
+ // Insert the group back into mRecentTasks at start.
+ mRecentTasks.addAll(start, mTmpRecents);
+
+ // Let the caller know where we left off.
+ return start + tmpSize;
+ }
+
/**
* Update the recent tasks lists: make sure tasks should still be here (their
* applications / activities still exist), update their availability, fixup ordering
@@ -3969,51 +4049,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Verify the affiliate chain for each task.
- for (int i = 0; i < N; ) {
- TaskRecord task = mRecentTasks.remove(i);
- if (mTmpRecents.contains(task)) {
- continue;
- }
- int affiliatedTaskId = task.mAffiliatedTaskId;
- while (true) {
- TaskRecord next = task.mNextAffiliate;
- if (next == null) {
- break;
- }
- if (next.mAffiliatedTaskId != affiliatedTaskId) {
- Slog.e(TAG, "Error in Recents: next.affiliatedTaskId=" +
- next.mAffiliatedTaskId + " affiliatedTaskId=" + affiliatedTaskId);
- task.setNextAffiliate(null);
- if (next.mPrevAffiliate == task) {
- next.setPrevAffiliate(null);
- }
- break;
- }
- if (next.mPrevAffiliate != task) {
- Slog.e(TAG, "Error in Recents chain prev.mNextAffiliate=" +
- next.mPrevAffiliate + " task=" + task);
- next.setPrevAffiliate(null);
- task.setNextAffiliate(null);
- break;
- }
- if (!mRecentTasks.contains(next)) {
- Slog.e(TAG, "Error in Recents: next=" + next + " not in mRecentTasks");
- task.setNextAffiliate(null);
- // We know that next.mPrevAffiliate is always task, from above, so clear
- // its previous affiliate.
- next.setPrevAffiliate(null);
- break;
- }
- task = next;
- }
- // task is now the end of the list
- do {
- mRecentTasks.remove(task);
- mRecentTasks.add(i++, task);
- mTmpRecents.add(task);
- task.inRecents = true;
- } while ((task = task.mPrevAffiliate) != null);
+ for (int i = 0; i < N; i = processNextAffiliateChain(i)) {
}
+
mTmpRecents.clear();
// mRecentTasks is now in sorted, affiliated order.
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bba786d..957d705 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,12 +43,16 @@ public class NetworkAgentInfo {
public Network network;
public LinkProperties linkProperties;
public NetworkCapabilities networkCapabilities;
- public int currentScore;
public final NetworkMonitor networkMonitor;
public final NetworkMisc networkMisc;
public boolean created;
public boolean validated;
+ // This represents the last score received from the NetworkAgent.
+ private int currentScore;
+ // Penalty applied to scores of Networks that have not been validated.
+ private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
// The list of NetworkRequests being satisfied by this Network.
public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -80,11 +84,33 @@ public class NetworkAgentInfo {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
+ // Get the current score for this Network. This may be modified from what the
+ // NetworkAgent sent, as it has modifiers applied to it.
+ public int getCurrentScore() {
+ // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
+ // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
+ // score. The NetworkScore class would provide a nice place to centralize score constants
+ // so they are not scattered about the transports.
+
+ int score = currentScore;
+
+ if (!validated) score -= UNVALIDATED_SCORE_PENALTY;
+
+ if (score < 0) score = 0;
+
+ return score;
+ }
+
+ public void setCurrentScore(int newScore) {
+ currentScore = newScore;
+ }
+
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" +
network + "} lp{" +
linkProperties + "} nc{" +
- networkCapabilities + "} Score{" + currentScore + "} }";
+ networkCapabilities + "} Score{" + getCurrentScore() + "} " +
+ "validated{" + validated + "} created{" + created + "} }";
}
public String name() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 96872a7..9e33205 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -95,6 +95,18 @@ public class NetworkMonitor extends StateMachine {
"android.net.netmon.captive_portal_logged_in";
private static final String LOGGED_IN_RESULT = "result";
+ // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+ // The network should be used as a default internet connection. It was found to be:
+ // 1. a functioning network providing internet access, or
+ // 2. a captive portal and the user decided to use it as is.
+ public static final int NETWORK_TEST_RESULT_VALID = 0;
+ // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+ // The network should not be used as a default internet connection. It was found to be:
+ // 1. a captive portal and the user is prompted to sign-in, or
+ // 2. a captive portal and the user did not want to use it, or
+ // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
+ public static final int NETWORK_TEST_RESULT_INVALID = 1;
+
private static final int BASE = Protocol.BASE_NETWORK_MONITOR;
/**
@@ -104,10 +116,11 @@ public class NetworkMonitor extends StateMachine {
public static final int CMD_NETWORK_CONNECTED = BASE + 1;
/**
- * Inform ConnectivityService that the network is validated.
+ * Inform ConnectivityService that the network has been tested.
* obj = NetworkAgentInfo
+ * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
*/
- public static final int EVENT_NETWORK_VALIDATED = BASE + 2;
+ public static final int EVENT_NETWORK_TESTED = BASE + 2;
/**
* Inform NetworkMonitor to linger a network. The Monitor should
@@ -216,6 +229,9 @@ public class NetworkMonitor extends StateMachine {
private String mServer;
private boolean mIsCaptivePortalCheckEnabled = false;
+ // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
+ private boolean mUserDoesNotWant = false;
+
public boolean systemReady = false;
private State mDefaultState = new DefaultState();
@@ -290,9 +306,23 @@ public class NetworkMonitor extends StateMachine {
private class OfflineState extends State {
@Override
+ public void enter() {
+ mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
+ NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
+ }
+
+ @Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString());
- return NOT_HANDLED;
+ switch (message.what) {
+ case CMD_FORCE_REEVALUATION:
+ // If the user has indicated they explicitly do not want to use this network,
+ // don't allow a reevaluation as this will be pointless and could result in
+ // the user being annoyed with repeated unwanted notifications.
+ return mUserDoesNotWant ? HANDLED : NOT_HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
}
}
@@ -300,8 +330,8 @@ public class NetworkMonitor extends StateMachine {
@Override
public void enter() {
if (DBG) log("Validated");
- mConnectivityServiceHandler.sendMessage(
- obtainMessage(EVENT_NETWORK_VALIDATED, mNetworkAgentInfo));
+ mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
+ NETWORK_TEST_RESULT_VALID, 0, mNetworkAgentInfo));
}
@Override
@@ -393,6 +423,8 @@ public class NetworkMonitor extends StateMachine {
@Override
public void enter() {
+ mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
+ NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
// Wait for user to select sign-in notifcation.
mUserRespondedBroadcastReceiver = new UserRespondedBroadcastReceiver(
++mUserPromptedToken);
@@ -477,6 +509,7 @@ public class NetworkMonitor extends StateMachine {
if (message.arg1 != mCaptivePortalLoggedInToken)
return HANDLED;
if (message.arg2 == 0) {
+ mUserDoesNotWant = true;
// TODO: Should teardown network.
transitionTo(mOfflineState);
} else {
@@ -544,6 +577,12 @@ public class NetworkMonitor extends StateMachine {
mConnectivityServiceHandler.sendMessage(
obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo));
return HANDLED;
+ case CMD_FORCE_REEVALUATION:
+ // Ignore reevaluation attempts when lingering. A reevaluation could result
+ // in a transition to the validated state which would abort the linger
+ // timeout. Lingering is the result of score assessment; validity is
+ // irrelevant.
+ return HANDLED;
default:
return NOT_HANDLED;
}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 11818d8..df846a8 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -494,7 +494,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
Log.d(TAG, "SIM STATE is ready, SIM MCC/MNC is " + mccMnc);
synchronized (mLock) {
reloadGpsProperties(context, mProperties);
- mNIHandler.setSuplEsEnablement(mSuplEsEnabled);
+ mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
}
}
}
@@ -590,6 +590,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
com.android.internal.R.array.config_gpsParameters);
for (String item : configValues) {
Log.d(TAG, "GpsParamsResource: " + item);
+ // We need to support "KEY =", but not "=VALUE".
String[] split = item.split("=");
if (split.length == 2) {
properties.setProperty(split[0].trim().toUpperCase(), split[1]);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index efaf253..95332bc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3716,7 +3716,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
// Only SYSTEM_UID can override the userSetupComplete
if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
- && isUserSetupComplete(userHandle)) {
+ && hasUserSetupCompleted(userHandle)) {
throw new IllegalStateException(
"Trying to set profile owner but user is already set-up.");
}
@@ -3773,10 +3773,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public boolean hasUserSetupCompleted() {
+ return hasUserSetupCompleted(UserHandle.getCallingUserId());
+ }
+
+ private boolean hasUserSetupCompleted(int userHandle) {
if (!mHasFeature) {
return true;
}
- DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+ DevicePolicyData policy = getUserData(userHandle);
// If policy is null, return true, else check if the setup has completed.
return policy == null || policy.mUserSetupComplete;
}
@@ -3888,16 +3892,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
return AccountManager.get(mContext).getAccounts().length == 0;
} else {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0) == 0;
+ return !hasUserSetupCompleted(UserHandle.USER_OWNER);
}
}
- private boolean isUserSetupComplete(int userId) {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
- }
-
private void enforceCrossUserPermission(int userHandle) {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);