diff options
Diffstat (limited to 'services')
44 files changed, 1532 insertions, 593 deletions
diff --git a/services/Android.mk b/services/Android.mk index 8777085..1918db5 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -24,6 +24,7 @@ services := \ appwidget \ backup \ devicepolicy \ + midi \ net \ print \ restrictions \ diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 31f9e22..45b0fb2 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -29,6 +29,7 @@ import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupTransport; import android.app.backup.FullBackup; +import android.app.backup.FullBackupDataOutput; import android.app.backup.RestoreDescription; import android.app.backup.RestoreSet; import android.app.backup.IBackupManager; @@ -134,6 +135,7 @@ import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.Deflater; @@ -369,7 +371,7 @@ public class BackupManagerService { // we're now good to go, so start the backup alarms if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups"); KeyValueBackupJob.schedule(mContext); - scheduleNextFullBackupJob(); + scheduleNextFullBackupJob(0); } } } @@ -726,7 +728,7 @@ public class BackupManagerService { { try { BackupRestoreTask task = (BackupRestoreTask) msg.obj; - task.operationComplete(); + task.operationComplete(msg.arg1); } catch (ClassCastException e) { Slog.e(TAG, "Invalid completion in flight, obj=" + msg.obj); } @@ -1784,7 +1786,7 @@ public class BackupManagerService { PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { enqueueFullBackup(packageName, now); - scheduleNextFullBackupJob(); + scheduleNextFullBackupJob(0); } // Transport maintenance: rebind to known existing transports that have @@ -2224,7 +2226,7 @@ public class BackupManagerService { void execute(); // An operation that wanted a callback has completed - void operationComplete(); + void operationComplete(int result); // An operation that wanted a callback has timed out void handleTimeout(); @@ -2792,7 +2794,7 @@ public class BackupManagerService { } @Override - public void operationComplete() { + public void operationComplete(int unusedResult) { // The agent reported back to us! if (mBackupData == null) { @@ -3128,8 +3130,23 @@ public class BackupManagerService { // Core logic for performing one package's full backup, gathering the tarball from the // application and emitting it to the designated OutputStream. + + // Callout from the engine to an interested participant that might need to communicate + // with the agent prior to asking it to move data + interface FullBackupPreflight { + /** + * Perform the preflight operation necessary for the given package. + * @param pkg The name of the package being proposed for full-data backup + * @param agent Live BackupAgent binding to the target app's agent + * @return BackupTransport.TRANSPORT_OK to proceed with the backup operation, + * or one of the other BackupTransport.* error codes as appropriate + */ + int preflightFullBackup(PackageInfo pkg, IBackupAgent agent); + }; + class FullBackupEngine { OutputStream mOutput; + FullBackupPreflight mPreflightHook; IFullBackupRestoreObserver mObserver; File mFilesDir; File mManifestFile; @@ -3160,8 +3177,7 @@ public class BackupManagerService { @Override public void run() { try { - BackupDataOutput output = new BackupDataOutput( - mPipe.getFileDescriptor()); + FullBackupDataOutput output = new FullBackupDataOutput(mPipe); if (mWriteManifest) { final boolean writeWidgetData = mWidgetData != null; @@ -3204,15 +3220,16 @@ public class BackupManagerService { } } - FullBackupEngine(OutputStream output, String packageName, boolean alsoApks) { + FullBackupEngine(OutputStream output, String packageName, FullBackupPreflight preflightHook, + boolean alsoApks) { mOutput = output; + mPreflightHook = preflightHook; mIncludeApks = alsoApks; mFilesDir = new File("/data/system"); mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME); mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME); } - public int backupOnePackage(PackageInfo pkg) throws RemoteException { int result = BackupTransport.TRANSPORT_OK; Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName); @@ -3222,42 +3239,52 @@ public class BackupManagerService { if (agent != null) { ParcelFileDescriptor[] pipes = null; try { - pipes = ParcelFileDescriptor.createPipe(); - - ApplicationInfo app = pkg.applicationInfo; - final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); - final boolean sendApk = mIncludeApks - && !isSharedStorage - && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0) - && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 || + // Call the preflight hook, if any + if (mPreflightHook != null) { + result = mPreflightHook.preflightFullBackup(pkg, agent); + if (MORE_DEBUG) { + Slog.v(TAG, "preflight returned " + result); + } + } + + // If we're still good to go after preflighting, start moving data + if (result == BackupTransport.TRANSPORT_OK) { + pipes = ParcelFileDescriptor.createPipe(); + + ApplicationInfo app = pkg.applicationInfo; + final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); + final boolean sendApk = mIncludeApks + && !isSharedStorage + && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0) + && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 || (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); - byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName, - UserHandle.USER_OWNER); + byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName, + UserHandle.USER_OWNER); - final int token = generateToken(); - FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1], - token, sendApk, !isSharedStorage, widgetBlob); - pipes[1].close(); // the runner has dup'd it - pipes[1] = null; - Thread t = new Thread(runner, "app-data-runner"); - t.start(); + final int token = generateToken(); + FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1], + token, sendApk, !isSharedStorage, widgetBlob); + pipes[1].close(); // the runner has dup'd it + pipes[1] = null; + Thread t = new Thread(runner, "app-data-runner"); + t.start(); - // Now pull data from the app and stuff it into the output - try { - routeSocketDataToOutput(pipes[0], mOutput); - } catch (IOException e) { - Slog.i(TAG, "Caught exception reading from agent", e); - result = BackupTransport.AGENT_ERROR; - } + // Now pull data from the app and stuff it into the output + try { + routeSocketDataToOutput(pipes[0], mOutput); + } catch (IOException e) { + Slog.i(TAG, "Caught exception reading from agent", e); + result = BackupTransport.AGENT_ERROR; + } - if (!waitUntilOperationComplete(token)) { - Slog.e(TAG, "Full backup failed on package " + pkg.packageName); - result = BackupTransport.AGENT_ERROR; - } else { - if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName); + if (!waitUntilOperationComplete(token)) { + Slog.e(TAG, "Full backup failed on package " + pkg.packageName); + result = BackupTransport.AGENT_ERROR; + } else { + if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName); + } } - } catch (IOException e) { Slog.e(TAG, "Error backing up " + pkg.packageName, e); result = BackupTransport.AGENT_ERROR; @@ -3282,7 +3309,7 @@ public class BackupManagerService { return result; } - private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) { + private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) { // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here // TODO: handle backing up split APKs final String appSourceDir = pkg.applicationInfo.getBaseCodePath(); @@ -3781,7 +3808,7 @@ public class BackupManagerService { final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); - mBackupEngine = new FullBackupEngine(out, pkg.packageName, mIncludeApks); + mBackupEngine = new FullBackupEngine(out, pkg.packageName, null, mIncludeApks); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); mBackupEngine.backupOnePackage(pkg); @@ -3828,13 +3855,13 @@ public class BackupManagerService { static final String TAG = "PFTBT"; ArrayList<PackageInfo> mPackages; boolean mUpdateSchedule; - AtomicBoolean mLatch; + CountDownLatch mLatch; AtomicBoolean mKeepRunning; // signal from job scheduler FullBackupJob mJob; // if a scheduled job needs to be finished afterwards PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, String[] whichPackages, boolean updateSchedule, - FullBackupJob runningJob, AtomicBoolean latch) { + FullBackupJob runningJob, CountDownLatch latch) { super(observer); mUpdateSchedule = updateSchedule; mLatch = latch; @@ -3892,6 +3919,7 @@ public class BackupManagerService { ParcelFileDescriptor[] transportPipes = null; PackageInfo currentPackage; + long backoff = 0; try { if (!mEnabled || !mProvisioned) { @@ -3944,10 +3972,10 @@ public class BackupManagerService { // Now set up the backup engine / data source end of things enginePipes = ParcelFileDescriptor.createPipe(); - AtomicBoolean runnerLatch = new AtomicBoolean(false); + CountDownLatch runnerLatch = new CountDownLatch(1); SinglePackageBackupRunner backupRunner = new SinglePackageBackupRunner(enginePipes[1], currentPackage, - runnerLatch); + transport, runnerLatch); // The runner dup'd the pipe half, so we close it here enginePipes[1].close(); enginePipes[1] = null; @@ -3972,6 +4000,9 @@ public class BackupManagerService { break; } nRead = in.read(buffer); + if (MORE_DEBUG) { + Slog.v(TAG, "in.read(buffer) from app: " + nRead); + } if (nRead > 0) { out.write(buffer, 0, nRead); result = transport.sendBackupData(nRead); @@ -4003,6 +4034,14 @@ public class BackupManagerService { Slog.e(TAG, "Error " + result + " backing up " + currentPackage.packageName); } + + // Also ask the transport how long it wants us to wait before + // moving on to the next package, if any. + backoff = transport.requestFullBackupTime(); + if (DEBUG_SCHEDULING) { + Slog.i(TAG, "Transport suggested backoff=" + backoff); + } + } // Roll this package to the end of the backup queue if we're @@ -4055,15 +4094,12 @@ public class BackupManagerService { mRunningFullBackupTask = null; } - synchronized (mLatch) { - mLatch.set(true); - mLatch.notifyAll(); - } + mLatch.countDown(); // Now that we're actually done with schedule-driven work, reschedule // the next pass based on the new queue state. if (mUpdateSchedule) { - scheduleNextFullBackupJob(); + scheduleNextFullBackupJob(backoff); } } } @@ -4094,15 +4130,79 @@ public class BackupManagerService { // Run the backup and pipe it back to the given socket -- expects to run on // a standalone thread. The runner owns this half of the pipe, and closes // it to indicate EOD to the other end. + class SinglePackageBackupPreflight implements BackupRestoreTask, FullBackupPreflight { + final AtomicInteger mResult = new AtomicInteger(); + final CountDownLatch mLatch = new CountDownLatch(1); + final IBackupTransport mTransport; + + public SinglePackageBackupPreflight(IBackupTransport transport) { + mTransport = transport; + } + + @Override + public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { + int result; + try { + final int token = generateToken(); + prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, this); + addBackupTrace("preflighting"); + if (MORE_DEBUG) { + Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); + } + agent.doMeasureFullBackup(token, mBackupManagerBinder); + + // now wait to get our result back + mLatch.await(); + int totalSize = mResult.get(); + if (MORE_DEBUG) { + Slog.v(TAG, "Got preflight response; size=" + totalSize); + } + + result = mTransport.checkFullBackupSize(totalSize); + } catch (Exception e) { + Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage()); + result = BackupTransport.AGENT_ERROR; + } + return result; + } + + @Override + public void execute() { + // Unused in this case + } + + @Override + public void operationComplete(int result) { + // got the callback, and our preflightFullBackup() method is waiting for the result + if (MORE_DEBUG) { + Slog.i(TAG, "Preflight op complete, result=" + result); + } + mResult.set(result); + mLatch.countDown(); + } + + @Override + public void handleTimeout() { + if (MORE_DEBUG) { + Slog.i(TAG, "Preflight timeout; failing"); + } + mResult.set(BackupTransport.AGENT_ERROR); + mLatch.countDown(); + } + + } + class SinglePackageBackupRunner implements Runnable { final ParcelFileDescriptor mOutput; final PackageInfo mTarget; - final AtomicBoolean mLatch; + final FullBackupPreflight mPreflight; + final CountDownLatch mLatch; SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target, - AtomicBoolean latch) throws IOException { + IBackupTransport transport, CountDownLatch latch) throws IOException { mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor()); mTarget = target; + mPreflight = new SinglePackageBackupPreflight(transport); mLatch = latch; } @@ -4110,15 +4210,13 @@ public class BackupManagerService { public void run() { try { FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor()); - FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, false); + FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, + mPreflight, false); engine.backupOnePackage(mTarget); } catch (Exception e) { Slog.e(TAG, "Exception during full package backup of " + mTarget); } finally { - synchronized (mLatch) { - mLatch.set(true); - mLatch.notifyAll(); - } + mLatch.countDown(); try { mOutput.close(); } catch (IOException e) { @@ -4126,7 +4224,6 @@ public class BackupManagerService { } } } - } } @@ -4135,16 +4232,17 @@ public class BackupManagerService { /** * Schedule a job to tell us when it's a good time to run a full backup */ - void scheduleNextFullBackupJob() { + void scheduleNextFullBackupJob(long transportMinLatency) { synchronized (mQueueLock) { if (mFullBackupQueue.size() > 0) { // schedule the next job at the point in the future when the least-recently // backed up app comes due for backup again; or immediately if it's already // due. - long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; - long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; - final long latency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) + final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; + final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; + final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; + final long latency = Math.min(transportMinLatency, appLatency); Runnable r = new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, latency); @@ -4258,7 +4356,7 @@ public class BackupManagerService { // Okay, the top thing is runnable now. Pop it off and get going. mFullBackupQueue.remove(0); - AtomicBoolean latch = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); String[] pkg = new String[] {entry.packageName}; mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true, scheduledJob, latch); @@ -7895,7 +7993,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } @Override - public void operationComplete() { + public void operationComplete(int unusedResult) { if (MORE_DEBUG) { Slog.i(TAG, "operationComplete() during restore: target=" + mCurrentPackage.packageName @@ -8395,17 +8493,25 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF Slog.d(TAG, "fullTransportBackup()"); } - AtomicBoolean latch = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames, false, null, latch); (new Thread(task, "full-transport-master")).start(); - synchronized (latch) { + do { try { - while (latch.get() == false) { - latch.wait(); - } - } catch (InterruptedException e) {} + latch.await(); + break; + } catch (InterruptedException e) { + // Just go back to waiting for the latch to indicate completion + } + } while (true); + + // We just ran a backup on these packages, so kick them to the end of the queue + final long now = System.currentTimeMillis(); + for (String pkg : pkgNames) { + enqueueFullBackup(pkg, now); } + if (DEBUG) { Slog.d(TAG, "Done with full transport backup."); } @@ -8575,7 +8681,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext); - scheduleNextFullBackupJob(); + scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups if (DEBUG) Slog.i(TAG, "Opting out of backup"); @@ -8948,8 +9054,10 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Note that a currently-active backup agent has notified us that it has // completed the given outstanding asynchronous backup/restore operation. - public void opComplete(int token) { - if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token)); + public void opComplete(int token, long result) { + if (MORE_DEBUG) { + Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result); + } Operation op = null; synchronized (mCurrentOpLock) { op = mCurrentOperations.get(token); @@ -8962,6 +9070,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // The completion callback, if any, is invoked on the handler if (op != null && op.callback != null) { Message msg = mBackupHandler.obtainMessage(MSG_OP_COMPLETE, op.callback); + // NB: this cannot distinguish between results > 2 gig + msg.arg1 = (result > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) result; mBackupHandler.sendMessage(msg); } } diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 2e84fbe..99bbdae 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -309,10 +309,10 @@ public class Trampoline extends IBackupManager.Stub { } @Override - public void opComplete(int token) throws RemoteException { + public void opComplete(int token, long result) throws RemoteException { BackupManagerService svc = mService; if (svc != null) { - svc.opComplete(token); + svc.opComplete(token, result); } } diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 983d83a..694e851 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -221,3 +221,4 @@ option java_package com.android.server # AudioService.java # --------------------------- 40000 volume_changed (stream|1), (prev_level|1), (level|1), (max_level|1), (caller|3) +40001 stream_devices_changed (stream|1), (prev_devices|1), (devices|1) diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 97d16c0..b36f515 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -70,6 +70,7 @@ public class PersistentDataBlockService extends SystemService { // Limit to 100k as blocks larger than this might cause strain on Binder. private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100; public static final int DIGEST_SIZE_BYTES = 32; + private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed"; private final Context mContext; private final String mDataBlockFile; @@ -108,11 +109,14 @@ public class PersistentDataBlockService extends SystemService { } private void formatIfOemUnlockEnabled() { - if (doGetOemUnlockEnabled()) { + boolean enabled = doGetOemUnlockEnabled(); + if (enabled) { synchronized (mLock) { formatPartitionLocked(true); } } + + SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0"); } private void enforceOemUnlockPermission() { @@ -132,7 +136,6 @@ public class PersistentDataBlockService extends SystemService { throw new SecurityException("Only the Owner is allowed to change OEM unlock state"); } } - private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException { // skip over checksum inputStream.skipBytes(DIGEST_SIZE_BYTES); @@ -290,6 +293,7 @@ public class PersistentDataBlockService extends SystemService { Slog.e(TAG, "unable to access persistent partition", e); return; } finally { + SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0"); IoUtils.closeQuietly(outputStream); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 626b442..b5e1de9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2188,7 +2188,7 @@ public final class ActivityManagerService extends ActivityManagerNative systemDir.mkdirs(); mBatteryStatsService = new BatteryStatsService(systemDir, mHandler); mBatteryStatsService.getActiveStatistics().readLocked(); - mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); + mBatteryStatsService.scheduleWriteToDisk(); mOnBattery = DEBUG_POWER ? true : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); @@ -2432,7 +2432,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mLastWriteTime < (now-BATTERY_STATS_TIME)) { mLastWriteTime = now; - mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); + mBatteryStatsService.scheduleWriteToDisk(); } } } @@ -3046,12 +3046,12 @@ public final class ActivityManagerService extends ActivityManagerNative int[] permGids = null; try { checkTime(startTime, "startProcess: getting gids from package manager"); - final PackageManager pm = mContext.getPackageManager(); - permGids = pm.getPackageGids(app.info.packageName); + permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName, + app.userId); if (Environment.isExternalStorageEmulated()) { checkTime(startTime, "startProcess: checking external storage perm"); - if (pm.checkPermission( + if (mContext.getPackageManager().checkPermission( android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, app.info.packageName) == PERMISSION_GRANTED) { mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL; @@ -3059,7 +3059,7 @@ public final class ActivityManagerService extends ActivityManagerNative mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER; } } - } catch (PackageManager.NameNotFoundException e) { + } catch (RemoteException e) { Slog.w(TAG, "Unable to retrieve gids", e); } @@ -6326,31 +6326,38 @@ public final class ActivityManagerService extends ActivityManagerNative } try { PendingIntentRecord res = (PendingIntentRecord)pendingResult; - Intent intent = res.key.requestIntent; - if (intent != null) { - if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null - || res.lastTagPrefix.equals(prefix))) { - return res.lastTag; - } - res.lastTagPrefix = prefix; - StringBuilder sb = new StringBuilder(128); - if (prefix != null) { - sb.append(prefix); - } - if (intent.getAction() != null) { - sb.append(intent.getAction()); - } else if (intent.getComponent() != null) { - intent.getComponent().appendShortString(sb); - } else { - sb.append("?"); - } - return res.lastTag = sb.toString(); + synchronized (this) { + return getTagForIntentSenderLocked(res, prefix); } } catch (ClassCastException e) { } return null; } + String getTagForIntentSenderLocked(PendingIntentRecord res, String prefix) { + final Intent intent = res.key.requestIntent; + if (intent != null) { + if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null + || res.lastTagPrefix.equals(prefix))) { + return res.lastTag; + } + res.lastTagPrefix = prefix; + final StringBuilder sb = new StringBuilder(128); + if (prefix != null) { + sb.append(prefix); + } + if (intent.getAction() != null) { + sb.append(intent.getAction()); + } else if (intent.getComponent() != null) { + intent.getComponent().appendShortString(sb); + } else { + sb.append("?"); + } + return res.lastTag = sb.toString(); + } + return null; + } + @Override public void setProcessLimit(int max) { enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT, @@ -10479,17 +10486,21 @@ public final class ActivityManagerService extends ActivityManagerNative if (!(sender instanceof PendingIntentRecord)) { return; } - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + final PendingIntentRecord rec = (PendingIntentRecord)sender; + final String tag; + synchronized (this) { + tag = getTagForIntentSenderLocked(rec, "*walarm*:"); + } + final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { if (mBatteryStatsService.isOnBattery()) { mBatteryStatsService.enforceCallingPermission(); - PendingIntentRecord rec = (PendingIntentRecord)sender; int MY_UID = Binder.getCallingUid(); int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid; BatteryStatsImpl.Uid.Pkg pkg = stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid, sourcePkg != null ? sourcePkg : rec.key.packageName); - pkg.incWakeupsLocked(); + pkg.noteWakeupAlarmLocked(tag); } } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index b102a07..0eb914b 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1018,6 +1018,10 @@ final class ActivityStack { if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev); prev = null; } + // It is possible the activity was freezing the screen before it was paused. + // In that case go ahead and remove the freeze this activity has on the screen + // since it is no longer visible. + prev.stopFreezingScreenLocked(true /*force*/); mPausingActivity = null; } @@ -1112,7 +1116,7 @@ final class ActivityStack { } } - private void setVisibile(ActivityRecord r, boolean visible) { + private void setVisible(ActivityRecord r, boolean visible) { r.visible = visible; mWindowManager.setAppVisibility(r.appToken, visible); final ArrayList<ActivityContainer> containers = r.mChildContainers; @@ -1297,7 +1301,7 @@ final class ActivityStack { if (!r.visible || r.mLaunchTaskBehind) { if (DEBUG_VISBILITY) Slog.v( TAG, "Starting and making visible: " + r); - setVisibile(r, true); + setVisible(r, true); } if (r != starting) { mStackSupervisor.startSpecificActivityLocked(r, false, false); @@ -1329,7 +1333,7 @@ final class ActivityStack { r.updateOptionsLocked(r.returningOptions); mUndrawnActivitiesBelowTopTranslucent.add(r); } - setVisibile(r, true); + setVisible(r, true); r.sleeping = false; r.app.pendingUiClean = true; r.app.thread.scheduleWindowVisibility(r.appToken, true); @@ -1364,7 +1368,7 @@ final class ActivityStack { if (r.visible) { if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r); try { - setVisibile(r, false); + setVisible(r, false); switch (r.state) { case STOPPING: case STOPPED: @@ -3896,8 +3900,7 @@ final class ActivityStack { return true; } - private boolean relaunchActivityLocked(ActivityRecord r, - int changes, boolean andResume) { + private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) { List<ResultInfo> results = null; List<ReferrerIntent> newIntents = null; if (andResume) { @@ -3916,9 +3919,8 @@ final class ActivityStack { mStackSupervisor.removeChildActivityContainers(r); try { - if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, - (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ") - + r); + if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Moving to " + + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r); r.forceNewConfig = false; r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes, !andResume, new Configuration(mService.mConfiguration), diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index e9e6496..f874244 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -129,7 +129,7 @@ public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG_RELEASE = DEBUG || false; static final boolean DEBUG_SAVED_STATE = DEBUG || false; static final boolean DEBUG_SCREENSHOTS = DEBUG || false; - static final boolean DEBUG_STATES = DEBUG || false; + static final boolean DEBUG_STATES = DEBUG || true; static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false; public static final int HOME_STACK_ID = 0; @@ -273,8 +273,8 @@ public final class ActivityStackSupervisor implements DisplayListener { * until the task exits or #stopLockTaskMode() is called. */ TaskRecord mLockTaskModeTask; /** Store the current lock task mode. Possible values: - * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED}, - * {@link ActicityManager#LOCK_TASK_MODE_PINNED} + * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, + * {@link ActivityManager#LOCK_TASK_MODE_PINNED} */ private int mLockTaskModeState; /** @@ -1132,12 +1132,13 @@ public final class ActivityStackSupervisor implements DisplayListener { ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { - r.startFreezingScreenLocked(app, 0); - if (false) Slog.d(TAG, "realStartActivity: setting app visibility true"); - mWindowManager.setAppVisibility(r.appToken, true); + if (andResume) { + r.startFreezingScreenLocked(app, 0); + mWindowManager.setAppVisibility(r.appToken, true); - // schedule launch ticks to collect information about slow apps. - r.startLaunchTickingLocked(); + // schedule launch ticks to collect information about slow apps. + r.startLaunchTickingLocked(); + } // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. Note that @@ -1195,34 +1196,37 @@ public final class ActivityStackSupervisor implements DisplayListener { r.forceNewConfig = false; mService.showAskCompatModeDialogLocked(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); - String profileFile = null; - ParcelFileDescriptor profileFd = null; + ProfilerInfo profilerInfo = null; if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) { if (mService.mProfileProc == null || mService.mProfileProc == app) { mService.mProfileProc = app; - profileFile = mService.mProfileFile; - profileFd = mService.mProfileFd; - } - } - app.hasShownUi = true; - app.pendingUiClean = true; - if (profileFd != null) { - try { - profileFd = profileFd.dup(); - } catch (IOException e) { - if (profileFd != null) { - try { - profileFd.close(); - } catch (IOException o) { + final String profileFile = mService.mProfileFile; + if (profileFile != null) { + ParcelFileDescriptor profileFd = mService.mProfileFd; + if (profileFd != null) { + try { + profileFd = profileFd.dup(); + } catch (IOException e) { + if (profileFd != null) { + try { + profileFd.close(); + } catch (IOException o) { + } + profileFd = null; + } + } } - profileFd = null; + + profilerInfo = new ProfilerInfo(profileFile, profileFd, + mService.mSamplingInterval, mService.mAutoStopProfiler); } } } - ProfilerInfo profilerInfo = profileFile != null - ? new ProfilerInfo(profileFile, profileFd, mService.mSamplingInterval, - mService.mAutoStopProfiler) : null; + if (andResume) { + app.hasShownUi = true; + app.pendingUiClean = true; + } app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP); app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 197b51d..c8db3be 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -16,20 +16,26 @@ package com.android.server.am; +import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.net.wifi.IWifiManager; +import android.net.wifi.WifiActivityEnergyInfo; import android.os.BatteryStats; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManagerInternal; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; @@ -38,10 +44,12 @@ import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.PowerProfile; +import com.android.server.FgThread; import com.android.server.LocalServices; import java.io.File; @@ -59,15 +67,52 @@ public final class BatteryStatsService extends IBatteryStats.Stub static final String TAG = "BatteryStatsService"; static IBatteryStats sService; - final BatteryStatsImpl mStats; + final BatteryStatsHandler mHandler; Context mContext; private boolean mBluetoothPendingStats; private BluetoothHeadset mBluetoothHeadset; PowerManagerInternal mPowerManagerInternal; + class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync { + public static final int MSG_SYNC_EXTERNAL_STATS = 1; + public static final int MSG_WRITE_TO_DISK = 2; + + public BatteryStatsHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SYNC_EXTERNAL_STATS: + updateExternalStats(); + break; + + case MSG_WRITE_TO_DISK: + updateExternalStats(); + synchronized (mStats) { + mStats.writeAsyncLocked(); + } + break; + } + } + + @Override + public void scheduleSync() { + if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) { + sendEmptyMessage(MSG_SYNC_EXTERNAL_STATS); + } + } + } + BatteryStatsService(File systemDir, Handler handler) { - mStats = new BatteryStatsImpl(systemDir, handler); + // Our handler here will be accessing the disk, use a different thread than + // what the ActivityManagerService gave us (no I/O on that one!). + mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper()); + + // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. + mStats = new BatteryStatsImpl(systemDir, handler, mHandler); } public void publish(Context context) { @@ -92,6 +137,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub public void shutdown() { Slog.w("BatteryStats", "Writing battery stats before shutdown..."); + + updateExternalStats(); synchronized (mStats) { mStats.shutdownLocked(); } @@ -122,6 +169,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub return mStats; } + /** + * Schedules a write to disk to occur. This will cause the BatteryStatsImpl + * object to update with the latest info, then write to disk. + */ + public void scheduleWriteToDisk() { + mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK); + } + // These are for direct use by the activity manager... void addIsolatedUid(int isolatedUid, int appUid) { @@ -174,7 +229,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub //Slog.i("foo", "SENDING BATTERY INFO:"); //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); Parcel out = Parcel.obtain(); - mStats.writeToParcel(out, 0); + updateExternalStats(); + synchronized (mStats) { + mStats.writeToParcel(out, 0); + } byte[] data = out.marshall(); out.recycle(); return data; @@ -186,7 +244,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub //Slog.i("foo", "SENDING BATTERY INFO:"); //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); Parcel out = Parcel.obtain(); - mStats.writeToParcel(out, 0); + updateExternalStats(); + synchronized (mStats) { + mStats.writeToParcel(out, 0); + } byte[] data = out.marshall(); out.recycle(); try { @@ -663,6 +724,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + @Override public void noteWifiMulticastDisabledFromSource(WorkSource ws) { enforceCallingPermission(); synchronized (mStats) { @@ -671,10 +733,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub } @Override - public void noteNetworkInterfaceType(String iface, int type) { + public void noteNetworkInterfaceType(String iface, int networkType) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteNetworkInterfaceTypeLocked(iface, type); + mStats.noteNetworkInterfaceTypeLocked(iface, networkType); } } @@ -715,7 +777,22 @@ public final class BatteryStatsService extends IBatteryStats.Stub public void setBatteryState(int status, int health, int plugType, int level, int temp, int volt) { enforceCallingPermission(); - mStats.setBatteryState(status, health, plugType, level, temp, volt); + synchronized (mStats) { + final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE; + if (mStats.isOnBattery() == onBattery) { + // The battery state has not changed, so we don't need to sync external + // stats immediately. + mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); + return; + } + } + + // Sync external stats first as the battery has changed states. If we don't sync + // immediately here, we may not collect the relevant data later. + updateExternalStats(); + synchronized (mStats) { + mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); + } } public long getAwakeTimeBattery() { @@ -772,12 +849,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub private void dumpHelp(PrintWriter pw) { pw.println("Battery stats (batterystats) dump options:"); - pw.println(" [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]"); + pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]"); pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]"); pw.println(" --checkin: format output for a checkin report."); pw.println(" --history: show only history data."); pw.println(" --history-start <num>: show only history data starting at given time offset."); - pw.println(" --unplugged: only output data since last unplugged."); pw.println(" --charged: only output data since last charged."); pw.println(" --daily: only output full daily data."); pw.println(" --reset: reset the stats, clearing all current data."); @@ -818,6 +894,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub return i; } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -856,8 +933,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else if ("-c".equals(arg)) { useCheckinFormat = true; flags |= BatteryStats.DUMP_INCLUDE_HISTORY; - } else if ("--unplugged".equals(arg)) { - flags |= BatteryStats.DUMP_UNPLUGGED_ONLY; } else if ("--charged".equals(arg)) { flags |= BatteryStats.DUMP_CHARGED_ONLY; } else if ("--daily".equals(arg)) { @@ -868,7 +943,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub pw.println("Battery stats reset."); noOutput = true; } + updateExternalStats(); } else if ("--write".equals(arg)) { + updateExternalStats(); synchronized (mStats) { mStats.writeSyncLocked(); pw.println("Battery stats written."); @@ -931,13 +1008,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub if (reqUid >= 0) { // By default, if the caller is only interested in a specific package, then // we only dump the aggregated data since charged. - if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_UNPLUGGED_ONLY - |BatteryStats.DUMP_CHARGED_ONLY)) == 0) { + if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) { flags |= BatteryStats.DUMP_CHARGED_ONLY; // Also if they are doing -c, we don't want history. flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY; } } + + // Fetch data from external sources and update the BatteryStatsImpl object with them. + updateExternalStats(); + if (useCheckinFormat) { List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0); if (isRealCheckin) { @@ -952,7 +1032,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub in.unmarshall(raw, 0, raw.length); in.setDataPosition(0); BatteryStatsImpl checkinStats = new BatteryStatsImpl( - null, mStats.mHandler); + null, mStats.mHandler, null); checkinStats.readSummaryFromParcel(in); in.recycle(); checkinStats.dumpCheckinLocked(mContext, pw, apps, flags, @@ -982,4 +1062,85 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } } + + // Objects for extracting data from external sources. + private final Object mExternalStatsLock = new Object(); + + @GuardedBy("mExternalStatsLock") + private IWifiManager mWifiManager; + + // WiFi keeps an accumulated total of stats, unlike Bluetooth. + // Keep the last WiFi stats so we can compute a delta. + @GuardedBy("mExternalStatsLock") + private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); + + @GuardedBy("mExternalStatsLock") + private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() { + if (mWifiManager == null) { + mWifiManager = IWifiManager.Stub.asInterface( + ServiceManager.getService(Context.WIFI_SERVICE)); + if (mWifiManager == null) { + return null; + } + } + + try { + // We read the data even if we are not on battery. This is so that we keep the + // correct delta from when we should start reading (aka when we are on battery). + WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo(); + if (info != null && info.isValid()) { + // We will modify the last info object to be the delta, and store the new + // WifiActivityEnergyInfo object as our last one. + final WifiActivityEnergyInfo result = mLastInfo; + result.mTimestamp = info.getTimeStamp(); + result.mStackState = info.getStackState(); + result.mControllerTxTimeMs = + info.getControllerTxTimeMillis()- mLastInfo.mControllerTxTimeMs; + result.mControllerRxTimeMs = + info.getControllerRxTimeMillis() - mLastInfo.mControllerRxTimeMs; + result.mControllerIdleTimeMs = + info.getControllerIdleTimeMillis() - mLastInfo.mControllerIdleTimeMs; + result.mControllerEnergyUsed = + info.getControllerEnergyUsed() - mLastInfo.mControllerEnergyUsed; + mLastInfo = info; + return result; + } + } catch (RemoteException e) { + // Nothing to report, WiFi is dead. + } + return null; + } + + @GuardedBy("mExternalStatsLock") + private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo( + BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED); + if (info != null && info.isValid()) { + return info; + } + } + return null; + } + + /** + * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates + * batterystats with that information. + * + * We first grab a lock specific to this method, then once all the data has been collected, + * we grab the mStats lock and update the data. + */ + void updateExternalStats() { + synchronized (mExternalStatsLock) { + final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked(); + final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked(); + synchronized (mStats) { + mStats.updateKernelWakelocksLocked(); + mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime()); + mStats.updateWifiStateLocked(wifiEnergyInfo); + mStats.updateBluetoothStateLocked(bluetoothEnergyInfo); + } + } + } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 65b2ae2..1eddc8e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -234,9 +234,6 @@ public class AudioService extends IAudioService.Stub { private final Object mSoundEffectsLock = new Object(); private static final int NUM_SOUNDPOOL_CHANNELS = 4; - // Maximum volume adjust steps allowed in a single batch call. - private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; - /* Sound effect file names */ private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>(); @@ -988,6 +985,7 @@ public class AudioService extends IAudioService.Stub { } else { streamType = getActiveStreamType(suggestedStreamType); } + ensureValidStreamType(streamType); final int resolvedStream = mStreamVolumeAlias[streamType]; // Play sounds on STREAM_RING only. @@ -1421,6 +1419,8 @@ public class AudioService extends IAudioService.Stub { private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) { streamType = AudioSystem.STREAM_NOTIFICATION; + } else { + streamType = mStreamVolumeAlias[streamType]; } if (streamType == AudioSystem.STREAM_MUSIC) { @@ -3131,12 +3131,6 @@ public class AudioService extends IAudioService.Stub { } } - private void ensureValidSteps(int steps) { - if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { - throw new IllegalArgumentException("Bad volume adjust steps " + steps); - } - } - private void ensureValidStreamType(int streamType) { if (streamType < 0 || streamType >= mStreamStates.length) { throw new IllegalArgumentException("Bad stream type " + streamType); @@ -3305,7 +3299,7 @@ public class AudioService extends IAudioService.Stub { } private int getDeviceForStream(int stream) { - int device = AudioSystem.getDevicesForStream(stream); + int device = getDevicesForStream(stream); if ((device & (device - 1)) != 0) { // Multiple device selection is either: // - speaker + one other device: give priority to speaker in this case. @@ -3328,6 +3322,27 @@ public class AudioService extends IAudioService.Stub { return device; } + private int getDevicesForStream(int stream) { + return getDevicesForStream(stream, true /*checkOthers*/); + } + + private int getDevicesForStream(int stream, boolean checkOthers) { + ensureValidStreamType(stream); + synchronized (VolumeStreamState.class) { + return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers); + } + } + + private void observeDevicesForStreams(int skipStream) { + synchronized (VolumeStreamState.class) { + for (int stream = 0; stream < mStreamStates.length; stream++) { + if (stream != skipStream) { + mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/); + } + } + } + } + /* * A class just for packaging up a set of connection parameters. */ @@ -3406,9 +3421,11 @@ public class AudioService extends IAudioService.Stub { private boolean mIsMuted; private String mVolumeIndexSettingName; + private int mObservedDevices; private final SparseIntArray mIndexMap = new SparseIntArray(8); private final Intent mVolumeChanged; + private final Intent mStreamDevicesChanged; private VolumeStreamState(String settingName, int streamType) { @@ -3422,6 +3439,29 @@ public class AudioService extends IAudioService.Stub { readSettings(); mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION); mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); + mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION); + mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); + } + + public int observeDevicesForStream_syncVSS(boolean checkOthers) { + final int devices = AudioSystem.getDevicesForStream(mStreamType); + if (devices == mObservedDevices) { + return devices; + } + final int prevDevices = mObservedDevices; + mObservedDevices = devices; + if (checkOthers) { + // one stream's devices have changed, check the others + observeDevicesForStreams(mStreamType); + } + // log base stream changes to the event log + if (mStreamVolumeAlias[mStreamType] == mStreamType) { + EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices); + } + sendBroadcastToAll(mStreamDevicesChanged + .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices) + .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices)); + return devices; } public String getSettingNameForDevice(int device) { @@ -3716,7 +3756,7 @@ public class AudioService extends IAudioService.Stub { } pw.println(); pw.print(" Devices: "); - final int devices = AudioSystem.getDevicesForStream(mStreamType); + final int devices = getDevicesForStream(mStreamType); int device, i = 0, n = 0; // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive // (the default device is not returned by getDevicesForStream) @@ -4250,6 +4290,7 @@ public class AudioService extends IAudioService.Stub { } } mRoutesObservers.finishBroadcast(); + observeDevicesForStreams(-1); break; } @@ -5348,7 +5389,7 @@ public class AudioService extends IAudioService.Stub { on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE); } - device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC); + device = getDevicesForStream(AudioSystem.STREAM_MUSIC); } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 7f47678..0b430ea 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1021,6 +1021,14 @@ public class Vpn { public synchronized LegacyVpnInfo getLegacyVpnInfo() { // Check if the caller is authorized. enforceControlPermission(); + return getLegacyVpnInfoPrivileged(); + } + + /** + * Return the information of the current ongoing legacy VPN. + * Callers are responsible for checking permissions if needed. + */ + public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() { if (mLegacyVpnRunner == null) return null; final LegacyVpnInfo info = new LegacyVpnInfo(); diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index b398f41..ab56b34 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -16,6 +16,7 @@ package com.android.server.fingerprint; +import android.content.ContentResolver; import android.content.Context; import android.os.Handler; import android.os.IBinder; @@ -29,12 +30,16 @@ import android.util.Slog; import com.android.server.SystemService; import android.service.fingerprint.FingerprintUtils; +import android.service.fingerprint.Fingerprint; import android.service.fingerprint.IFingerprintService; import android.service.fingerprint.IFingerprintServiceReceiver; + import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.USE_FINGERPRINT; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; /** * A service to manage multiple clients that want to access the fingerprint HAL API. @@ -50,11 +55,14 @@ public class FingerprintService extends SystemService { private static final int MSG_NOTIFY = 10; + private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute + Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_NOTIFY: - handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj); + FpHalMsg m = (FpHalMsg) msg.obj; + handleNotify(m.type, m.arg1, m.arg2, m.arg3); break; default: @@ -66,7 +74,7 @@ public class FingerprintService extends SystemService { private int mHalDeviceId; private static final int STATE_IDLE = 0; - private static final int STATE_LISTENING = 1; + private static final int STATE_AUTHENTICATING = 1; private static final int STATE_ENROLLING = 2; private static final int STATE_REMOVING = 3; private static final long MS_PER_SEC = 1000; @@ -76,7 +84,10 @@ public class FingerprintService extends SystemService { int state; int userId; public TokenWatcher tokenWatcher; - IBinder getToken() { return tokenWatcher.getToken(); } + + IBinder getToken() { + return tokenWatcher.getToken(); + } } private class TokenWatcher implements IBinder.DeathRecipient { @@ -86,7 +97,10 @@ public class FingerprintService extends SystemService { this.token = new WeakReference<IBinder>(token); } - IBinder getToken() { return token.get(); } + IBinder getToken() { + return token.get(); + } + public void binderDied() { mClients.remove(token); this.token = null; @@ -112,21 +126,42 @@ public class FingerprintService extends SystemService { // TODO: Move these into separate process // JNI methods to communicate from FingerprintManagerService to HAL - static native int nativeEnroll(int timeout); + static native int nativeEnroll(int timeout, int groupId); + + static native int nativeAuthenticate(long sessionId, int groupId); + static native int nativeEnrollCancel(); - static native int nativeRemove(int fingerprintId); + + static native int nativeRemove(int fingerId, int groupId); + static native int nativeOpenHal(); + static native int nativeCloseHal(); + static native void nativeInit(MessageQueue queue, FingerprintService service); + static final class FpHalMsg { + int type; // Type of the message. One of the constants in fingerprint.h + int arg1; // optional arguments + int arg2; + int arg3; + + FpHalMsg(int type, int arg1, int arg2, int arg3) { + this.type = type; + this.arg1 = arg1; + this.arg2 = arg2; + this.arg3 = arg3; + } + } + // JNI methods for communicating from HAL to clients - void notify(int msg, int arg1, int arg2) { - mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget(); + void notify(int type, int arg1, int arg2, int arg3) { + mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget(); } - void handleNotify(int msg, int arg1, int arg2) { - Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" - + ", " + mClients.size() + " clients"); + void handleNotify(int type, int arg1, int arg2, int arg3) { + Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", " + + mClients.size() + " clients"); for (int i = 0; i < mClients.size(); i++) { if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i)); ClientData clientData = mClients.valueAt(i); @@ -134,21 +169,20 @@ public class FingerprintService extends SystemService { if (DEBUG) Slog.v(TAG, "clientData is invalid!!"); continue; } - switch (msg) { + ContentResolver contentResolver = mContext.getContentResolver(); + switch (type) { case FingerprintManager.FINGERPRINT_ERROR: { - final int error = arg1; try { - clientData.receiver.onError(error); + clientData.receiver.onError(mHalDeviceId, arg1 /* error */); } catch (RemoteException e) { Slog.e(TAG, "can't send message to client. Did it die?", e); mClients.remove(mClients.keyAt(i)); } } - break; + break; case FingerprintManager.FINGERPRINT_ACQUIRED: { - final int acquireInfo = arg1; try { - clientData.receiver.onAcquired(acquireInfo); + clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */); } catch (RemoteException e) { Slog.e(TAG, "can't send message to client. Did it die?", e); mClients.remove(mClients.keyAt(i)); @@ -156,9 +190,9 @@ public class FingerprintService extends SystemService { break; } case FingerprintManager.FINGERPRINT_PROCESSED: { - final int fingerId = arg1; try { - clientData.receiver.onProcessed(fingerId); + clientData.receiver + .onProcessed(mHalDeviceId, arg1 /* fingerId */, arg2 /* groupId */); } catch (RemoteException e) { Slog.e(TAG, "can't send message to client. Did it die?", e); mClients.remove(mClients.keyAt(i)); @@ -167,11 +201,13 @@ public class FingerprintService extends SystemService { } case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: { final int fingerId = arg1; - final int remaining = arg2; + final int groupId = arg2; + final int remaining = arg3; if (clientData.state == STATE_ENROLLING) { // Only send enroll updates to clients that are actually enrolling try { - clientData.receiver.onEnrollResult(fingerId, remaining); + clientData.receiver.onEnrollResult(mHalDeviceId, fingerId, groupId, + remaining); } catch (RemoteException e) { Slog.e(TAG, "can't send message to client. Did it die?", e); mClients.remove(mClients.keyAt(i)); @@ -179,8 +215,8 @@ public class FingerprintService extends SystemService { // Update the database with new finger id. // TODO: move to client code (Settings) if (remaining == 0) { - FingerprintUtils.addFingerprintIdForUser(fingerId, - mContext.getContentResolver(), clientData.userId); + FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId, + clientData.userId); clientData.state = STATE_IDLE; // Nothing left to do } } else { @@ -191,30 +227,50 @@ public class FingerprintService extends SystemService { } case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: { int fingerId = arg1; - if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL"); - FingerprintUtils.removeFingerprintIdForUser(fingerId, - mContext.getContentResolver(), clientData.userId); + int groupId = arg2; + if (fingerId == 0) { + throw new IllegalStateException("Got illegal id from HAL"); + } + FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver, + clientData.userId); if (clientData.receiver != null) { try { - clientData.receiver.onRemoved(fingerId); + clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId); } catch (RemoteException e) { Slog.e(TAG, "can't send message to client. Did it die?", e); mClients.remove(mClients.keyAt(i)); } } - clientData.state = STATE_LISTENING; + clientData.state = STATE_IDLE; } - break; + break; } } } - void startEnroll(IBinder token, long timeout, int userId) { + void startEnroll(IBinder token, int groupId, int flags) { ClientData clientData = mClients.get(token); if (clientData != null) { - if (clientData.userId != userId) throw new IllegalStateException("Bad user"); + if (clientData.userId != groupId) { + throw new IllegalStateException("Bad user"); + } clientData.state = STATE_ENROLLING; - nativeEnroll((int) (timeout / MS_PER_SEC)); + final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); + nativeEnroll(timeout, groupId); + } else { + Slog.w(TAG, "enroll(): No listener registered"); + } + } + + void startAuthenticate(IBinder token, long sessionId, int groupId, int flags) { + ClientData clientData = mClients.get(token); + if (clientData != null) { + if (clientData.userId != groupId) { + throw new IllegalStateException("Bad user"); + } + clientData.state = STATE_AUTHENTICATING; + final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); + nativeAuthenticate(sessionId, groupId); } else { Slog.w(TAG, "enroll(): No listener registered"); } @@ -224,7 +280,7 @@ public class FingerprintService extends SystemService { ClientData clientData = mClients.get(token); if (clientData != null) { if (clientData.userId != userId) throw new IllegalStateException("Bad user"); - clientData.state = STATE_LISTENING; + clientData.state = STATE_IDLE; nativeEnrollCancel(); } else { Slog.w(TAG, "enrollCancel(): No listener registered"); @@ -238,7 +294,7 @@ public class FingerprintService extends SystemService { if (clientData.userId != userId) throw new IllegalStateException("Bad user"); clientData.state = STATE_REMOVING; // The fingerprint id will be removed when we get confirmation from the HAL - int result = nativeRemove(fingerId); + int result = nativeRemove(fingerId, userId); if (result != 0) { Slog.w(TAG, "Error removing fingerprint with id = " + fingerId); } @@ -251,7 +307,7 @@ public class FingerprintService extends SystemService { if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")"); if (mClients.get(token) == null) { ClientData clientData = new ClientData(); - clientData.state = STATE_LISTENING; + clientData.state = STATE_IDLE; clientData.receiver = receiver; clientData.userId = userId; clientData.tokenWatcher = new TokenWatcher(token); @@ -266,7 +322,7 @@ public class FingerprintService extends SystemService { } } - void removeListener(IBinder token, int userId) { + void removeListener(IBinder token, IFingerprintServiceReceiver receiver) { if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")"); ClientData clientData = mClients.get(token); if (clientData != null) { @@ -278,61 +334,91 @@ public class FingerprintService extends SystemService { mClients.remove(token); } + public List<Fingerprint> getEnrolledFingerprints(int groupId) { + ContentResolver resolver = mContext.getContentResolver(); + int[] ids = FingerprintUtils.getFingerprintIdsForUser(resolver, groupId); + List<Fingerprint> result = new ArrayList<Fingerprint>(); + for (int i = 0; i < ids.length; i++) { + // TODO: persist names in Settings + CharSequence name = "Finger" + ids[i]; + final int group = 0; // TODO + final int fingerId = ids[i]; + final long deviceId = 0; // TODO + Fingerprint item = new Fingerprint(name, 0, ids[i], 0); + result.add(item); + } + return result; + } + void checkPermission(String permission) { - getContext().enforceCallingOrSelfPermission(permission, "Must have " - + permission + " permission."); + getContext().enforceCallingOrSelfPermission(permission, + "Must have " + permission + " permission."); } private final class FingerprintServiceWrapper extends IFingerprintService.Stub { - @Override // Binder call - public void enroll(IBinder token, long timeout, int userId) { + @Override + // Binder call + public void enroll(IBinder token, int groupId, int flags) { checkPermission(MANAGE_FINGERPRINT); - startEnroll(token, timeout, userId); + startEnroll(token, groupId, flags); } - @Override // Binder call - public void enrollCancel(IBinder token,int userId) { - checkPermission(MANAGE_FINGERPRINT); - startEnrollCancel(token, userId); + @Override + // Binder call + public void authenticate(IBinder token, long sessionId, int groupId, int flags) { + checkPermission(USE_FINGERPRINT); + startAuthenticate(token, sessionId, groupId, flags); } - @Override // Binder call - public void remove(IBinder token, int fingerprintId, int userId) { + @Override + // Binder call + public void remove(IBinder token, int fingerId, int groupId) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission - startRemove(token, fingerprintId, userId); + startRemove(token, fingerId, groupId); } - @Override // Binder call - public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId) - { + @Override + // Binder call + public void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) { checkPermission(USE_FINGERPRINT); - addListener(token, receiver, userId); + FingerprintService.this.addListener(token, receiver, userId); } - @Override // Binder call - public void stopListening(IBinder token, int userId) { + @Override + // Binder call + public void removeListener(IBinder token, IFingerprintServiceReceiver receiver) { checkPermission(USE_FINGERPRINT); - removeListener(token, userId); + FingerprintService.this.removeListener(token, receiver); } - @Override // Binder call - public boolean isHardwareDetected() { + @Override + // Binder call + public boolean isHardwareDetected(long deviceId) { checkPermission(USE_FINGERPRINT); - return mHalDeviceId != 0; + return mHalDeviceId != 0; // TODO } @Override - public void rename(int fpId, String name) { + // Binder call + public void rename(int fingerId, int groupId, String name) { checkPermission(MANAGE_FINGERPRINT); + Slog.w(TAG, "rename id=" + fingerId + ",gid=" + groupId + ",name=" + name); // TODO } + + @Override + // Binder call + public List<Fingerprint> getEnrolledFingerprints(int groupId) { + checkPermission(USE_FINGERPRINT); + return FingerprintService.this.getEnrolledFingerprints(groupId); + } } @Override public void onStart() { - publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); - mHalDeviceId = nativeOpenHal(); - if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); + publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); + mHalDeviceId = nativeOpenHal(); + if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 70fa441..89ffe45 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -192,6 +192,13 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { } } + @ServiceThreadOnly + protected boolean handleUserControlPressed(HdmiCecMessage message) { + assertRunOnServiceThread(); + wakeUpIfActiveSource(); + return super.handleUserControlPressed(message); + } + @Override @ServiceThreadOnly protected boolean handleSetStreamPath(HdmiCecMessage message) { @@ -229,7 +236,12 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { } private void wakeUpIfActiveSource() { - if (mIsActiveSource && mService.isPowerStandbyOrTransient()) { + if (!mIsActiveSource) { + return; + } + // Wake up the device if the power is in standby mode, or its screen is off - + // which can happen if the device is holding a partial lock. + if (mService.isPowerStandbyOrTransient() || !mService.getPowerManager().isScreenOn()) { mService.wakeUp(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7c93e56..d5cb5e3 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -251,7 +251,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } int targetAddress = targetDevice.getLogicalAddress(); ActiveSource active = getActiveSource(); - if (active.isValid() && targetAddress == active.logicalAddress) { + if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON + && active.isValid() + && targetAddress == active.logicalAddress) { invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); return; } diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java index cbbf91b..75a79cb 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java @@ -58,14 +58,16 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { // received without <Request ARC Initiation> or <Request ARC Termination>. case Constants.MESSAGE_FEATURE_ABORT: int originalOpcode = cmd.getParams()[0] & 0xFF; - if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION - || originalOpcode == Constants.MESSAGE_REQUEST_ARC_TERMINATION) { + if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_TERMINATION) { disableArcTransmission(); finish(); return true; - } else { - return false; + } else if (originalOpcode == Constants.MESSAGE_REQUEST_ARC_INITIATION) { + tv().setArcStatus(false); + finish(); + return true; } + return false; } return false; } @@ -82,7 +84,7 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { if (mState != state || state != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) { return; } - HdmiLogger.debug("[T]RequestArcAction."); + HdmiLogger.debug("[T] RequestArcAction."); disableArcTransmission(); finish(); } diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index d9e1f24..f69f975 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -35,6 +35,7 @@ final class RequestArcInitiationAction extends RequestArcAction { @Override boolean start() { + // Seq #38 mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; addTimer(mState, HdmiConfig.TIMEOUT_MS); @@ -44,9 +45,8 @@ final class RequestArcInitiationAction extends RequestArcAction { @Override public void onSendCompleted(int error) { if (error != Constants.SEND_RESULT_SUCCESS) { - // If failed to send <Request ARC Initiation>, start "Disabled" - // ARC transmission action. - disableArcTransmission(); + // Turn off ARC status if <Request ARC Initiation> fails. + tv().setArcStatus(false); finish(); } } diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index bffa854..d200d35 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -52,6 +52,7 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { @Override boolean start() { + // Seq #37. if (mEnabled) { // Enable ARC status immediately after sending <Report Arc Initiated>. // If AVR responds with <Feature Abort>, disable ARC status again. diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index fe1260d..d79b5fd 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -41,6 +41,7 @@ import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -109,21 +110,22 @@ public class JobSchedulerService extends com.android.server.SystemService * Track Services that have currently active or pending jobs. The index is provided by * {@link JobStatus#getServiceToken()} */ - final List<JobServiceContext> mActiveServices = new ArrayList<JobServiceContext>(); + final List<JobServiceContext> mActiveServices = new ArrayList<>(); /** List of controllers that will notify this service of updates to jobs. */ List<StateController> mControllers; /** * Queue of pending jobs. The JobServiceContext class will receive jobs from this list * when ready to execute them. */ - final ArrayList<JobStatus> mPendingJobs = new ArrayList<JobStatus>(); + final ArrayList<JobStatus> mPendingJobs = new ArrayList<>(); - final ArrayList<Integer> mStartedUsers = new ArrayList(); + final ArrayList<Integer> mStartedUsers = new ArrayList<>(); final JobHandler mHandler; final JobSchedulerStub mJobSchedulerStub; IBatteryStats mBatteryStats; + PowerManager mPowerManager; /** * Set to true once we are allowed to run third party apps. @@ -131,6 +133,11 @@ public class JobSchedulerService extends com.android.server.SystemService boolean mReadyToRock; /** + * True when in device idle mode, so we don't want to schedule any jobs. + */ + boolean mDeviceIdleMode; + + /** * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we * still clean up. On reinstall the package will have a new uid. */ @@ -154,6 +161,8 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for user: " + userId); } cancelJobsForUser(userId); + } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) { + updateIdleMode(mPowerManager != null ? mPowerManager.isDeviceIdleMode() : false); } } }; @@ -199,7 +208,7 @@ public class JobSchedulerService extends com.android.server.SystemService return outList; } - private void cancelJobsForUser(int userHandle) { + void cancelJobsForUser(int userHandle) { List<JobStatus> jobsForUser; synchronized (mJobs) { jobsForUser = mJobs.getJobsByUser(userHandle); @@ -257,6 +266,40 @@ public class JobSchedulerService extends com.android.server.SystemService } } + void updateIdleMode(boolean enabled) { + boolean changed = false; + boolean rocking; + synchronized (mJobs) { + if (mDeviceIdleMode != enabled) { + changed = true; + } + rocking = mReadyToRock; + } + if (changed) { + if (rocking) { + for (int i=0; i<mControllers.size(); i++) { + mControllers.get(i).deviceIdleModeChanged(enabled); + } + } + synchronized (mJobs) { + mDeviceIdleMode = enabled; + if (enabled) { + // When becoming idle, make sure no jobs are actively running. + for (int i=0; i<mActiveServices.size(); i++) { + JobServiceContext jsc = mActiveServices.get(i); + final JobStatus executing = jsc.getRunningJob(); + if (executing != null) { + jsc.cancelExecutingJob(); + } + } + } else { + // When coming out of idle, allow thing to start back up. + mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); + } + } + } + } + /** * Initializes the system service. * <p> @@ -294,8 +337,10 @@ public class JobSchedulerService extends com.android.server.SystemService getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, filter, null, null); final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); + userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); + mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE); } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mJobs) { // Let's go! @@ -313,6 +358,7 @@ public class JobSchedulerService extends com.android.server.SystemService for (int i=0; i<jobs.size(); i++) { JobStatus job = jobs.valueAt(i); for (int controller=0; controller<mControllers.size(); controller++) { + mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode); mControllers.get(controller).maybeStartTrackingJob(job); } } @@ -667,6 +713,10 @@ public class JobSchedulerService extends com.android.server.SystemService */ private void maybeRunPendingJobsH() { synchronized (mJobs) { + if (mDeviceIdleMode) { + // If device is idle, we will not schedule jobs to run. + return; + } Iterator<JobStatus> it = mPendingJobs.iterator(); if (DEBUG) { Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs."); @@ -878,6 +928,7 @@ public class JobSchedulerService extends com.android.server.SystemService } pw.println(); pw.print("mReadyToRock="); pw.println(mReadyToRock); + pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode); } pw.println(); } 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 7d76fc0..efd1928 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -31,12 +31,17 @@ public abstract class StateController { protected static final boolean DEBUG = false; protected Context mContext; protected StateChangedListener mStateChangedListener; + protected boolean mDeviceIdleMode; public StateController(StateChangedListener stateChangedListener, Context context) { mStateChangedListener = stateChangedListener; mContext = context; } + public void deviceIdleModeChanged(boolean enabled) { + mDeviceIdleMode = enabled; + } + /** * Implement the logic here to decide whether a job should be tracked by this controller. * This logic is put here so the JobManger can be completely agnostic of Controller logic. @@ -50,5 +55,4 @@ public abstract class StateController { public abstract void maybeStopTrackingJob(JobStatus jobStatus); public abstract void dumpControllerState(PrintWriter pw); - } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index b5036db..09d0501 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -40,6 +40,7 @@ import android.media.session.MediaSession; import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.media.AudioAttributes; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.DeadObjectException; @@ -887,6 +888,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } + public void playFromUri(Uri uri, Bundle extras) { + try { + mCb.onPlayFromUri(uri, extras); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in playFromUri.", e); + } + } + public void skipToTrack(long id) { try { mCb.onSkipToTrack(id); @@ -1103,6 +1112,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override + public void playFromUri(Uri uri, Bundle extras) throws RemoteException { + mSessionCb.playFromUri(uri, extras); + } + + @Override public void skipToQueueItem(long id) { mSessionCb.skipToTrack(id); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 8d46775..5de7d42 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -71,7 +71,9 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UP import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; +import android.Manifest; import android.app.ActivityManager; +import android.app.AppGlobals; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.IProcessObserver; @@ -83,6 +85,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -2021,6 +2024,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updateRulesForUidLocked(int uid) { if (!isUidValidForRules(uid)) return; + // quick check: if this uid doesn't have INTERNET permission, it doesn't have + // network access anyway, so it is a waste to mess with it here. + final IPackageManager ipm = AppGlobals.getPackageManager(); + try { + if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid) + != PackageManager.PERMISSION_GRANTED) { + return; + } + } catch (RemoteException e) { + } + final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final boolean uidForeground = isUidForegroundLocked(uid); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 20f5f97..a415a84 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -22,21 +22,28 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; +import static android.net.TrafficStats.UID_TETHERING; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.Binder; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.AtomicFile; +import android.util.IntArray; import libcore.io.IoUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; + import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -129,6 +136,23 @@ public class NetworkStatsCollection implements FileRotator.Reader { return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; } + public int[] getRelevantUids() { + final int callerUid = Binder.getCallingUid(); + IntArray uids = new IntArray(); + for (int i = 0; i < mStats.size(); i++) { + final Key key = mStats.keyAt(i); + if (isAccessibleToUser(key.uid, callerUid)) { + int j = uids.binarySearch(key.uid); + + if (j < 0) { + j = ~j; + uids.add(j, key.uid); + } + } + } + return uids.toArray(); + } + /** * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. @@ -144,12 +168,21 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { + final int callerUid = Binder.getCallingUid(); + if (!isAccessibleToUser(uid, callerUid)) { + throw new SecurityException("Network stats history of uid " + uid + + " is forbidden for caller " + callerUid); + } + final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDuration, estimateBuckets(), fields); + mBucketDuration, start == end ? 1 : estimateBuckets(), fields); + + // shortcut when we know stats will be empty + if (start == end) return combined; + for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - final boolean setMatches = set == SET_ALL || key.set == set; - if (key.uid == uid && setMatches && key.tag == tag + if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag && templateMatches(template, key.ident)) { final NetworkStatsHistory value = mStats.valueAt(i); combined.recordHistory(value, start, end); @@ -166,15 +199,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - // shortcut when we know stats will be empty if (start == end) return stats; + final NetworkStats.Entry entry = new NetworkStats.Entry(); + NetworkStatsHistory.Entry historyEntry = null; + + final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident)) { + if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid) + && key.set < NetworkStats.SET_DEBUG_START) { final NetworkStatsHistory value = mStats.valueAt(i); historyEntry = value.getValues(start, end, now, historyEntry); @@ -507,6 +542,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStatsHistory value = mStats.valueAt(i); if (!templateMatches(groupTemplate, key.ident)) continue; + if (key.set >= NetworkStats.SET_DEBUG_START) continue; final Key groupKey = new Key(null, key.uid, key.set, key.tag); NetworkStatsHistory groupHistory = grouped.get(groupKey); @@ -534,6 +570,12 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + private static boolean isAccessibleToUser(int uid, int callerUid) { + return callerUid == android.os.Process.SYSTEM_UID || + uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING + || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); + } + /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0b596aa..50e03a2 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -62,9 +62,13 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; +import android.Manifest; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.IAlarmManager; import android.app.PendingIntent; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -93,7 +97,9 @@ import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -116,6 +122,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.connectivity.Tethering; import java.io.File; @@ -429,7 +436,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return openSessionForUsageStats(null); + } + + @Override + public INetworkStatsSession openSessionForUsageStats(final String callingPackage) { assertBandwidthControlEnabled(); // return an IBinder which holds strong references to any loaded stats @@ -438,6 +449,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new INetworkStatsSession.Stub() { private NetworkStatsCollection mUidComplete; private NetworkStatsCollection mUidTagComplete; + private String mCallingPackage = callingPackage; private NetworkStatsCollection getUidComplete() { synchronized (mStatsLock) { @@ -458,8 +470,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override + public int[] getRelevantUids() { + enforcePermissionForManagedAdmin(mCallingPackage); + return getUidComplete().getRelevantUids(); + } + + @Override + public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, + long end) { + enforcePermission(mCallingPackage); + NetworkStats result = new NetworkStats(end - start, 1); + final long ident = Binder.clearCallingIdentity(); + try { + result.combineAllValues(internalGetSummaryForNetwork(template, start, end)); + } finally { + Binder.restoreCallingIdentity(ident); + } + return result; + } + + @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { + enforcePermission(mCallingPackage); return internalGetSummaryForNetwork(template, start, end); } @@ -471,6 +504,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { + enforcePermissionForManagedAdmin(mCallingPackage); final NetworkStats stats = getUidComplete().getSummary(template, start, end); if (includeTags) { final NetworkStats tagStats = getUidTagComplete() @@ -483,6 +517,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { + enforcePermissionForManagedAdmin(mCallingPackage); if (tag == TAG_NONE) { return getUidComplete().getHistory(template, uid, set, tag, fields); } else { @@ -498,6 +533,53 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; } + private boolean hasAppOpsPermission(String callingPackage) { + final int callingUid = Binder.getCallingUid(); + boolean appOpsAllow = false; + if (callingPackage != null) { + AppOpsManager appOps = (AppOpsManager) mContext.getSystemService( + Context.APP_OPS_SERVICE); + + final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + callingUid, callingPackage); + if (mode == AppOpsManager.MODE_DEFAULT) { + // The default behavior here is to check if PackageManager has given the app + // permission. + final int permissionCheck = mContext.checkCallingPermission( + Manifest.permission.PACKAGE_USAGE_STATS); + appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED; + } + appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED); + } + return appOpsAllow; + } + + private void enforcePermissionForManagedAdmin(String callingPackage) { + boolean hasPermission = hasAppOpsPermission(callingPackage); + if (!hasPermission) { + // Profile and device owners are exempt from permission checking. + final int callingUid = Binder.getCallingUid(); + final DevicePolicyManagerInternal dpmi = LocalServices.getService( + DevicePolicyManagerInternal.class); + if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) + || dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) { + return; + } + } + if (!hasPermission) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + } + } + + private void enforcePermission(String callingPackage) { + boolean appOpsAllow = hasAppOpsPermission(callingPackage); + if (!appOpsAllow) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + } + } + + /** * Return network summary, splicing between DEV and XT stats when * appropriate. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2629e48..c7dc74f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -248,8 +248,8 @@ public class PackageManagerService extends IPackageManager.Stub { private static final boolean DEBUG_DEXOPT = false; private static final boolean DEBUG_ABI_SELECTION = false; - private static final boolean RUNTIME_PERMISSIONS_ENABLED = - SystemProperties.getInt("ro.runtime.premissions.enabled", 0) == 1; + static final boolean RUNTIME_PERMISSIONS_ENABLED = + SystemProperties.getInt("ro.runtime.permissions.enabled", 0) == 1; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; @@ -275,6 +275,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final int SCAN_TRUSTED_OVERLAY = 1<<9; static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10; static final int SCAN_REPLACING = 1<<11; + static final int SCAN_REQUIRE_KNOWN = 1<<12; static final int REMOVE_CHATTY = 1<<16; @@ -339,7 +340,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** Permission grant: grant the permission as an install permission. */ private static final int GRANT_INSTALL = 2; - /** Permission grant: grant the permission as a runtime permission. */ + /** Permission grant: grant the permission as a runtime one. */ private static final int GRANT_RUNTIME = 3; /** Permission grant: grant as runtime a permission that was granted as an install time one. */ @@ -1348,7 +1349,7 @@ public class PackageManagerService extends IPackageManager.Stub { mOnlyCore = onlyCore; mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); - mSettings = new Settings(mContext, mPackages); + mSettings = new Settings(mPackages); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, @@ -1699,10 +1700,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); - scanDirLI(mAppInstallDir, 0, scanFlags, 0); + scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, - scanFlags, 0); + scanFlags | SCAN_REQUIRE_KNOWN, 0); /** * Remove disable package settings for any updated system @@ -1810,7 +1811,14 @@ public class PackageManagerService extends IPackageManager.Stub { + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; - + + // For now runtime permissions are toggled via a system property. + if (!RUNTIME_PERMISSIONS_ENABLED) { + // Remove the runtime permissions state if the feature + // was disabled by flipping the system property. + mSettings.deleteRuntimePermissionsFiles(); + } + updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) @@ -1842,7 +1850,6 @@ public class PackageManagerService extends IPackageManager.Stub { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); - mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock) @@ -1951,15 +1958,14 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - PermissionsState permissionsState = ps.getPermissionsState(); + final PermissionsState permissionsState = ps.getPermissionsState(); final int[] gids = permissionsState.computeGids(userId); - Set<String> permissions = permissionsState.getPermissions(userId); - + final Set<String> permissions = permissionsState.getPermissions(userId); final PackageUserState state = ps.readUserState(userId); + return PackageParser.generatePackageInfo(p, gids, flags, - ps.firstInstallTime, ps.lastUpdateTime, permissions, - state, userId); + ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId); } @Override @@ -2696,6 +2702,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean grantPermission(String packageName, String name, int userId) { + if (!RUNTIME_PERMISSIONS_ENABLED) { + return false; + } + if (!sUserManager.exists(userId)) { return false; } @@ -2707,6 +2717,9 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "grantPermission"); + boolean gidsChanged = false; + final SettingBase sb; + synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { @@ -2720,7 +2733,7 @@ public class PackageManagerService extends IPackageManager.Stub { enforceDeclaredAsUsedAndRuntimePermission(pkg, bp); - final SettingBase sb = (SettingBase) pkg.mExtras; + sb = (SettingBase) pkg.mExtras; if (sb == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -2734,19 +2747,27 @@ public class PackageManagerService extends IPackageManager.Stub { } case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { - killSettingPackagesForUser(sb, userId, KILL_APP_REASON_GIDS_CHANGED); + gidsChanged = true; } break; } // Not critical if that is lost - app has to request again. mSettings.writeRuntimePermissionsForUserLPr(userId, false); + } - return true; + if (gidsChanged) { + killSettingPackagesForUser(sb, userId, KILL_APP_REASON_GIDS_CHANGED); } + + return true; } @Override public boolean revokePermission(String packageName, String name, int userId) { + if (!RUNTIME_PERMISSIONS_ENABLED) { + return false; + } + if (!sUserManager.exists(userId)) { return false; } @@ -2758,6 +2779,8 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "revokePermission"); + final SettingBase sb; + synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { @@ -2771,7 +2794,7 @@ public class PackageManagerService extends IPackageManager.Stub { enforceDeclaredAsUsedAndRuntimePermission(pkg, bp); - final SettingBase sb = (SettingBase) pkg.mExtras; + sb = (SettingBase) pkg.mExtras; if (sb == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -2783,13 +2806,13 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } - killSettingPackagesForUser(sb, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); - // Critical, after this call all should never have the permission. mSettings.writeRuntimePermissionsForUserLPr(userId, true); - - return true; } + + killSettingPackagesForUser(sb, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); + + return true; } @Override @@ -5260,6 +5283,28 @@ public class PackageManagerService extends IPackageManager.Stub { + " already installed. Skipping duplicate."); } + // If we're only installing presumed-existing packages, require that the + // scanned APK is both already known and at the path previously established + // for it. Previously unknown packages we pick up normally, but if we have an + // a priori expectation about this package's install presence, enforce it. + if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) { + PackageSetting known = mSettings.peekPackageLPr(pkg.packageName); + if (known != null) { + if (DEBUG_PACKAGE_SCANNING) { + Log.d(TAG, "Examining " + pkg.codePath + + " and requiring known paths " + known.codePathString + + " & " + known.resourcePathString); + } + if (!pkg.applicationInfo.getCodePath().equals(known.codePathString) + || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) { + throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, + "Application package " + pkg.packageName + + " found at " + pkg.applicationInfo.getCodePath() + + " but expected at " + known.codePathString + "; ignoring."); + } + } + } + // Initialize package source and resource directories File destCodeFile = new File(pkg.applicationInfo.getCodePath()); File destResourceFile = new File(pkg.applicationInfo.getResourcePath()); @@ -6968,10 +7013,15 @@ public class PackageManagerService extends IPackageManager.Stub { PermissionsState permissionsState = ps.getPermissionsState(); PermissionsState origPermissions = permissionsState; - boolean changedPermission = false; + final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); + + int[] upgradeUserIds = PermissionsState.USERS_NONE; + int[] changedRuntimePermissionUserIds = PermissionsState.USERS_NONE; + + boolean changedInstallPermission = false; if (replace) { - ps.permissionsFixed = false; + ps.installPermissionsFixed = false; origPermissions = new PermissionsState(permissionsState); permissionsState.reset(); } @@ -7022,17 +7072,33 @@ public class PackageManagerService extends IPackageManager.Stub { <= Build.VERSION_CODES.LOLLIPOP_MR1) { // For legacy apps dangerous permissions are install time ones. grant = GRANT_INSTALL; - } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - // For modern system apps dangerous permissions are install time ones. - grant = GRANT_INSTALL; - } else { + } else if (ps.isSystem()) { + final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds(); if (origPermissions.hasInstallPermission(bp.name)) { - // For legacy apps that became modern, install becomes runtime. + // If a system app had an install permission, then the app was + // upgraded and we grant the permissions as runtime to all users. + grant = GRANT_UPGRADE; + upgradeUserIds = currentUserIds; + } else if (!Arrays.equals(updatedUserIds, currentUserIds)) { + // If users changed since the last permissions update for a + // system app, we grant the permission as runtime to the new users. grant = GRANT_UPGRADE; - } else if (replace) { - // For upgraded modern apps keep runtime permissions unchanged. + upgradeUserIds = currentUserIds; + for (int userId : updatedUserIds) { + upgradeUserIds = ArrayUtils.removeInt(upgradeUserIds, userId); + } + } else { + // Otherwise, we grant the permission as runtime if the app + // already had it, i.e. we preserve runtime permissions. grant = GRANT_RUNTIME; } + } else if (origPermissions.hasInstallPermission(bp.name)) { + // For legacy apps that became modern, install becomes runtime. + grant = GRANT_UPGRADE; + upgradeUserIds = currentUserIds; + } else if (replace) { + // For upgraded modern apps keep runtime permissions unchanged. + grant = GRANT_RUNTIME; } } break; @@ -7050,7 +7116,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (grant != GRANT_DENIED) { - if (!isSystemApp(ps) && ps.permissionsFixed) { + if (!isSystemApp(ps) && ps.installPermissionsFixed) { // If this is an existing, non-system package, then // we can't add any new permissions to it. if (!allowedSig && !origPermissions.hasInstallPermission(perm)) { @@ -7068,7 +7134,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Grant an install permission. if (permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { - changedPermission = true; + changedInstallPermission = true; } } break; @@ -7076,9 +7142,11 @@ public class PackageManagerService extends IPackageManager.Stub { // Grant previously granted runtime permissions. for (int userId : UserManagerService.getInstance().getUserIds()) { if (origPermissions.hasRuntimePermission(bp.name, userId)) { - if (permissionsState.grantRuntimePermission(bp, userId) != + if (permissionsState.grantRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_FAILURE) { - changedPermission = true; + // If we cannot put the permission as it was, we have to write. + changedRuntimePermissionUserIds = ArrayUtils.appendInt( + changedRuntimePermissionUserIds, userId); } } } @@ -7087,10 +7155,12 @@ public class PackageManagerService extends IPackageManager.Stub { case GRANT_UPGRADE: { // Grant runtime permissions for a previously held install permission. permissionsState.revokeInstallPermission(bp); - for (int userId : UserManagerService.getInstance().getUserIds()) { + for (int userId : upgradeUserIds) { if (permissionsState.grantRuntimePermission(bp, userId) != PermissionsState.PERMISSION_OPERATION_FAILURE) { - changedPermission = true; + // If we granted the permission, we have to write. + changedRuntimePermissionUserIds = ArrayUtils.appendInt( + changedRuntimePermissionUserIds, userId); } } } break; @@ -7107,7 +7177,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { if (permissionsState.revokeInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { - changedPermission = true; + changedInstallPermission = true; Slog.i(TAG, "Un-granting permission " + perm + " from package " + pkg.packageName + " (protectionLevel=" + bp.protectionLevel @@ -7127,12 +7197,21 @@ public class PackageManagerService extends IPackageManager.Stub { } } - if ((changedPermission || replace) && !ps.permissionsFixed && + if ((changedInstallPermission || replace) && !ps.installPermissionsFixed && !isSystemApp(ps) || isUpdatedSystemApp(ps)){ // This is the first that we have heard about this package, so the // permissions we have now selected are fixed until explicitly // changed. - ps.permissionsFixed = true; + ps.installPermissionsFixed = true; + } + + ps.setPermissionsUpdatedForUserIds(currentUserIds); + + // Persist the runtime permissions state for users with changes. + if (RUNTIME_PERMISSIONS_ENABLED) { + for (int userId : changedRuntimePermissionUserIds) { + mSettings.writeRuntimePermissionsForUserLPr(userId, true); + } } } @@ -10971,15 +11050,18 @@ public class PackageManagerService extends IPackageManager.Stub { for (int userId : UserManagerService.getInstance().getUserIds()) { final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs, userId); - if (userIdToKill == userId) { + if (userIdToKill == UserHandle.USER_ALL + || userIdToKill >= UserHandle.USER_OWNER) { // If gids changed for this user, kill all affected packages. - killSettingPackagesForUser(deletedPs, userIdToKill, - KILL_APP_REASON_GIDS_CHANGED); - } else if (userIdToKill == UserHandle.USER_ALL) { - // If gids changed for all users, kill them all - done. - killSettingPackagesForUser(deletedPs, userIdToKill, - KILL_APP_REASON_GIDS_CHANGED); - break; + mHandler.post(new Runnable() { + @Override + public void run() { + // This has to happen with no lock held. + killSettingPackagesForUser(deletedPs, userIdToKill, + KILL_APP_REASON_GIDS_CHANGED); + } + }); + break; } } } @@ -13359,6 +13441,11 @@ public class PackageManagerService extends IPackageManager.Stub { } } + void newUserCreatedLILPw(int userHandle) { + // Adding a user requires updating runtime permissions for system apps. + updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL); + } + @Override public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { mContext.enforceCallingOrSelfPermission( diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 889164c..a3f4c0b 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -70,4 +70,8 @@ final class PackageSetting extends PackageSettingBase { public boolean isForwardLocked() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; } + + public boolean isSystem() { + return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; + } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 9e8b3df..35df33b 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -92,7 +92,7 @@ abstract class PackageSettingBase extends SettingBase { PackageSignatures signatures = new PackageSignatures(); - boolean permissionsFixed; + boolean installPermissionsFixed; PackageKeySetData keySetData = new PackageKeySetData(); @@ -145,7 +145,7 @@ abstract class PackageSettingBase extends SettingBase { signatures = new PackageSignatures(base.signatures); - permissionsFixed = base.permissionsFixed; + installPermissionsFixed = base.installPermissionsFixed; userState.clear(); for (int i=0; i<base.userState.size(); i++) { userState.put(base.userState.keyAt(i), @@ -198,6 +198,7 @@ abstract class PackageSettingBase extends SettingBase { * Make a shallow copy of this package settings. */ public void copyFrom(PackageSettingBase base) { + setPermissionsUpdatedForUserIds(base.getPermissionsUpdatedForUserIds()); getPermissionsState().copyFrom(base.getPermissionsState()); primaryCpuAbiString = base.primaryCpuAbiString; secondaryCpuAbiString = base.secondaryCpuAbiString; @@ -206,7 +207,7 @@ abstract class PackageSettingBase extends SettingBase { firstInstallTime = base.firstInstallTime; lastUpdateTime = base.lastUpdateTime; signatures = base.signatures; - permissionsFixed = base.permissionsFixed; + installPermissionsFixed = base.installPermissionsFixed; userState.clear(); for (int i=0; i<base.userState.size(); i++) { userState.put(base.userState.keyAt(i), base.userState.valueAt(i)); diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java index 3e0e342..705abf8 100644 --- a/services/core/java/com/android/server/pm/PermissionsState.java +++ b/services/core/java/com/android/server/pm/PermissionsState.java @@ -55,9 +55,9 @@ public final class PermissionsState { /** The permission operation failed. */ public static final int PERMISSION_OPERATION_FAILURE = 3; - private static final int[] USERS_ALL = {UserHandle.USER_ALL}; + public static final int[] USERS_ALL = {UserHandle.USER_ALL}; - private static final int[] USERS_NONE = {}; + public static final int[] USERS_NONE = {}; private static final int[] NO_GIDS = {}; @@ -149,6 +149,9 @@ public final class PermissionsState { * #PERMISSION_OPERATION_FAILURE}. */ public int grantRuntimePermission(BasePermission permission, int userId) { + if (userId == UserHandle.USER_ALL) { + return PERMISSION_OPERATION_FAILURE; + } return grantPermission(permission, userId); } @@ -162,6 +165,9 @@ public final class PermissionsState { * #PERMISSION_OPERATION_FAILURE}. */ public int revokeRuntimePermission(BasePermission permission, int userId) { + if (userId == UserHandle.USER_ALL) { + return PERMISSION_OPERATION_FAILURE; + } return revokePermission(permission, userId); } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index d350c09..3a7b6ee 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -17,13 +17,15 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; -import android.util.ArraySet; + +import java.util.Arrays; abstract class SettingBase { int pkgFlags; int pkgPrivateFlags; private final PermissionsState mPermissionsState; + private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE; SettingBase(int pkgFlags, int pkgPrivateFlags) { setFlags(pkgFlags); @@ -35,12 +37,29 @@ abstract class SettingBase { pkgFlags = base.pkgFlags; pkgPrivateFlags = base.pkgPrivateFlags; mPermissionsState = new PermissionsState(base.mPermissionsState); + setPermissionsUpdatedForUserIds(base.mPermissionsUpdatedForUserIds); } public PermissionsState getPermissionsState() { return mPermissionsState; } + public int[] getPermissionsUpdatedForUserIds() { + return mPermissionsUpdatedForUserIds; + } + + public void setPermissionsUpdatedForUserIds(int[] userIds) { + if (Arrays.equals(mPermissionsUpdatedForUserIds, userIds)) { + return; + } + + if (userIds == PermissionsState.USERS_NONE || userIds == PermissionsState.USERS_ALL) { + mPermissionsUpdatedForUserIds = userIds; + } else { + mPermissionsUpdatedForUserIds = Arrays.copyOf(userIds, userIds.length); + } + } + void setFlags(int pkgFlags) { this.pkgFlags = pkgFlags & (ApplicationInfo.FLAG_SYSTEM diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 82aa74a..8f185ec 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -25,7 +25,6 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.os.Process.SYSTEM_UID; import static android.os.Process.PACKAGE_INFO_GID; -import android.content.Context; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ResolveInfo; @@ -177,7 +176,6 @@ final class Settings { private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall"; private final Object mLock; - private final Context mContext; private final RuntimePermissionPersistence mRuntimePermissionsPersistence; @@ -277,12 +275,11 @@ final class Settings { public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages); - Settings(Context context, Object lock) { - this(context, Environment.getDataDirectory(), lock); + Settings(Object lock) { + this(Environment.getDataDirectory(), lock); } - Settings(Context context, File dataDir, Object lock) { - mContext = context; + Settings(File dataDir, Object lock) { mLock = lock; mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock); @@ -948,6 +945,17 @@ final class Settings { return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME); } + boolean isFirstRuntimePermissionsBoot() { + return !getUserRuntimePermissionsFile(UserHandle.USER_OWNER).exists(); + } + + void deleteRuntimePermissionsFiles() { + for (int userId : UserManagerService.getInstance().getUserIds()) { + File file = getUserRuntimePermissionsFile(userId); + file.delete(); + } + } + private File getUserPackagesStateBackupFile(int userId) { return new File(Environment.getUserSystemDirectory(userId), "package-restrictions-backup.xml"); @@ -2730,6 +2738,18 @@ final class Settings { } } + // We keep track for which users we granted permissions to be able + // to grant runtime permissions to system apps for newly appeared + // users or newly appeared system apps. If we supported runtime + // permissions during the previous boot, then we already granted + // permissions for all device users. In such a case we set the users + // for which we granted permissions to avoid clobbering of runtime + // permissions we granted to system apps but the user revoked later. + if (!isFirstRuntimePermissionsBoot()) { + final int[] userIds = UserManagerService.getInstance().getUserIds(); + ps.setPermissionsUpdatedForUserIds(userIds); + } + mDisabledSysPackages.put(name, ps); } @@ -2990,7 +3010,7 @@ final class Settings { } else if (tagName.equals(TAG_PERMISSIONS)) { readInstallPermissionsLPr(parser, packageSetting.getPermissionsState()); - packageSetting.permissionsFixed = true; + packageSetting.installPermissionsFixed = true; } else if (tagName.equals("proper-signing-keyset")) { long id = Long.parseLong(parser.getAttributeValue(null, "identifier")); packageSetting.keySetData.setProperSigningKeySet(id); @@ -3011,7 +3031,17 @@ final class Settings { } } - + // We keep track for which users we granted permissions to be able + // to grant runtime permissions to system apps for newly appeared + // users or newly appeared system apps. If we supported runtime + // permissions during the previous boot, then we already granted + // permissions for all device users. In such a case we set the users + // for which we granted permissions to avoid clobbering of runtime + // permissions we granted to system apps but the user revoked later. + if (!isFirstRuntimePermissionsBoot()) { + final int[] userIds = UserManagerService.getInstance().getUserIds(); + packageSetting.setPermissionsUpdatedForUserIds(userIds); + } } else { XmlUtils.skipCurrentTag(parser); } @@ -3129,6 +3159,18 @@ final class Settings { XmlUtils.skipCurrentTag(parser); } } + + // We keep track for which users we granted permissions to be able + // to grant runtime permissions to system apps for newly appeared + // users or newly appeared system apps. If we supported runtime + // permissions during the previous boot, then we already granted + // permissions for all device users. In such a case we set the users + // for which we granted permissions to avoid clobbering of runtime + // permissions we granted to system apps but the user revoked later. + if (!isFirstRuntimePermissionsBoot()) { + final int[] userIds = UserManagerService.getInstance().getUserIds(); + su.setPermissionsUpdatedForUserIds(userIds); + } } else { XmlUtils.skipCurrentTag(parser); } @@ -3565,7 +3607,8 @@ final class Settings { pw.println(ps.installerPackageName); } pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures); - pw.print(prefix); pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed); + pw.print(prefix); pw.print(" installPermissionsFixed="); + pw.print(ps.installPermissionsFixed); pw.print(" installStatus="); pw.println(ps.installStatus); pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); pw.println(); @@ -3842,11 +3885,19 @@ final class Settings { } public void writePermissionsForUserSyncLPr(int userId) { + if (!PackageManagerService.RUNTIME_PERMISSIONS_ENABLED) { + return; + } + mHandler.removeMessages(userId); writePermissionsSync(userId); } public void writePermissionsForUserAsyncLPr(int userId) { + if (!PackageManagerService.RUNTIME_PERMISSIONS_ENABLED) { + return; + } + final long currentTimeMillis = SystemClock.uptimeMillis(); if (mWriteScheduled.get(userId)) { @@ -4006,128 +4057,67 @@ final class Settings { private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId) throws IOException, XmlPullParserException { - parser.next(); - skipEmptyTextTags(parser); - if (!accept(parser, XmlPullParser.START_TAG, TAG_RUNTIME_PERMISSIONS)) { - return; - } - - parser.next(); - - while (parsePackageLPr(parser, userId) - || parseSharedUserLPr(parser, userId)) { - parser.next(); - } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_RUNTIME_PERMISSIONS); - } - - private boolean parsePackageLPr(XmlPullParser parser, int userId) - throws IOException, XmlPullParserException { - skipEmptyTextTags(parser); - if (!accept(parser, XmlPullParser.START_TAG, TAG_PACKAGE)) { - return false; - } - - String name = parser.getAttributeValue(null, ATTR_NAME); - - parser.next(); - - PackageSetting ps = mPackages.get(name); - if (ps != null) { - while (parsePermissionLPr(parser, ps.getPermissionsState(), userId)) { - parser.next(); + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; } - } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_PACKAGE); - - return true; - } - - private boolean parseSharedUserLPr(XmlPullParser parser, int userId) - throws IOException, XmlPullParserException { - skipEmptyTextTags(parser); - if (!accept(parser, XmlPullParser.START_TAG, TAG_SHARED_USER)) { - return false; - } - - String name = parser.getAttributeValue(null, ATTR_NAME); - parser.next(); - - SharedUserSetting sus = mSharedUsers.get(name); - if (sus != null) { - while (parsePermissionLPr(parser, sus.getPermissionsState(), userId)) { - parser.next(); + switch (parser.getName()) { + case TAG_PACKAGE: { + String name = parser.getAttributeValue(null, ATTR_NAME); + PackageSetting ps = mPackages.get(name); + if (ps == null) { + Slog.w(PackageManagerService.TAG, "Unknown package:" + name); + XmlUtils.skipCurrentTag(parser); + continue; + } + parsePermissionsLPr(parser, ps.getPermissionsState(), userId); + } break; + + case TAG_SHARED_USER: { + String name = parser.getAttributeValue(null, ATTR_NAME); + SharedUserSetting sus = mSharedUsers.get(name); + if (sus == null) { + Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name); + XmlUtils.skipCurrentTag(parser); + continue; + } + parsePermissionsLPr(parser, sus.getPermissionsState(), userId); + } break; } } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_SHARED_USER); - - return true; } - private boolean parsePermissionLPr(XmlPullParser parser, PermissionsState permissionsState, + private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState, int userId) throws IOException, XmlPullParserException { - skipEmptyTextTags(parser); - if (!accept(parser, XmlPullParser.START_TAG, TAG_ITEM)) { - return false; - } - - String name = parser.getAttributeValue(null, ATTR_NAME); - - parser.next(); - - BasePermission bp = mPermissions.get(name); - if (bp != null) { - if (permissionsState.grantRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name); + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; } - } else { - Slog.w(PackageManagerService.TAG, "Unknown permission:" + name); - } - - skipEmptyTextTags(parser); - expect(parser, XmlPullParser.END_TAG, TAG_ITEM); - - return true; - } - private void expect(XmlPullParser parser, int type, String tag) - throws IOException, XmlPullParserException { - if (!accept(parser, type, tag)) { - throw new XmlPullParserException("Expected event: " + type - + " and tag: " + tag + " but got event: " + parser.getEventType() - + " and tag:" + parser.getName()); - } - } - - private void skipEmptyTextTags(XmlPullParser parser) - throws IOException, XmlPullParserException { - while (accept(parser, XmlPullParser.TEXT, null) - && parser.isWhitespace()) { - parser.next(); - } - } + switch (parser.getName()) { + case TAG_ITEM: { + String name = parser.getAttributeValue(null, ATTR_NAME); + BasePermission bp = mPermissions.get(name); + if (bp == null) { + Slog.w(PackageManagerService.TAG, "Unknown permission:" + name); + XmlUtils.skipCurrentTag(parser); + continue; + } - private boolean accept(XmlPullParser parser, int type, String tag) - throws IOException, XmlPullParserException { - if (parser.getEventType() != type) { - return false; - } - if (tag != null) { - if (!tag.equals(parser.getName())) { - return false; + if (permissionsState.grantRuntimePermission(bp, userId) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name); + } + } break; } - } else if (parser.getName() != null) { - return false; } - return true; } private void writePermissions(XmlSerializer serializer, Set<String> permissions) diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 26ecb72..8cc9d19 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1219,6 +1219,7 @@ public class UserManagerService extends IUserManager.Stub { updateUserIdsLocked(); Bundle restrictions = new Bundle(); mUserRestrictions.append(userId, restrictions); + mPm.newUserCreatedLILPw(userId); } } if (userInfo != null) { diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/power/DeviceIdleController.java index 062992d..dd00446 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/power/DeviceIdleController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.power; import android.app.AlarmManager; import android.app.PendingIntent; @@ -30,12 +30,16 @@ import android.hardware.TriggerEventListener; import android.hardware.display.DisplayManager; import android.net.INetworkPolicyManager; import android.os.Binder; +import android.os.PowerManager; +import android.os.PowerManagerInternal; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.UserHandle; import android.util.TimeUtils; import android.view.Display; import com.android.internal.app.IBatteryStats; +import com.android.server.SystemService; import com.android.server.am.BatteryStatsService; import java.io.FileDescriptor; @@ -60,6 +64,11 @@ public class DeviceIdleController extends SystemService { */ private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L; /** + * This is the time, after seeing motion, that we wait after becoming inactive from + * that until we start looking for motion again. + */ + private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L; + /** * This is the time, after the inactive timeout elapses, that we will wait looking * for significant motion until we truly consider the device to be idle. */ @@ -94,11 +103,13 @@ public class DeviceIdleController extends SystemService { private AlarmManager mAlarmManager; private IBatteryStats mBatteryStats; + private PowerManagerInternal mLocalPowerManager; private INetworkPolicyManager mNetworkPolicyManager; private DisplayManager mDisplayManager; private SensorManager mSensorManager; private Sensor mSigMotionSensor; private PendingIntent mAlarmIntent; + private Intent mIdleIntent; private Display mCurDisplay; private boolean mScreenOn; private boolean mCharging; @@ -124,6 +135,7 @@ public class DeviceIdleController extends SystemService { private int mState; + private long mInactiveTimeout; private long mNextAlarmTime; private long mNextIdlePendingDelay; private long mNextIdleDelay; @@ -181,6 +193,7 @@ public class DeviceIdleController extends SystemService { synchronized (this) { mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); mBatteryStats = BatteryStatsService.getService(); + mLocalPowerManager = getLocalService(PowerManagerInternal.class); mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface( ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); mDisplayManager = (DisplayManager) getContext().getSystemService( @@ -193,6 +206,9 @@ public class DeviceIdleController extends SystemService { .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0); + mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(ACTION_STEP_IDLE_STATE); @@ -205,6 +221,7 @@ public class DeviceIdleController extends SystemService { // a battery update the next time the level drops. mCharging = true; mState = STATE_ACTIVE; + mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT; updateDisplayLocked(); } @@ -238,12 +255,17 @@ public class DeviceIdleController extends SystemService { void becomeActiveLocked() { if (mState != STATE_ACTIVE) { + mLocalPowerManager.setDeviceIdleMode(false); try { mNetworkPolicyManager.setDeviceIdleMode(false); mBatteryStats.noteDeviceIdleMode(false, true, false); } catch (RemoteException e) { } + if (mState == STATE_IDLE) { + getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); + } mState = STATE_ACTIVE; + mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT; mNextIdlePendingDelay = 0; mNextIdleDelay = 0; cancelAlarmLocked(); @@ -256,7 +278,9 @@ public class DeviceIdleController extends SystemService { // Screen has turned off; we are now going to become inactive and start // waiting to see if we will ultimately go idle. mState = STATE_INACTIVE; - scheduleAlarmLocked(DEFAULT_INACTIVE_TIMEOUT, false); + mNextIdlePendingDelay = 0; + mNextIdleDelay = 0; + scheduleAlarmLocked(mInactiveTimeout, false); } } @@ -283,11 +307,13 @@ public class DeviceIdleController extends SystemService { mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT; } mState = STATE_IDLE; + mLocalPowerManager.setDeviceIdleMode(true); try { mNetworkPolicyManager.setDeviceIdleMode(true); mBatteryStats.noteDeviceIdleMode(true, false, false); } catch (RemoteException e) { } + getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); break; case STATE_IDLE: // We have been idling long enough, now it is time to do some work. @@ -297,11 +323,13 @@ public class DeviceIdleController extends SystemService { mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT; } mState = STATE_IDLE_PENDING; + mLocalPowerManager.setDeviceIdleMode(false); try { mNetworkPolicyManager.setDeviceIdleMode(false); mBatteryStats.noteDeviceIdleMode(false, false, false); } catch (RemoteException e) { } + getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); break; } } @@ -313,13 +341,18 @@ public class DeviceIdleController extends SystemService { // state to wait again for no motion. Note that we only monitor for significant // motion after moving out of the inactive state, so no need to worry about that. if (mState != STATE_ACTIVE) { - mState = STATE_INACTIVE; + mLocalPowerManager.setDeviceIdleMode(false); try { mNetworkPolicyManager.setDeviceIdleMode(false); mBatteryStats.noteDeviceIdleMode(false, false, true); } catch (RemoteException e) { } - stepIdleStateLocked(); + if (mState == STATE_IDLE) { + getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL); + } + mState = STATE_ACTIVE; + mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT; + becomeInactiveIfAppropriateLocked(); } } @@ -399,26 +432,30 @@ public class DeviceIdleController extends SystemService { } } - pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); - pw.print(" mCurDisplay="); pw.println(mCurDisplay); - pw.print(" mScreenOn="); pw.println(mScreenOn); - pw.print(" mCharging="); pw.println(mCharging); - pw.print(" mSigMotionActive="); pw.println(mSigMotionActive); - pw.print(" mState="); pw.println(stateToString(mState)); - if (mNextAlarmTime != 0) { - pw.print(" mNextAlarmTime="); - TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw); - pw.println(); - } - if (mNextIdlePendingDelay != 0) { - pw.print(" mNextIdlePendingDelay="); - TimeUtils.formatDuration(mNextIdlePendingDelay, pw); - pw.println(); - } - if (mNextIdleDelay != 0) { - pw.print(" mNextIdleDelay="); - TimeUtils.formatDuration(mNextIdleDelay, pw); + synchronized (this) { + pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); + pw.print(" mCurDisplay="); pw.println(mCurDisplay); + pw.print(" mScreenOn="); pw.println(mScreenOn); + pw.print(" mCharging="); pw.println(mCharging); + pw.print(" mSigMotionActive="); pw.println(mSigMotionActive); + pw.print(" mState="); pw.println(stateToString(mState)); + pw.print(" mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw); pw.println(); + if (mNextAlarmTime != 0) { + pw.print(" mNextAlarmTime="); + TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw); + pw.println(); + } + if (mNextIdlePendingDelay != 0) { + pw.print(" mNextIdlePendingDelay="); + TimeUtils.formatDuration(mNextIdlePendingDelay, pw); + pw.println(); + } + if (mNextIdleDelay != 0) { + pw.print(" mNextIdleDelay="); + TimeUtils.formatDuration(mNextIdleDelay, pw); + pw.println(); + } } } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 1349926..c48367e 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -78,6 +78,7 @@ final class Notifier { private static final int MSG_USER_ACTIVITY = 1; private static final int MSG_BROADCAST = 2; private static final int MSG_WIRELESS_CHARGING_STARTED = 3; + private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4; private final Object mLock = new Object(); @@ -92,6 +93,7 @@ final class Notifier { private final NotifierHandler mHandler; private final Intent mScreenOnIntent; private final Intent mScreenOffIntent; + private final Intent mScreenBrightnessBoostIntent; // The current interactive state. private int mActualInteractiveState; @@ -128,6 +130,10 @@ final class Notifier { mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); mScreenOffIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); + mScreenBrightnessBoostIntent = + new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED); + mScreenBrightnessBoostIntent.addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); // Initialize interactive state for battery stats. try { @@ -349,6 +355,19 @@ final class Notifier { } /** + * Called when screen brightness boost begins or ends. + */ + public void onScreenBrightnessBoostChanged() { + if (DEBUG) { + Slog.d(TAG, "onScreenBrightnessBoostChanged"); + } + + mSuspendBlocker.acquire(); + Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + } + /** * Called when there has been user activity. */ public void onUserActivity(int event, int uid) { @@ -457,6 +476,22 @@ final class Notifier { } } + private void sendBrightnessBoostChangedBroadcast() { + if (DEBUG) { + Slog.d(TAG, "Sending brightness boost changed broadcast."); + } + + mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null, + mScreeBrightnessBoostChangedDone, mHandler, 0, null, null); + } + + private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mSuspendBlocker.release(); + } + }; + private void sendWakeUpBroadcast() { if (DEBUG) { Slog.d(TAG, "Sending wake up broadcast."); @@ -539,6 +574,9 @@ final class Notifier { case MSG_WIRELESS_CHARGING_STARTED: playWirelessChargingStartedSound(); break; + case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED: + sendBrightnessBoostChangedBroadcast(); + break; } } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 9e373b7..6c8959c 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -420,6 +420,9 @@ public final class PowerManagerService extends SystemService // True if the battery level is currently considered low. private boolean mBatteryLevelLow; + // True if we are currently in device idle mode. + private boolean mDeviceIdleMode; + // True if theater mode is enabled private boolean mTheaterModeEnabled; @@ -1900,6 +1903,7 @@ public final class PowerManagerService extends SystemService } } mScreenBrightnessBoostInProgress = false; + mNotifier.onScreenBrightnessBoostChanged(); userActivityNoUpdateLocked(now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); } @@ -2178,6 +2182,12 @@ public final class PowerManagerService extends SystemService } } + private boolean isDeviceIdleModeInternal() { + synchronized (mLock) { + return mDeviceIdleMode; + } + } + private void handleBatteryStateChangedLocked() { mDirty |= DIRTY_BATTERY_STATE; updatePowerStateLocked(); @@ -2275,7 +2285,10 @@ public final class PowerManagerService extends SystemService Slog.i(TAG, "Brightness boost activated (uid " + uid +")..."); mLastScreenBrightnessBoostTime = eventTime; - mScreenBrightnessBoostInProgress = true; + if (!mScreenBrightnessBoostInProgress) { + mScreenBrightnessBoostInProgress = true; + mNotifier.onScreenBrightnessBoostChanged(); + } mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST; userActivityNoUpdateLocked(eventTime, @@ -2284,6 +2297,12 @@ public final class PowerManagerService extends SystemService } } + private boolean isScreenBrightnessBoostedInternal() { + synchronized (mLock) { + return mScreenBrightnessBoostInProgress; + } + } + /** * Called when a screen brightness boost timeout has occurred. * @@ -3050,6 +3069,16 @@ public final class PowerManagerService extends SystemService } } + @Override // Binder call + public boolean isDeviceIdleMode() { + final long ident = Binder.clearCallingIdentity(); + try { + return isDeviceIdleModeInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + /** * Reboots the device. * @@ -3218,6 +3247,16 @@ public final class PowerManagerService extends SystemService } @Override // Binder call + public boolean isScreenBrightnessBoosted() { + final long ident = Binder.clearCallingIdentity(); + try { + return isScreenBrightnessBoostedInternal(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override // Binder call protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { @@ -3295,5 +3334,12 @@ public final class PowerManagerService extends SystemService mLowPowerModeListeners.add(listener); } } + + @Override + public void setDeviceIdleMode(boolean enabled) { + synchronized (mLock) { + mDeviceIdleMode = enabled; + } + } } } diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 0109313..dec195d 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -272,13 +272,14 @@ public class TrustAgentWrapper { alarmFilter.addDataScheme(mAlarmIntent.getScheme()); final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME); alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL); - mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null); // Schedules a restart for when connecting times out. If the connection succeeds, // the restart is canceled in mCallback's onConnected. scheduleRestart(); mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); - if (!mBound) { + if (mBound) { + mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null); + } else { Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); } } @@ -398,7 +399,6 @@ public class TrustAgentWrapper { } public void destroy() { - mContext.unregisterReceiver(mBroadcastReceiver); mHandler.removeMessages(MSG_RESTART_TIMEOUT); if (!mBound) { @@ -408,6 +408,7 @@ public class TrustAgentWrapper { mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); mContext.unbindService(mConnection); mBound = false; + mContext.unregisterReceiver(mBroadcastReceiver); mTrustAgentService = null; mSetTrustAgentFeaturesToken = null; mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1dc027a..32bb78e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -178,7 +178,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_ORIENTATION = false; static final boolean DEBUG_APP_ORIENTATION = false; static final boolean DEBUG_CONFIGURATION = false; - static final boolean DEBUG_APP_TRANSITIONS = false; + static final boolean DEBUG_APP_TRANSITIONS = true; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; @@ -189,7 +189,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_LAYOUT_REPEATS = true; static final boolean DEBUG_SURFACE_TRACE = false; static final boolean DEBUG_WINDOW_TRACE = false; - static final boolean DEBUG_TASK_MOVEMENT = false; + static final boolean DEBUG_TASK_MOVEMENT = true; static final boolean DEBUG_STACK = false; static final boolean DEBUG_DISPLAY = false; static final boolean DEBUG_POWER = false; @@ -3056,7 +3056,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility + if (true || DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs); win.mEnforceSizeCompat = @@ -3720,10 +3720,8 @@ public class WindowManagerService extends IWindowManager.Stub } else { // TODO(multidisplay): Change to the correct display. final WindowList windows = getDefaultWindowListLocked(); - int pos = windows.size() - 1; - while (pos >= 0) { + for (int pos = windows.size() - 1; pos >= 0; --pos) { WindowState win = windows.get(pos); - pos--; if (win.mAppToken != null) { // We hit an application window. so the orientation will be determined by the // app window. No point in continuing further. @@ -4173,8 +4171,8 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition, - new RuntimeException("here").fillInStackTrace()); + if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition + + " Callers=" + Debug.getCallers(5)); if (mAppTransition.isTransitionSet()) { mAppTransition.setReady(); final long origId = Binder.clearCallingIdentity(); @@ -4610,8 +4608,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible + "): " + mAppTransition + " hidden=" + wtoken.hidden + " hiddenRequested=" + - wtoken.hiddenRequested, HIDE_STACK_CRAWLS ? - null : new RuntimeException("here").fillInStackTrace()); + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6)); // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp index 94853b8..cb70144 100644 --- a/services/core/jni/com_android_server_UsbMidiDevice.cpp +++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp @@ -94,9 +94,20 @@ android_server_UsbMidiDevice_open(JNIEnv *env, jobject /* thiz */, jint card, ji return fds; } +static void +android_server_UsbMidiDevice_close(JNIEnv *env, jobject /* thiz */, jobjectArray fds) +{ + int count = env->GetArrayLength(fds); + for (int i = 0; i < count; i++) { + jobject fd = env->GetObjectArrayElement(fds, i); + close(jniGetFDFromFileDescriptor(env, fd)); + } +} + static JNINativeMethod method_table[] = { { "nativeGetSubdeviceCount", "(II)I", (void*)android_server_UsbMidiDevice_get_subdevice_count }, { "nativeOpen", "(III)[Ljava/io/FileDescriptor;", (void*)android_server_UsbMidiDevice_open }, + { "nativeClose", "([Ljava/io/FileDescriptor;)V", (void*)android_server_UsbMidiDevice_close }, }; int register_android_server_UsbMidiDevice(JNIEnv *env) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d07cd98..73b5de1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1140,70 +1140,85 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = Binder.getCallingUid(); - final int userHandle = UserHandle.getUserId(callingUid); - final DevicePolicyData policy = getUserData(userHandle); - List<ActiveAdmin> candidates = new ArrayList<ActiveAdmin>(); + ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid); + if (result != null) { + return result; + } + + if (who != null) { + final int userId = UserHandle.getUserId(callingUid); + final DevicePolicyData policy = getUserData(userId); + ActiveAdmin admin = policy.mAdminMap.get(who); + if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { + throw new SecurityException("Admin " + admin.info.getComponent() + + " does not own the device"); + } + if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { + throw new SecurityException("Admin " + admin.info.getComponent() + + " does not own the profile"); + } + throw new SecurityException("Admin " + admin.info.getComponent() + + " did not specify uses-policy for: " + + admin.info.getTagForPolicy(reqPolicy)); + } else { + throw new SecurityException("No active admin owned by uid " + + Binder.getCallingUid() + " for policy #" + reqPolicy); + } + } - // Build a list of admins for this uid matching the given ComponentName + private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy, + int uid) { + // Try to find an admin which can use reqPolicy + final int userId = UserHandle.getUserId(uid); + final DevicePolicyData policy = getUserData(userId); if (who != null) { ActiveAdmin admin = policy.mAdminMap.get(who); if (admin == null) { throw new SecurityException("No active admin " + who); } - if (admin.getUid() != callingUid) { + if (admin.getUid() != uid) { throw new SecurityException("Admin " + who + " is not owned by uid " + Binder.getCallingUid()); } - candidates.add(admin); + if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) { + return admin; + } } else { for (ActiveAdmin admin : policy.mAdminList) { - if (admin.getUid() == callingUid) { - candidates.add(admin); + if (admin.getUid() == uid && isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, + userId)) { + return admin; } } } - // Try to find an admin which can use reqPolicy - for (ActiveAdmin admin : candidates) { - boolean ownsDevice = isDeviceOwner(admin.info.getPackageName()); - boolean ownsProfile = (getProfileOwner(userHandle) != null - && getProfileOwner(userHandle).getPackageName() - .equals(admin.info.getPackageName())); - boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName()) - && !hasUserSetupCompleted(userHandle); + return null; + } - if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { - if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) { - return admin; - } - } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { - if (ownsDevice || ownsProfile || ownsInitialization) { - return admin; - } - } else { - if (admin.info.usesPolicy(reqPolicy)) { - return admin; - } - } - } + private boolean isActiveAdminWithPolicyForUserLocked(ActiveAdmin admin, int reqPolicy, + int userId) { + boolean ownsDevice = isDeviceOwner(admin.info.getPackageName()); + boolean ownsProfile = (getProfileOwner(userId) != null + && getProfileOwner(userId).getPackageName() + .equals(admin.info.getPackageName())); + boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName()) + && !hasUserSetupCompleted(userId); - if (who != null) { - if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { - throw new SecurityException("Admin " + candidates.get(0).info.getComponent() - + " does not own the device"); + if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) { + if (ownsDevice || (userId == UserHandle.USER_OWNER && ownsInitialization)) { + return true; } - if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { - throw new SecurityException("Admin " + candidates.get(0).info.getComponent() - + " does not own the profile"); + } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) { + if (ownsDevice || ownsProfile || ownsInitialization) { + return true; } - throw new SecurityException("Admin " + candidates.get(0).info.getComponent() - + " did not specify uses-policy for: " - + candidates.get(0).info.getTagForPolicy(reqPolicy)); } else { - throw new SecurityException("No active admin owned by uid " - + Binder.getCallingUid() + " for policy #" + reqPolicy); + if (admin.info.usesPolicy(reqPolicy)) { + return true; + } } + return false; } void sendAdminCommandLocked(ActiveAdmin admin, String action) { @@ -3159,7 +3174,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } PersistentDataBlockManager manager = (PersistentDataBlockManager) mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); - manager.wipe(); + if (manager != null) { + manager.wipe(); + } } boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0; wipeDeviceOrUserLocked(wipeExtRequested, userHandle, @@ -5702,6 +5719,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean isActiveAdminWithPolicy(int uid, int reqPolicy) { + final int userId = UserHandle.getUserId(uid); + synchronized(DevicePolicyManagerService.this) { + return getActiveAdminWithPolicyForUidLocked(null, reqPolicy, uid) != null; + } + } + private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) { final List<OnCrossProfileWidgetProvidersChangeListener> listeners; synchronized (DevicePolicyManagerService.this) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ae2c54b..8c653e2 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -66,7 +66,6 @@ import com.android.server.lights.LightsService; import com.android.server.media.MediaRouterService; import com.android.server.media.MediaSessionService; import com.android.server.media.projection.MediaProjectionManagerService; -import com.android.server.MidiService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; import com.android.server.notification.NotificationManagerService; @@ -76,6 +75,7 @@ import com.android.server.pm.Installer; import com.android.server.pm.LauncherAppsService; import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerService; +import com.android.server.power.DeviceIdleController; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import com.android.server.restrictions.RestrictionsManagerService; @@ -124,6 +124,8 @@ public final class SystemServer { "com.android.server.print.PrintManagerService"; private static final String USB_SERVICE_CLASS = "com.android.server.usb.UsbService$Lifecycle"; + private static final String MIDI_SERVICE_CLASS = + "com.android.server.midi.MidiService$Lifecycle"; private static final String WIFI_SERVICE_CLASS = "com.android.server.wifi.WifiService"; private static final String WIFI_P2P_SERVICE_CLASS = @@ -406,12 +408,9 @@ public final class SystemServer { AudioService audioService = null; MmsServiceBroker mmsService = null; EntropyMixer entropyMixer = null; - MidiService midiService = null; boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false); - boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false); boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false); - boolean disableTelephony = SystemProperties.getBoolean("config.disable_telephony", false); boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false); boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false); boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false); @@ -520,7 +519,6 @@ public final class SystemServer { LockSettingsService lockSettings = null; AssetAtlasService atlas = null; MediaRouterService mediaRouter = null; - MidiService midi = null; // Bring up services needed for UI. if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { @@ -792,32 +790,33 @@ public final class SystemServer { } } - if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) { - try { - Slog.i(TAG, "Audio Service"); - audioService = new AudioService(context); - ServiceManager.addService(Context.AUDIO_SERVICE, audioService); - } catch (Throwable e) { - reportWtf("starting Audio Service", e); - } + try { + Slog.i(TAG, "Audio Service"); + audioService = new AudioService(context); + ServiceManager.addService(Context.AUDIO_SERVICE, audioService); + } catch (Throwable e) { + reportWtf("starting Audio Service", e); } if (!disableNonCoreServices) { mSystemServiceManager.startService(DockObserver.class); } - if (!disableMedia) { - try { - Slog.i(TAG, "Wired Accessory Manager"); - // Listen for wired headset changes - inputManager.setWiredAccessoryCallbacks( - new WiredAccessoryManager(context, inputManager)); - } catch (Throwable e) { - reportWtf("starting WiredAccessoryManager", e); - } + try { + Slog.i(TAG, "Wired Accessory Manager"); + // Listen for wired headset changes + inputManager.setWiredAccessoryCallbacks( + new WiredAccessoryManager(context, inputManager)); + } catch (Throwable e) { + reportWtf("starting WiredAccessoryManager", e); } if (!disableNonCoreServices) { + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) { + // Start MIDI Manager service + mSystemServiceManager.startService(MIDI_SERVICE_CLASS); + } + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST) || mPackageManager.hasSystemFeature( PackageManager.FEATURE_USB_ACCESSORY)) { @@ -835,16 +834,6 @@ public final class SystemServer { } } - if (!disableNonCoreServices) { - try { - Slog.i(TAG, "MIDI Service"); - ServiceManager.addService(Context.MIDI_SERVICE, - new MidiService(context)); - } catch (Throwable e) { - reportWtf("starting MIDI Service", e); - } - } - mSystemServiceManager.startService(TwilightService.class); mSystemServiceManager.startService(JobSchedulerService.class); @@ -891,14 +880,12 @@ public final class SystemServer { } } - if (!disableMedia) { - try { - Slog.i(TAG, "CommonTimeManagementService"); - commonTimeMgmtService = new CommonTimeManagementService(context); - ServiceManager.addService("commontime_management", commonTimeMgmtService); - } catch (Throwable e) { - reportWtf("starting CommonTimeManagementService service", e); - } + try { + Slog.i(TAG, "CommonTimeManagementService"); + commonTimeMgmtService = new CommonTimeManagementService(context); + ServiceManager.addService("commontime_management", commonTimeMgmtService); + } catch (Throwable e) { + reportWtf("starting CommonTimeManagementService service", e); } if (!disableNetwork) { diff --git a/services/midi/Android.mk b/services/midi/Android.mk new file mode 100644 index 0000000..faac01c --- /dev/null +++ b/services/midi/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.midi + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +LOCAL_JAVA_LIBRARIES := services.core + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/core/java/com/android/server/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java index 3418930..1d2180e 100644 --- a/services/core/java/com/android/server/MidiService.java +++ b/services/midi/java/com/android/server/midi/MidiService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.midi; import android.content.Context; import android.content.Intent; @@ -40,6 +40,7 @@ import android.util.Log; import com.android.internal.content.PackageMonitor; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; +import com.android.server.SystemService; import org.xmlpull.v1.XmlPullParser; @@ -47,9 +48,25 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; public class MidiService extends IMidiManager.Stub { + + public static class Lifecycle extends SystemService { + private MidiService mMidiService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mMidiService = new MidiService(getContext()); + publishBinderService(Context.MIDI_SERVICE, mMidiService); + } + } + private static final String TAG = "MidiService"; private final Context mContext; @@ -269,7 +286,9 @@ public class MidiService extends IMidiManager.Stub { public void binderDied() { synchronized (mDevicesByInfo) { - removeDeviceLocked(this); + if (mDevicesByInfo.remove(mDeviceInfo) != null) { + removeDeviceLocked(this); + } } } @@ -368,6 +387,7 @@ public class MidiService extends IMidiManager.Stub { synchronized (mDevicesByInfo) { Device device = mDevicesByServer.get(server.asBinder()); if (device != null) { + mDevicesByInfo.remove(device.getDeviceInfo()); removeDeviceLocked(device); } } @@ -454,16 +474,14 @@ public class MidiService extends IMidiManager.Stub { // synchronize on mDevicesByInfo private void removeDeviceLocked(Device device) { - if (mDevicesByInfo.remove(device.getDeviceInfo()) != null) { - IMidiDeviceServer server = device.getDeviceServer(); - if (server != null) { - mDevicesByServer.remove(server); - } + IMidiDeviceServer server = device.getDeviceServer(); + if (server != null) { + mDevicesByServer.remove(server); + } - synchronized (mClients) { - for (Client c : mClients.values()) { - c.deviceRemoved(device); - } + synchronized (mClients) { + for (Client c : mClients.values()) { + c.deviceRemoved(device); } } } @@ -616,8 +634,11 @@ public class MidiService extends IMidiManager.Stub { private void removePackageDeviceServers(String packageName) { synchronized (mDevicesByInfo) { - for (Device device : mDevicesByInfo.values()) { + Iterator<Device> iterator = mDevicesByInfo.values().iterator(); + while (iterator.hasNext()) { + Device device = iterator.next(); if (packageName.equals(device.getPackageName())) { + iterator.remove(); removeDeviceLocked(device); } } @@ -634,15 +655,19 @@ public class MidiService extends IMidiManager.Stub { pw.println("Devices:"); pw.increaseIndent(); - for (Device device : mDevicesByInfo.values()) { - pw.println(device.toString()); + synchronized (mDevicesByInfo) { + for (Device device : mDevicesByInfo.values()) { + pw.println(device.toString()); + } } pw.decreaseIndent(); pw.println("Clients:"); pw.increaseIndent(); - for (Client client : mClients.values()) { - pw.println(client.toString()); + synchronized (mClients) { + for (Client client : mClients.values()) { + pw.println(client.toString()); + } } pw.decreaseIndent(); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 4dc1131..a3f3a5d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -134,7 +134,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase { public void testSettingsReadOld() { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object()); + Settings settings = new Settings(getContext().getFilesDir(), new Object()); assertEquals(true, settings.readLPw(null, null, 0, false)); assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3)); assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1)); @@ -152,12 +152,12 @@ public class PackageManagerSettingsTests extends AndroidTestCase { public void testNewPackageRestrictionsFile() { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object()); + Settings settings = new Settings(getContext().getFilesDir(), new Object()); assertEquals(true, settings.readLPw(null, null, 0, false)); settings.writeLPr(); // Create Settings again to make it read from the new files - settings = new Settings(getContext(), getContext().getFilesDir(), new Object()); + settings = new Settings(getContext().getFilesDir(), new Object()); assertEquals(true, settings.readLPw(null, null, 0, false)); PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2); @@ -168,7 +168,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase { public void testEnableDisable() { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object()); + Settings settings = new Settings(getContext().getFilesDir(), new Object()); assertEquals(true, settings.readLPw(null, null, 0, false)); // Enable/Disable a package diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 23e1970..2728af1 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -17,6 +17,7 @@ package com.android.server.usb; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; @@ -55,6 +56,7 @@ public final class UsbAlsaManager { private final Context mContext; private IAudioService mAudioService; + private final boolean mHasMidiFeature; private final AlsaCardsParser mCardsParser = new AlsaCardsParser(); private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser(); @@ -126,6 +128,7 @@ public final class UsbAlsaManager { /* package */ UsbAlsaManager(Context context) { mContext = context; + mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI); // initial scan mCardsParser.scan(); @@ -389,7 +392,7 @@ public final class UsbAlsaManager { // mDevicesParser.scan() boolean hasMidi = mDevicesParser.hasMIDIDevices(addedCard); - if (hasMidi) { + if (hasMidi && mHasMidiFeature) { int device = mDevicesParser.getDefaultDeviceNum(addedCard); AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI); if (alsaDevice != null) { @@ -459,7 +462,11 @@ public final class UsbAlsaManager { } /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) { - if (enabled) { + if (!mHasMidiFeature) { + return; + } + + if (enabled && mPeripheralMidiDevice == null) { Bundle properties = new Bundle(); Resources r = mContext.getResources(); properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString( @@ -469,7 +476,7 @@ public final class UsbAlsaManager { properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card); properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device); mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device); - } else if (mPeripheralMidiDevice != null) { + } else if (!enabled && mPeripheralMidiDevice != null) { IoUtils.closeQuietly(mPeripheralMidiDevice); mPeripheralMidiDevice = null; } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 41cf2ef..6adb8be 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -126,6 +126,8 @@ public class UsbDeviceManager { private boolean mAdbEnabled; private boolean mAudioSourceEnabled; private boolean mMidiEnabled; + private int mMidiCard; + private int mMidiDevice; private Map<String, List<Pair<String, String>>> mOemModeMap; private String[] mAccessoryStrings; private UsbDebuggingManager mDebuggingManager; @@ -363,18 +365,6 @@ public class UsbDeviceManager { updateState(state); mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); - // Upgrade step for previous versions that used persist.service.adb.enable - String value = SystemProperties.get("persist.service.adb.enable", ""); - if (value.length() > 0) { - char enable = value.charAt(0); - if (enable == '1') { - setAdbEnabled(true); - } else if (enable == '0') { - setAdbEnabled(false); - } - SystemProperties.set("persist.service.adb.enable", ""); - } - // register observer to listen for settings changes mContentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), @@ -623,26 +613,24 @@ public class UsbDeviceManager { private void updateMidiFunction() { boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI); if (enabled != mMidiEnabled) { - int card = -1; - int device = -1; - if (enabled) { Scanner scanner = null; try { scanner = new Scanner(new File(MIDI_ALSA_PATH)); - card = scanner.nextInt(); - device = scanner.nextInt(); + mMidiCard = scanner.nextInt(); + mMidiDevice = scanner.nextInt(); } catch (FileNotFoundException e) { Slog.e(TAG, "could not open MIDI PCM file", e); + enabled = false; } finally { if (scanner != null) { scanner.close(); } } } - mUsbAlsaManager.setPeripheralMidiState(enabled, card, device); mMidiEnabled = enabled; } + mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice); } @Override diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java index f23bb93..7c101a4 100644 --- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java +++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java @@ -19,7 +19,6 @@ package com.android.server.usb; import android.content.Context; import android.media.midi.MidiDeviceInfo; import android.media.midi.MidiDeviceServer; -import android.media.midi.MidiDispatcher; import android.media.midi.MidiManager; import android.media.midi.MidiReceiver; import android.media.midi.MidiSender; @@ -47,6 +46,8 @@ public final class UsbMidiDevice implements Closeable { private static final int BUFFER_SIZE = 512; + private final FileDescriptor[] mFileDescriptors; + // for polling multiple FileDescriptors for MIDI events private final StructPollfd[] mPollFDs; // streams for reading from ALSA driver @@ -69,7 +70,7 @@ public final class UsbMidiDevice implements Closeable { return null; } - UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors); + UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors); if (!midiDevice.register(context, properties)) { IoUtils.closeQuietly(midiDevice); Log.e(TAG, "createDeviceServer failed"); @@ -78,14 +79,15 @@ public final class UsbMidiDevice implements Closeable { return midiDevice; } - private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) { - int inputCount = inputFiles.length; - int outputCount = outputFiles.length; + private UsbMidiDevice(FileDescriptor[] fileDescriptors) { + mFileDescriptors = fileDescriptors; + int inputCount = fileDescriptors.length; + int outputCount = fileDescriptors.length; mPollFDs = new StructPollfd[inputCount]; mInputStreams = new FileInputStream[inputCount]; for (int i = 0; i < inputCount; i++) { - FileDescriptor fd = inputFiles[i]; + FileDescriptor fd = fileDescriptors[i]; StructPollfd pollfd = new StructPollfd(); pollfd.fd = fd; pollfd.events = (short)OsConstants.POLLIN; @@ -95,7 +97,7 @@ public final class UsbMidiDevice implements Closeable { mOutputStreams = new FileOutputStream[outputCount]; for (int i = 0; i < outputCount; i++) { - mOutputStreams[i] = new FileOutputStream(outputFiles[i]); + mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]); } mInputPortReceivers = new MidiReceiver[inputCount]; @@ -176,8 +178,10 @@ public final class UsbMidiDevice implements Closeable { for (int i = 0; i < mOutputStreams.length; i++) { mOutputStreams[i].close(); } + nativeClose(mFileDescriptors); } private static native int nativeGetSubdeviceCount(int card, int device); private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount); + private static native void nativeClose(FileDescriptor[] fileDescriptors); } |
