Merge "AccountManagerService send pkg uid when creating notification channel"
diff --git a/api/system-current.txt b/api/system-current.txt
index 60d7f2f..9328420 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11393,6 +11393,7 @@
field public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23; // 0xffffffe9
field public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26; // 0xffffffe6
field public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; // 0xfffffff6
+ field public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27; // 0xffffffe5
field public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; // 0xfffffff8
field public static final int INSTALL_FAILED_TEST_ONLY = -15; // 0xfffffff1
field public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7; // 0xfffffff9
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e89dc0b..b4e6bd5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -808,6 +808,11 @@
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
+ // TODO: Debugging added for bug:36406078 . Remove when done
+ if (Log.isLoggable("36406078", Log.DEBUG)) {
+ Log.d(TAG, "scheduleReceiver");
+ }
+
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
@@ -894,6 +899,11 @@
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial) {
+ // TODO: Debugging added for bug:36406078 . Remove when done
+ if (Log.isLoggable("36406078", Log.DEBUG)) {
+ Log.d(TAG, "bindApplication: " + processName);
+ }
+
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
@@ -3229,6 +3239,10 @@
if (receiver.getPendingResult() != null) {
data.finish();
}
+ // TODO: Debugging added for bug:36406078 . Remove when done
+ if (Log.isLoggable("36406078", Log.DEBUG)) {
+ Log.d(TAG, "handleReceiver done");
+ }
}
// Instantiate a BackupAgent and tell it that it's alive
@@ -5764,6 +5778,10 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ // TODO: Debugging added for bug:36406078 . Remove when done
+ if (Log.isLoggable("36406078", Log.DEBUG)) {
+ Log.d(TAG, "handleBindApplication done");
+ }
}
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bb35928..71db5d3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1069,6 +1069,16 @@
public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;
/**
+ * Installation return code: this is passed to the
+ * {@link IPackageInstallObserver} if the new package attempts to downgrade the
+ * target sandbox version of the app.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27;
+
+ /**
* Installation parse return code: this is passed to the
* {@link IPackageInstallObserver} if the parser was given a path that is
* not a file, or does not end with the expected '.apk' extension.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 96e2626..25f9c30 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16692,6 +16692,16 @@
+ " target SDK " + oldTargetSdk + " does.");
return;
}
+ // Prevent apps from downgrading their targetSandbox.
+ final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
+ final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
+ if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
+ res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Package " + pkg.packageName + " new target sandbox "
+ + newTargetSandbox + " is incompatible with the previous value of"
+ + oldTargetSandbox + ".");
+ return;
+ }
// Prevent installing of child packages
if (oldPackage.parentPackage != null) {
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 308632f..374aee1 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.times;
@@ -32,7 +31,6 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerInternal;
-import android.accounts.AuthenticatorDescription;
import android.accounts.CantAddAccountActivity;
import android.accounts.IAccountManagerResponse;
import android.app.AppOpsManager;
@@ -49,11 +47,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCacheListener;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
-import android.content.pm.RegisteredServicesCache.ServiceInfo;
import android.database.Cursor;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
@@ -62,6 +58,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
@@ -78,16 +75,18 @@
import org.mockito.MockitoAnnotations;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
/**
@@ -2616,6 +2615,142 @@
}
}
+ @SmallTest
+ public void testConcurrencyReadWrite() throws Exception {
+ // Test 2 threads calling getAccounts and 1 thread setAuthToken
+ unlockSystemUser();
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+ Account a1 = new Account("account1",
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ mAms.addAccountExplicitly(a1, "p1", null);
+ List<String> errors = Collections.synchronizedList(new ArrayList<>());
+ int readerCount = 2;
+ ExecutorService es = Executors.newFixedThreadPool(readerCount + 1);
+ AtomicLong readTotalTime = new AtomicLong(0);
+ AtomicLong writeTotalTime = new AtomicLong(0);
+ final CyclicBarrier cyclicBarrier = new CyclicBarrier(readerCount + 1);
+
+ final int loopSize = 20;
+ for (int t = 0; t < readerCount; t++) {
+ es.submit(() -> {
+ for (int i = 0; i < loopSize; i++) {
+ String logPrefix = Thread.currentThread().getName() + " " + i;
+ waitForCyclicBarrier(cyclicBarrier);
+ cyclicBarrier.reset();
+ SystemClock.sleep(1); // Ensure that writer wins
+ Log.d(TAG, logPrefix + " getAccounts started");
+ long ti = System.currentTimeMillis();
+ try {
+ Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+ if (accounts == null || accounts.length != 1
+ || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
+ accounts[0].type)) {
+ String msg = logPrefix + ": Unexpected accounts: " + Arrays
+ .toString(accounts);
+ Log.e(TAG, " " + msg);
+ errors.add(msg);
+ }
+ Log.d(TAG, logPrefix + " getAccounts done");
+ } catch (Exception e) {
+ String msg = logPrefix + ": getAccounts failed " + e;
+ Log.e(TAG, msg, e);
+ errors.add(msg);
+ }
+ ti = System.currentTimeMillis() - ti;
+ readTotalTime.addAndGet(ti);
+ }
+ });
+ }
+
+ es.submit(() -> {
+ for (int i = 0; i < loopSize; i++) {
+ String logPrefix = Thread.currentThread().getName() + " " + i;
+ waitForCyclicBarrier(cyclicBarrier);
+ long ti = System.currentTimeMillis();
+ Log.d(TAG, logPrefix + " setAuthToken started");
+ try {
+ mAms.setAuthToken(a1, "t1", "v" + i);
+ Log.d(TAG, logPrefix + " setAuthToken done");
+ } catch (Exception e) {
+ errors.add(logPrefix + ": setAuthToken failed: " + e);
+ }
+ ti = System.currentTimeMillis() - ti;
+ writeTotalTime.addAndGet(ti);
+ }
+ });
+ es.shutdown();
+ assertTrue("Time-out waiting for jobs to finish",
+ es.awaitTermination(10, TimeUnit.SECONDS));
+ es.shutdownNow();
+ assertTrue("Errors: " + errors, errors.isEmpty());
+ Log.i(TAG, "testConcurrencyReadWrite: readTotalTime=" + readTotalTime + " avg="
+ + (readTotalTime.doubleValue() / readerCount / loopSize));
+ Log.i(TAG, "testConcurrencyReadWrite: writeTotalTime=" + writeTotalTime + " avg="
+ + (writeTotalTime.doubleValue() / loopSize));
+ }
+
+ @SmallTest
+ public void testConcurrencyRead() throws Exception {
+ // Test 2 threads calling getAccounts
+ unlockSystemUser();
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+ Account a1 = new Account("account1",
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ mAms.addAccountExplicitly(a1, "p1", null);
+ List<String> errors = Collections.synchronizedList(new ArrayList<>());
+ int readerCount = 2;
+ ExecutorService es = Executors.newFixedThreadPool(readerCount + 1);
+ AtomicLong readTotalTime = new AtomicLong(0);
+
+ final int loopSize = 20;
+ for (int t = 0; t < readerCount; t++) {
+ es.submit(() -> {
+ for (int i = 0; i < loopSize; i++) {
+ String logPrefix = Thread.currentThread().getName() + " " + i;
+ Log.d(TAG, logPrefix + " getAccounts started");
+ long ti = System.currentTimeMillis();
+ try {
+ Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+ if (accounts == null || accounts.length != 1
+ || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
+ accounts[0].type)) {
+ String msg = logPrefix + ": Unexpected accounts: " + Arrays
+ .toString(accounts);
+ Log.e(TAG, " " + msg);
+ errors.add(msg);
+ }
+ Log.d(TAG, logPrefix + " getAccounts done");
+ } catch (Exception e) {
+ String msg = logPrefix + ": getAccounts failed " + e;
+ Log.e(TAG, msg, e);
+ errors.add(msg);
+ }
+ ti = System.currentTimeMillis() - ti;
+ readTotalTime.addAndGet(ti);
+ }
+ });
+ }
+ es.shutdown();
+ assertTrue("Time-out waiting for jobs to finish",
+ es.awaitTermination(10, TimeUnit.SECONDS));
+ es.shutdownNow();
+ assertTrue("Errors: " + errors, errors.isEmpty());
+ Log.i(TAG, "testConcurrencyRead: readTotalTime=" + readTotalTime + " avg="
+ + (readTotalTime.doubleValue() / readerCount / loopSize));
+ }
+
+ private void waitForCyclicBarrier(CyclicBarrier cyclicBarrier) {
+ try {
+ cyclicBarrier.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ throw new IllegalStateException("Should not throw " + e, e);
+ }
+ }
+
private void waitForLatch(CountDownLatch latch) {
try {
latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);