summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java6
-rw-r--r--services/core/java/com/android/server/MountService.java9
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java6
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java9
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java27
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java13
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java4
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java13
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java38
-rw-r--r--services/core/java/com/android/server/job/JobStore.java45
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java7
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java3
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java57
-rw-r--r--services/core/java/com/android/server/pm/Settings.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java64
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java39
20 files changed, 316 insertions, 68 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index e3d5d38..a2929bd 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -971,8 +971,8 @@ class AlarmManagerService extends SystemService {
// This is a special alarm that will put the system into idle until it goes off.
// The caller has given the time they want this to happen at, however we need
// to pull that earlier if there are existing alarms that have requested to
- // bring us out of idle.
- if (mNextWakeFromIdle != null) {
+ // bring us out of idle at an earlier time.
+ if (mNextWakeFromIdle != null && a.whenElapsed > mNextWakeFromIdle.whenElapsed) {
a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
}
// Add fuzz to make the alarm go off some time before the actual desired time.
@@ -1256,7 +1256,7 @@ class AlarmManagerService extends SystemService {
pw.print(" Idling until: ");
if (mPendingIdleUntil != null) {
pw.println(mPendingIdleUntil);
- mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf);
+ mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf);
} else {
pw.println("null");
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 4e721da..5e67414 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2415,8 +2415,13 @@ class MountService extends IMountService.Stub
}
try {
- mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
- new SensitiveArg(password));
+ if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
+ mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
+ CRYPTO_TYPES[type]);
+ } else {
+ mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
+ CRYPTO_TYPES[type], new SensitiveArg(password));
+ }
} catch (NativeDaemonConnectorException e) {
// Encryption failed
return e.getCode();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 433f707..ba9279c 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2023,9 +2023,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
synchronized (mQuotaLock) {
- if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
- mFirewallChainStates.get(chain) == enable) {
- // All is the same, nothing to do.
+ if (mFirewallChainStates.get(chain, false) == enable) {
+ // All is the same, nothing to do. This relies on the fact that netd has child
+ // chains default detached.
return;
}
mFirewallChainStates.put(chain, enable);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b87e109..970f1b5 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1314,6 +1314,15 @@ public final class ActiveServices {
if (!mRestartingServices.contains(r)) {
return;
}
+ if (!isServiceNeeded(r, false, false)) {
+ // Paranoia: is this service actually needed? In theory a service that is not
+ // needed should never remain on the restart list. In practice... well, there
+ // have been bugs where this happens, and bad things happen because the process
+ // ends up just being cached, so quickly killed, then restarted again and again.
+ // Let's not let that happen.
+ Slog.wtf(TAG, "Restarting service that is not needed: " + r);
+ return;
+ }
try {
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
} catch (TransactionTooLargeException e) {
@@ -2043,6 +2052,13 @@ public final class ActiveServices {
mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
+ if (!isServiceNeeded(sr, false, false)) {
+ // We were waiting for this service to start, but it is actually no
+ // longer needed. This could happen because bringDownServiceIfNeeded
+ // won't bring down a service that is pending... so now the pending
+ // is done, so let's drop it.
+ bringDownServiceLocked(sr);
+ }
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
@@ -2055,7 +2071,7 @@ public final class ActiveServices {
// be weird to bring up the process but arbitrarily not let the services
// run at this point just because their restart time hasn't come up.
if (mRestartingServices.size() > 0) {
- ServiceRecord sr = null;
+ ServiceRecord sr;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bf63931..17a86ca 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2467,8 +2467,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
final void doPendingActivityLaunchesLocked(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
- startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
- doResume && mPendingActivityLaunches.isEmpty(), null, null);
+
+ try {
+ startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ doResume && mPendingActivityLaunches.isEmpty(), null, null);
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception during pending activity launch pal=" + pal, e);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 960cbf1..6de8579 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -44,6 +44,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.server.DeviceIdleController;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -1284,6 +1285,7 @@ public final class BroadcastQueue {
final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
|| mPendingBroadcast != null) {
boolean printed = false;
@@ -1301,7 +1303,7 @@ public final class BroadcastQueue {
pw.println(" Active broadcasts [" + mQueueName + "]:");
}
pw.println(" Active Broadcast " + mQueueName + " #" + i + ":");
- br.dump(pw, " ");
+ br.dump(pw, " ", sdf);
}
printed = false;
needSep = true;
@@ -1319,7 +1321,7 @@ public final class BroadcastQueue {
pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
}
pw.println(" Active Ordered Broadcast " + mQueueName + " #" + i + ":");
- mOrderedBroadcasts.get(i).dump(pw, " ");
+ mOrderedBroadcasts.get(i).dump(pw, " ", sdf);
}
if (dumpPackage == null || (mPendingBroadcast != null
&& dumpPackage.equals(mPendingBroadcast.callerPackage))) {
@@ -1328,7 +1330,7 @@ public final class BroadcastQueue {
}
pw.println(" Pending broadcast [" + mQueueName + "]:");
if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
+ mPendingBroadcast.dump(pw, " ", sdf);
} else {
pw.println(" (null)");
}
@@ -1366,7 +1368,7 @@ public final class BroadcastQueue {
if (dumpAll) {
pw.print(" Historical Broadcast " + mQueueName + " #");
pw.print(i); pw.println(":");
- r.dump(pw, " ");
+ r.dump(pw, " ", sdf);
} else {
pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
pw.print(" ");
@@ -1400,7 +1402,6 @@ public final class BroadcastQueue {
}
// done skipping; dump the remainder of the ring. 'i' is still the ordinal within
// the overall broadcast history.
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
do {
ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
Intent intent = mBroadcastSummaryHistory[ringIndex];
@@ -1422,9 +1423,19 @@ public final class BroadcastQueue {
i++;
pw.print(" #"); pw.print(i); pw.print(": ");
pw.println(intent.toShortString(false, true, true, false));
- pw.print(" enq="); pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
- pw.print(" disp="); pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
- pw.print(" fin="); pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
+ pw.print(" ");
+ TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
+ - mSummaryHistoryEnqueueTime[ringIndex], pw);
+ pw.print(" dispatch ");
+ TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
+ - mSummaryHistoryDispatchTime[ringIndex], pw);
+ pw.println(" finish");
+ pw.print(" enq=");
+ pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
+ pw.print(" disp=");
+ pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
+ pw.print(" fin=");
+ pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
Bundle bundle = intent.getExtras();
if (bundle != null) {
pw.print(" extras: "); pw.println(bundle.toString());
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 1fbfd9f..b42bcff 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -32,6 +32,7 @@ import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -88,7 +89,7 @@ final class BroadcastRecord extends Binder {
ComponentName curComponent; // the receiver class that is currently running.
ActivityInfo curReceiver; // info about the receiver that is currently running.
- void dump(PrintWriter pw, String prefix) {
+ void dump(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
@@ -114,13 +115,19 @@ final class BroadcastRecord extends Binder {
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
pw.print(prefix); pw.print("enqueueClockTime=");
- pw.print(new Date(enqueueClockTime));
+ pw.print(sdf.format(new Date(enqueueClockTime)));
pw.print(" dispatchClockTime=");
- pw.println(new Date(dispatchClockTime));
+ pw.println(sdf.format(new Date(dispatchClockTime)));
pw.print(prefix); pw.print("dispatchTime=");
TimeUtils.formatDuration(dispatchTime, now, pw);
+ pw.print(" (");
+ TimeUtils.formatDuration(dispatchClockTime-enqueueClockTime, pw);
+ pw.print(" since enq)");
if (finishTime != 0) {
pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
+ pw.print(" (");
+ TimeUtils.formatDuration(finishTime-dispatchTime, pw);
+ pw.print(" since disp)");
} else {
pw.print(" receiverTime="); TimeUtils.formatDuration(receiverTime, now, pw);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 334bc18..b61f90e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -104,6 +104,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Random;
import java.util.Set;
@@ -3370,7 +3371,7 @@ public class SyncManager {
if (!smaller.containsKey(key)) {
return false;
}
- if (!bigger.get(key).equals(smaller.get(key))) {
+ if (!Objects.equals(bigger.get(key), smaller.get(key))) {
return false;
}
}
@@ -3378,7 +3379,6 @@ public class SyncManager {
}
/**
- * TODO: Get rid of this when we separate sync settings extras from dev specified extras.
* @return true if the provided key is used by the SyncManager in scheduling the sync.
*/
private static boolean isSyncSetting(String key) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5a13672..0205a20 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -792,8 +792,17 @@ public class InputManagerService extends IInputManager.Stub
}
@Override // Binder call
+ public int isInTabletMode() {
+ if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
+ "isInTabletMode()")) {
+ throw new SecurityException("Requires TABLET_MODE permission");
+ }
+ return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
+ }
+
+ @Override // Binder call
public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
- if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE_LISTENER,
+ if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
"registerTabletModeChangedListener()")) {
throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
}
@@ -1488,7 +1497,7 @@ public class InputManagerService extends IInputManager.Stub
switchMask);
}
- if ((switchMask & SW_TABLET_MODE) != 0) {
+ if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
args.argi2 = (int) (whenNanos >> 32);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 06bd583..3c50102 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -73,7 +73,7 @@ import com.android.server.job.controllers.TimeController;
*/
public class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
- static final boolean DEBUG = false;
+ public static final boolean DEBUG = false;
/** The number of concurrent jobs we run at one time. */
private static final int MAX_JOB_CONTEXTS_COUNT
= ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
@@ -99,7 +99,7 @@ public class JobSchedulerService extends com.android.server.SystemService
* Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
* things early.
*/
- static final int MIN_CONNECTIVITY_COUNT = 2;
+ static final int MIN_CONNECTIVITY_COUNT = 1; // Run connectivity jobs as soon as ready.
/**
* Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
* some work early.
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 43d5648..5515393 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -62,7 +62,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
*/
public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = JobSchedulerService.DEBUG;
private static final String TAG = "JobServiceContext";
/** Define the maximum # of jobs allowed to run on a service at once. */
private static final int defaultMaxActiveJobsPerService =
@@ -108,7 +108,13 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
int mVerb;
private AtomicBoolean mCancelled = new AtomicBoolean();
- /** All the information maintained about the job currently being executed. */
+ /**
+ * All the information maintained about the job currently being executed.
+ *
+ * Any reads (dereferences) not done from the handler thread must be synchronized on
+ * {@link #mLock}.
+ * Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
+ */
private JobStatus mRunningJob;
/** Binder to the client service. */
IJobService service;
@@ -192,7 +198,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
*/
JobStatus getRunningJob() {
synchronized (mLock) {
- return mRunningJob;
+ return mRunningJob == null ?
+ null : new JobStatus(mRunningJob);
}
}
@@ -253,15 +260,22 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (!name.equals(mRunningJob.getServiceComponent())) {
+ JobStatus runningJob;
+ synchronized (mLock) {
+ // This isn't strictly necessary b/c the JobServiceHandler is running on the main
+ // looper and at this point we can't get any binder callbacks from the client. Better
+ // safe than sorry.
+ runningJob = mRunningJob;
+ }
+ if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
this.service = IJobService.Stub.asInterface(service);
final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
- mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
+ mWakeLock.setWorkSource(new WorkSource(runningJob.getUid()));
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
@@ -279,13 +293,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne
* @return True if the binder calling is coming from the client we expect.
*/
private boolean verifyCallingUid() {
- if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
- if (DEBUG) {
- Slog.d(TAG, "Stale callback received, ignoring.");
+ synchronized (mLock) {
+ if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stale callback received, ignoring.");
+ }
+ return false;
}
- return false;
+ return true;
}
- return true;
}
/**
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 24d4f15..53125c0 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.PersistableBundle;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.format.DateUtils;
import android.util.AtomicFile;
import android.util.ArraySet;
import android.util.Pair;
@@ -552,9 +553,10 @@ public class JobStore {
return null;
}
- Pair<Long, Long> runtimes;
+ // Tuple of (earliest runtime, latest runtime) in elapsed realtime after disk load.
+ Pair<Long, Long> elapsedRuntimes;
try {
- runtimes = buildExecutionTimesFromXml(parser);
+ elapsedRuntimes = buildExecutionTimesFromXml(parser);
} catch (NumberFormatException e) {
if (DEBUG) {
Slog.d(TAG, "Error parsing execution time parameters, skipping.");
@@ -562,22 +564,45 @@ public class JobStore {
return null;
}
+ final long elapsedNow = SystemClock.elapsedRealtime();
if (XML_TAG_PERIODIC.equals(parser.getName())) {
try {
String val = parser.getAttributeValue(null, "period");
- jobBuilder.setPeriodic(Long.valueOf(val));
+ final long periodMillis = Long.valueOf(val);
+ jobBuilder.setPeriodic(periodMillis);
+ // As a sanity check, cap the recreated run time to be no later than 2 periods
+ // from now. This is the latest the periodic could be pushed out. This could
+ // happen if the periodic ran early (at the start of its period), and then the
+ // device rebooted.
+ if (elapsedRuntimes.second > elapsedNow + 2 * periodMillis) {
+ final long clampedEarlyRuntimeElapsed = elapsedNow + periodMillis;
+ final long clampedLateRuntimeElapsed = elapsedNow + 2 * periodMillis;
+ Slog.w(TAG,
+ String.format("Periodic job for uid='%d' persisted run-time is" +
+ " too big [%s, %s]. Clamping to [%s,%s]",
+ uid,
+ DateUtils.formatElapsedTime(elapsedRuntimes.first / 1000),
+ DateUtils.formatElapsedTime(elapsedRuntimes.second / 1000),
+ DateUtils.formatElapsedTime(
+ clampedEarlyRuntimeElapsed / 1000),
+ DateUtils.formatElapsedTime(
+ clampedLateRuntimeElapsed / 1000))
+ );
+ elapsedRuntimes =
+ Pair.create(clampedEarlyRuntimeElapsed, clampedLateRuntimeElapsed);
+ }
} catch (NumberFormatException e) {
Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
return null;
}
} else if (XML_TAG_ONEOFF.equals(parser.getName())) {
try {
- if (runtimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
- jobBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
+ if (elapsedRuntimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
+ jobBuilder.setMinimumLatency(elapsedRuntimes.first - elapsedNow);
}
- if (runtimes.second != JobStatus.NO_LATEST_RUNTIME) {
+ if (elapsedRuntimes.second != JobStatus.NO_LATEST_RUNTIME) {
jobBuilder.setOverrideDeadline(
- runtimes.second - SystemClock.elapsedRealtime());
+ elapsedRuntimes.second - elapsedNow);
}
} catch (NumberFormatException e) {
Slog.d(TAG, "Error reading job execution criteria, skipping.");
@@ -598,7 +623,8 @@ public class JobStore {
do {
eventType = parser.next();
} while (eventType == XmlPullParser.TEXT);
- if (!(eventType == XmlPullParser.START_TAG && XML_TAG_EXTRAS.equals(parser.getName()))) {
+ if (!(eventType == XmlPullParser.START_TAG
+ && XML_TAG_EXTRAS.equals(parser.getName()))) {
if (DEBUG) {
Slog.d(TAG, "Error reading extras, skipping.");
}
@@ -609,7 +635,8 @@ public class JobStore {
jobBuilder.setExtras(extras);
parser.nextTag(); // Consume </extras>
- return new JobStatus(jobBuilder.build(), uid, runtimes.first, runtimes.second);
+ return new JobStatus(
+ jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
}
private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 69c63f3..c02611f 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -82,6 +82,13 @@ public class JobStatus {
this.numFailures = numFailures;
}
+ /** Copy constructor. */
+ public JobStatus(JobStatus jobStatus) {
+ this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
+ this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
+ this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
+ }
+
/** Create a newly scheduled job. */
public JobStatus(JobInfo job, int uId) {
this(job, uId, 0);
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index cda7c32..21c30c7 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -18,6 +18,7 @@ package com.android.server.job.controllers;
import android.content.Context;
+import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -28,7 +29,7 @@ import java.io.PrintWriter;
* are ready to run, or whether they must be stopped.
*/
public abstract class StateController {
- protected static final boolean DEBUG = false;
+ protected static final boolean DEBUG = JobSchedulerService.DEBUG;
protected Context mContext;
protected StateChangedListener mStateChangedListener;
protected boolean mDeviceIdleMode;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 88e86e7..bc8957f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2511,9 +2511,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* Add or remove a uid to the firewall blacklist for all network ifaces.
*/
private void enableFirewallChainLocked(int chain, boolean enable) {
- if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
- mFirewallChainStates.get(chain) == enable) {
- // All is the same, nothing to do.
+ if (mFirewallChainStates.get(chain, false) == enable) {
+ // All is the same, nothing to do. This relies on the fact that netd has child
+ // chains default detached.
return;
}
mFirewallChainStates.put(chain, enable);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 313972b..6bf3001 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2282,7 +2282,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ mSdkVersion + "; regranting permissions for internal storage");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
@@ -7551,8 +7551,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// We would never need to extract libs for forward-locked and external packages,
// since the container service will do it for us. We shouldn't attempt to
// extract libs from system app when it was not updated.
- if (pkg.isForwardLocked() || isExternal(pkg) ||
- (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) ) {
+ if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() ||
+ (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) {
extractLibs = false;
}
@@ -7829,7 +7829,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
- final boolean asecApp = info.isForwardLocked() || isExternal(info);
+ final boolean asecApp = info.isForwardLocked() || info.isExternalAsec();
info.nativeLibraryRootDir = null;
info.nativeLibraryRootRequiresIsa = false;
@@ -8227,8 +8227,14 @@ public class PackageManagerService extends IPackageManager.Stub {
static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1;
static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2;
+ private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo,
+ int flags) {
+ final String volumeUuid = (pkgInfo != null) ? getVolumeUuidForPackage(pkgInfo) : null;
+ updatePermissionsLPw(changingPkg, pkgInfo, volumeUuid, flags);
+ }
+
private void updatePermissionsLPw(String changingPkg,
- PackageParser.Package pkgInfo, int flags) {
+ PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
// Make sure there are no dangling permission trees.
Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
@@ -8297,14 +8303,21 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
- grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
- changingPkg);
+ // Only replace for packages on requested volume
+ final String volumeUuid = getVolumeUuidForPackage(pkg);
+ final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
+ && Objects.equals(replaceVolumeUuid, volumeUuid);
+ grantPermissionsLPw(pkg, replace, changingPkg);
}
}
}
if (pkgInfo != null) {
- grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
+ // Only replace for packages on requested volume
+ final String volumeUuid = getVolumeUuidForPackage(pkgInfo);
+ final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
+ && Objects.equals(replaceVolumeUuid, volumeUuid);
+ grantPermissionsLPw(pkgInfo, replace, changingPkg);
}
}
@@ -12625,6 +12638,18 @@ public class PackageManagerService extends IPackageManager.Stub {
return installFlags;
}
+ private String getVolumeUuidForPackage(PackageParser.Package pkg) {
+ if (isExternal(pkg)) {
+ if (TextUtils.isEmpty(pkg.volumeUuid)) {
+ return StorageManager.UUID_PRIMARY_PHYSICAL;
+ } else {
+ return pkg.volumeUuid;
+ }
+ } else {
+ return StorageManager.UUID_PRIVATE_INTERNAL;
+ }
+ }
+
private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
if (isExternal(pkg)) {
if (TextUtils.isEmpty(pkg.volumeUuid)) {
@@ -13647,7 +13672,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ps != null) {
libDirRoot = ps.legacyNativeLibraryPathString;
}
- if (p != null && (isExternal(p) || p.isForwardLocked())) {
+ if (p != null && (p.isForwardLocked() || p.applicationInfo.isExternalAsec())) {
final long token = Binder.clearCallingIdentity();
try {
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
@@ -15501,7 +15526,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isMounted) {
if (DEBUG_SD_INSTALL)
Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr);
+ loadMediaPackages(processCids, uidArr, externalStorage);
startCleaningPackages();
mInstallerService.onSecureContainersAvailable();
} else {
@@ -15556,7 +15581,8 @@ public class PackageManagerService extends IPackageManager.Stub {
* the cid is added to list of removeCids. We currently don't delete stale
* containers.
*/
- private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr) {
+ private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr,
+ boolean externalStorage) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<AsecInstallArgs> keys = processCids.keySet();
@@ -15628,7 +15654,10 @@ public class PackageManagerService extends IPackageManager.Stub {
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
- final VersionInfo ver = mSettings.getExternalVersion();
+ final VersionInfo ver = externalStorage ? mSettings.getExternalVersion()
+ : mSettings.getInternalVersion();
+ final String volumeUuid = externalStorage ? StorageManager.UUID_PRIMARY_PHYSICAL
+ : StorageManager.UUID_PRIVATE_INTERNAL;
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
@@ -15636,7 +15665,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ mSdkVersion + "; regranting permissions for external");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, volumeUuid, updateFlags);
// Yay, everything is now upgraded
ver.forceCurrent();
@@ -15769,7 +15798,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ mSdkVersion + "; regranting permissions for " + vol.fsUuid);
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, vol.fsUuid, updateFlags);
// Yay, everything is now upgraded
ver.forceCurrent();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 943e649..647c17b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -517,7 +517,18 @@ final class Settings {
ArrayList<String> removeStage = new ArrayList<String>();
for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) {
final SharedUserSetting sus = entry.getValue();
- if (sus == null || sus.packages.size() == 0) {
+ if (sus == null) {
+ removeStage.add(entry.getKey());
+ continue;
+ }
+ // remove packages that are no longer installed
+ for (Iterator<PackageSetting> iter = sus.packages.iterator(); iter.hasNext();) {
+ PackageSetting ps = iter.next();
+ if (mPackages.get(ps.name) == null) {
+ iter.remove();
+ }
+ }
+ if (sus.packages.size() == 0) {
removeStage.add(entry.getKey());
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 726d29d..42042b9 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1064,6 +1064,8 @@ class WindowStateAnimator {
mAnimator.getScreenRotationAnimationLocked(displayId);
final boolean screenAnimation =
screenRotationAnimation != null && screenRotationAnimation.isAnimating();
+
+ mHasClipRect = false;
if (selfTransformation || attachedTransformation != null
|| appTransformation != null || screenAnimation) {
// cache often used attributes locally
@@ -1139,7 +1141,6 @@ class WindowStateAnimator {
// transforming since it is more important to have that
// animation be smooth.
mShownAlpha = mAlpha;
- mHasClipRect = false;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
new file mode 100644
index 0000000..be6861c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
@@ -0,0 +1,64 @@
+package com.android.server.content;
+
+import android.os.Bundle;
+
+import junit.framework.TestCase;
+
+public class SyncManagerTest extends TestCase {
+
+ final String KEY_1 = "key_1";
+ final String KEY_2 = "key_2";
+
+ public void testSyncExtrasEquals_WithNull() throws Exception {
+ Bundle b1 = new Bundle();
+ Bundle b2 = new Bundle();
+
+ b1.putString(KEY_1, null);
+ b2.putString(KEY_1, null);
+
+ assertTrue("Null extra not properly compared between bundles.",
+ SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
+ }
+
+ public void testSyncExtrasEqualsBigger_WithNull() throws Exception {
+ Bundle b1 = new Bundle();
+ Bundle b2 = new Bundle();
+
+ b1.putString(KEY_1, null);
+ b2.putString(KEY_1, null);
+
+ b1.putString(KEY_2, "bla");
+ b2.putString(KEY_2, "bla");
+
+ assertTrue("Extras not properly compared between bundles.",
+ SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
+ }
+
+ public void testSyncExtrasEqualsFails_differentValues() throws Exception {
+ Bundle b1 = new Bundle();
+ Bundle b2 = new Bundle();
+
+ b1.putString(KEY_1, null);
+ b2.putString(KEY_1, null);
+
+ b1.putString(KEY_2, "bla");
+ b2.putString(KEY_2, "ble"); // different key
+
+ assertFalse("Extras considered equal when they are different.",
+ SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
+ }
+
+ public void testSyncExtrasEqualsFails_differentNulls() throws Exception {
+ Bundle b1 = new Bundle();
+ Bundle b2 = new Bundle();
+
+ b1.putString(KEY_1, null);
+ b2.putString(KEY_1, "bla"); // different key
+
+ b1.putString(KEY_2, "ble");
+ b2.putString(KEY_2, "ble");
+
+ assertFalse("Extras considered equal when they are different.",
+ SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index bd64392..0b73beb 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -6,6 +6,7 @@ import android.content.Context;
import android.app.job.JobInfo;
import android.app.job.JobInfo.Builder;
import android.os.PersistableBundle;
+import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.util.Log;
@@ -102,6 +103,14 @@ public class JobStoreTest extends AndroidTestCase {
Iterator<JobStatus> it = jobStatusSet.iterator();
JobStatus loaded1 = it.next();
JobStatus loaded2 = it.next();
+
+ // Reverse them so we know which comparison to make.
+ if (loaded1.getJobId() != 8) {
+ JobStatus tmp = loaded1;
+ loaded1 = loaded2;
+ loaded2 = tmp;
+ }
+
assertTasksEqual(task1, loaded1.getJob());
assertTasksEqual(task2, loaded2.getJob());
assertTrue("JobStore#contains invalid.", mTaskStoreUnderTest.containsJob(taskStatus1));
@@ -143,6 +152,36 @@ public class JobStoreTest extends AndroidTestCase {
assertTasksEqual(task, loaded.getJob());
}
+ public void testMassivePeriodClampedOnRead() throws Exception {
+ final long TEN_SECONDS = 10000L;
+ JobInfo.Builder b = new Builder(8, mComponent)
+ .setPeriodic(TEN_SECONDS)
+ .setPersisted(true);
+ final long invalidLateRuntimeElapsedMillis =
+ SystemClock.elapsedRealtime() + (TEN_SECONDS * 2) + 5000; // >2P from now.
+ final long invalidEarlyRuntimeElapsedMillis =
+ invalidLateRuntimeElapsedMillis - TEN_SECONDS; // Early is (late - period).
+ final JobStatus js = new JobStatus(b.build(), SOME_UID,
+ invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
+
+ mTaskStoreUnderTest.add(js);
+ Thread.sleep(IO_WAIT);
+
+ final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+ assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size());
+ JobStatus loaded = jobStatusSet.iterator().next();
+
+ // Assert early runtime was clamped to be under now + period. We can do <= here b/c we'll
+ // call SystemClock.elapsedRealtime after doing the disk i/o.
+ final long newNowElapsed = SystemClock.elapsedRealtime();
+ assertTrue("Early runtime wasn't correctly clamped.",
+ loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS);
+ // Assert late runtime was clamped to be now + period*2.
+ assertTrue("Early runtime wasn't correctly clamped.",
+ loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS*2);
+ }
+
/**
* Helper function to throw an error if the provided task and TaskStatus objects are not equal.
*/