Merge "Change app selection policy for post-OTA verification" into nyc-dev
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 2be55317..3050ac8 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -510,11 +510,15 @@
}
// Setup jit profile support.
+ //
// It is ok to call this multiple times if the application gets updated with new splits.
// The runtime only keeps track of unique code paths and can handle re-registration of
// the same code path. There's no need to pass `addedPaths` since any new code paths
// are already in `mApplicationInfo`.
- if (needToSetupJitProfiles) {
+ //
+ // It is NOT ok to call this function from the system_server (for any of the packages it
+ // loads code from) so we explicitly disallow it there.
+ if (needToSetupJitProfiles && !ActivityThread.isSystem()) {
// Temporarily disable logging of disk reads/writes on the Looper thread
// as this is early and necessary. Write is only needed to create the
// profile file if it's not already there.
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index f13cbae..5db0f16 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -216,7 +216,7 @@
}
if (chosen.versionCode > toUse.versionCode) {
throw new MissingWebViewPackageException("Failed to verify WebView provider, "
- + "version code mismatch, expected: " + chosen.versionCode
+ + "version code is lower than expected: " + chosen.versionCode
+ " actual: " + toUse.versionCode);
}
if (getWebViewLibrary(toUse.applicationInfo) == null) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7458898..9fc17a2 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -72,6 +72,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -2047,6 +2048,65 @@
}
}
+ private void closeSocketsForFirewallChain(int chain, String chainName) {
+ // UID ranges to close sockets on.
+ UidRange[] ranges;
+ // UID ranges whose sockets we won't touch.
+ int[] exemptUids;
+
+ SparseIntArray rules = getUidFirewallRules(chain);
+ int numUids = 0;
+
+ if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
+ // Close all sockets on all non-system UIDs...
+ ranges = new UidRange[] {
+ // TODO: is there a better way of finding all existing users? If so, we could
+ // specify their ranges here.
+ new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+ };
+ // ... except for the UIDs that have allow rules.
+ exemptUids = new int[rules.size()];
+ for (int i = 0; i < exemptUids.length; i++) {
+ if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ exemptUids[numUids] = rules.keyAt(i);
+ numUids++;
+ }
+ }
+ // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length.
+ // But the code does not guarantee this in any way, and at least in one case - if we add
+ // a UID rule to the firewall, and then disable the firewall - the chains can contain
+ // the wrong type of rule. In this case, don't close connections that we shouldn't.
+ //
+ // TODO: tighten up this code by ensuring we never set the wrong type of rule, and
+ // fix setFirewallEnabled to grab mQuotaLock and clear rules.
+ if (numUids != exemptUids.length) {
+ exemptUids = Arrays.copyOf(exemptUids, numUids);
+ }
+ } else {
+ // Close sockets for every UID that has a deny rule...
+ ranges = new UidRange[rules.size()];
+ for (int i = 0; i < ranges.length; i++) {
+ if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ int uid = rules.keyAt(i);
+ ranges[numUids] = new UidRange(uid, uid);
+ numUids++;
+ }
+ }
+ // As above; usually numUids == ranges.length, but not always.
+ if (numUids != ranges.length) {
+ ranges = Arrays.copyOf(ranges, numUids);
+ }
+ // ... with no exceptions.
+ exemptUids = new int[0];
+ }
+
+ try {
+ mNetdService.socketDestroy(ranges, exemptUids);
+ } catch(RemoteException | ServiceSpecificException e) {
+ Slog.e(TAG, "Error closing sockets after enabling chain " + chainName + ": " + e);
+ }
+ }
+
@Override
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
@@ -2059,25 +2119,35 @@
mFirewallChainStates.put(chain, enable);
final String operation = enable ? "enable_chain" : "disable_chain";
+ String chainName;
+ switch(chain) {
+ case FIREWALL_CHAIN_STANDBY:
+ chainName = FIREWALL_CHAIN_NAME_STANDBY;
+ break;
+ case FIREWALL_CHAIN_DOZABLE:
+ chainName = FIREWALL_CHAIN_NAME_DOZABLE;
+ break;
+ case FIREWALL_CHAIN_POWERSAVE:
+ chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
+ break;
+ default:
+ throw new IllegalArgumentException("Bad child chain: " + chain);
+ }
+
try {
- String chainName;
- switch(chain) {
- case FIREWALL_CHAIN_STANDBY:
- chainName = FIREWALL_CHAIN_NAME_STANDBY;
- break;
- case FIREWALL_CHAIN_DOZABLE:
- chainName = FIREWALL_CHAIN_NAME_DOZABLE;
- break;
- case FIREWALL_CHAIN_POWERSAVE:
- chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
- break;
- default:
- throw new IllegalArgumentException("Bad child chain: " + chain);
- }
mConnector.execute("firewall", operation, chainName);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
+
+ // Close any sockets that were opened by the affected UIDs. This has to be done after
+ // disabling network connectivity, in case they react to the socket close by reopening
+ // the connection and race with the iptables commands that enable the firewall. All
+ // whitelist and blacklist chains allow RSTs through.
+ if (enable) {
+ if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
+ closeSocketsForFirewallChain(chain, chainName);
+ }
}
}
@@ -2376,7 +2446,7 @@
}
private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
- pw.print("UID firewall");
+ pw.print("UID firewall ");
pw.print(name);
pw.print(" rule: [");
final int size = rules.size();
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 8af0af0..92aa8d9 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -405,6 +405,7 @@
private final SyncHandler mSyncHandler;
private volatile boolean mBootCompleted = false;
+ private volatile boolean mJobServiceReady = false;
private ConnectivityManager getConnectivityManager() {
synchronized (this) {
@@ -2177,11 +2178,7 @@
static final int MESSAGE_SCHEDULE_SYNC = 12;
static final int MESSAGE_UPDATE_PERIODIC_SYNC = 13;
static final int MESSAGE_REMOVE_PERIODIC_SYNC = 14;
- /**
- * Posted delayed in order to expire syncs that are long-running.
- * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
- */
- private static final int MESSAGE_SYNC_EXPIRED = 7;
+
/**
* Posted periodically to monitor network process for long-running syncs.
* obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
@@ -2209,7 +2206,7 @@
}
void checkIfDeviceReady() {
- if (mProvisioned && mBootCompleted) {
+ if (mProvisioned && mBootCompleted && mJobServiceReady) {
synchronized(this) {
mSyncStorageEngine.restoreAllPeriodicSyncs();
// Dispatch any stashed messages.
@@ -2229,7 +2226,7 @@
*/
private boolean tryEnqueueMessageUntilReadyToRun(Message msg) {
synchronized (this) {
- if (!mBootCompleted || !mProvisioned) {
+ if (!mBootCompleted || !mProvisioned || !mJobServiceReady) {
// Need to copy the message bc looper will recycle it.
Message m = Message.obtain(msg);
mUnreadyQueue.add(m);
@@ -2252,6 +2249,8 @@
if (msg.what == MESSAGE_JOBSERVICE_OBJECT) {
Slog.i(TAG, "Got SyncJobService instance.");
mSyncJobService = (SyncJobService) msg.obj;
+ mJobServiceReady = true;
+ checkIfDeviceReady();
} else if (msg.what == SyncHandler.MESSAGE_ACCOUNTS_UPDATED) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
@@ -2972,7 +2971,6 @@
Slog.v(TAG, "removing all MESSAGE_MONITOR_SYNC & MESSAGE_SYNC_EXPIRED for "
+ activeSyncContext.toString());
}
- mSyncHandler.removeMessages(SyncHandler.MESSAGE_SYNC_EXPIRED, activeSyncContext);
mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index f6255af..0a25402 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -148,7 +148,7 @@
// jobs because PackageDexOptimizer.performDexOpt is synchronized.
pm.performDexOpt(pkg,
/* instruction set */ null,
- /* checkProfiles */ false,
+ /* checkProfiles */ true,
PackageManagerService.REASON_BOOT,
/* force */ false);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 547379d..38144e4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7197,7 +7197,7 @@
performDexOpt(pkg.packageName,
null /* instructionSet */,
- false /* checkProfiles */,
+ true /* checkProfiles */,
causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* force */);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index d90d922..91de797 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -536,16 +536,37 @@
}
/**
+ * Both versionCodes should be from a WebView provider package implemented by Chromium.
+ * VersionCodes from other kinds of packages won't make any sense in this method.
+ *
+ * An introduction to Chromium versionCode scheme:
+ * "BBBBPPPAX"
+ * BBBB: 4 digit branch number. It monotonically increases over time.
+ * PPP: patch number in the branch. It is padded with zeroes to the left. These three digits may
+ * change their meaning in the future.
+ * A: architecture digit.
+ * X: A digit to differentiate APKs for other reasons.
+ *
+ * This method takes the "BBBB" of versionCodes and compare them.
+ *
+ * @return true if versionCode1 is higher than or equal to versionCode2.
+ */
+ private static boolean versionCodeGE(int versionCode1, int versionCode2) {
+ int v1 = versionCode1 / 100000;
+ int v2 = versionCode2 / 100000;
+
+ return v1 >= v2;
+ }
+
+ /**
* Returns whether this provider is valid for use as a WebView provider.
*/
public boolean isValidProvider(WebViewProviderInfo configInfo,
PackageInfo packageInfo) {
- if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
- && packageInfo.versionCode < getMinimumVersionCode()
+ if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
&& !mSystemInterface.systemIsDebuggable()) {
- // Non-system package webview providers may be downgraded arbitrarily low, prevent
- // that by enforcing minimum version code. This check is only enforced for user
- // builds.
+ // Webview providers may be downgraded arbitrarily low, prevent that by enforcing
+ // minimum version code. This check is only enforced for user builds.
return false;
}
if (providerHasValidSignature(configInfo, packageInfo, mSystemInterface) &&