diff options
Diffstat (limited to 'services')
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. */ |