diff options
Diffstat (limited to 'core/java')
53 files changed, 2394 insertions, 1241 deletions
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl index 451af99..fe8e228 100644 --- a/core/java/android/app/IBackupAgent.aidl +++ b/core/java/android/app/IBackupAgent.aidl @@ -100,6 +100,11 @@ oneway interface IBackupAgent { void doFullBackup(in ParcelFileDescriptor data, int token, IBackupManager callbackBinder); /** + * Estimate how much data a full backup will deliver + */ + void doMeasureFullBackup(int token, IBackupManager callbackBinder); + + /** * Restore a single "file" to the application. The file was typically obtained from * a full-backup dataset. The agent reads 'size' bytes of file content * from the provided file descriptor. diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ea48b61..cf6619f 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -175,7 +175,8 @@ public class DevicePolicyManager { * * <p>This component is set as device owner and active admin when device owner provisioning is * started by an NFC message containing an NFC record with MIME type - * {@link #MIME_TYPE_PROVISIONING_NFC_V2}. + * {@link #MIME_TYPE_PROVISIONING_NFC_V2}. For the NFC record, the component name should be + * flattened to a string, via {@link ComponentName#flattenToShortString()}. * * @see DeviceAdminReceiver */ @@ -398,14 +399,16 @@ public class DevicePolicyManager { "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; /** - * On devices managed by a device owner app, a String representation of a Component name extra - * indicating the component of the application that is temporarily granted device owner - * privileges during device initialization and profile owner privileges during secondary user - * initialization. + * On devices managed by a device owner app, a {@link ComponentName} extra indicating the + * component of the application that is temporarily granted device owner privileges during + * device initialization and profile owner privileges during secondary user initialization. * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - * @see ComponentName#unflattenFromString() + * <p> + * It can also be used in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts + * device owner provisioning via an NFC bump. For the NFC record, it should be flattened to a + * string first. + * + * @see ComponentName#flattenToShortString() */ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME"; diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 7f89100..2bf267a 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -424,10 +424,12 @@ public abstract class BackupAgent extends ContextWrapper { } // And now that we know where it lives, semantically, back it up appropriately - Log.i(TAG, "backupFile() of " + filePath + " => domain=" + domain + // In the measurement case, backupToTar() updates the size in output and returns + // without transmitting any file data. + if (DEBUG) Log.i(TAG, "backupFile() of " + filePath + " => domain=" + domain + " rootpath=" + rootpath); - FullBackup.backupToTar(getPackageName(), domain, null, rootpath, filePath, - output.getData()); + + FullBackup.backupToTar(getPackageName(), domain, null, rootpath, filePath, output); } /** @@ -477,9 +479,8 @@ public abstract class BackupAgent extends ContextWrapper { continue; } - // Finally, back this file up before proceeding - FullBackup.backupToTar(packageName, domain, null, rootPath, filePath, - output.getData()); + // Finally, back this file up (or measure it) before proceeding + FullBackup.backupToTar(packageName, domain, null, rootPath, filePath, output); } } } @@ -640,7 +641,7 @@ public abstract class BackupAgent extends ContextWrapper { Binder.restoreCallingIdentity(ident); try { - callbackBinder.opComplete(token); + callbackBinder.opComplete(token, 0); } catch (RemoteException e) { // we'll time out anyway, so we're safe } @@ -670,7 +671,7 @@ public abstract class BackupAgent extends ContextWrapper { Binder.restoreCallingIdentity(ident); try { - callbackBinder.opComplete(token); + callbackBinder.opComplete(token, 0); } catch (RemoteException e) { // we'll time out anyway, so we're safe } @@ -692,10 +693,10 @@ public abstract class BackupAgent extends ContextWrapper { try { BackupAgent.this.onFullBackup(new FullBackupDataOutput(data)); } catch (IOException ex) { - Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); + Log.d(TAG, "onFullBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw new RuntimeException(ex); } catch (RuntimeException ex) { - Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); + Log.d(TAG, "onFullBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); throw ex; } finally { // ... and then again after, as in the doBackup() case @@ -713,13 +714,37 @@ public abstract class BackupAgent extends ContextWrapper { Binder.restoreCallingIdentity(ident); try { - callbackBinder.opComplete(token); + callbackBinder.opComplete(token, 0); } catch (RemoteException e) { // we'll time out anyway, so we're safe } } } + public void doMeasureFullBackup(int token, IBackupManager callbackBinder) { + // Ensure that we're running with the app's normal permission level + final long ident = Binder.clearCallingIdentity(); + FullBackupDataOutput measureOutput = new FullBackupDataOutput(); + + waitForSharedPrefs(); + try { + BackupAgent.this.onFullBackup(measureOutput); + } catch (IOException ex) { + Log.d(TAG, "onFullBackup[M] (" + BackupAgent.this.getClass().getName() + ") threw", ex); + throw new RuntimeException(ex); + } catch (RuntimeException ex) { + Log.d(TAG, "onFullBackup[M] (" + BackupAgent.this.getClass().getName() + ") threw", ex); + throw ex; + } finally { + Binder.restoreCallingIdentity(ident); + try { + callbackBinder.opComplete(token, measureOutput.getSize()); + } catch (RemoteException e) { + // timeout, so we're safe + } + } + } + @Override public void doRestoreFile(ParcelFileDescriptor data, long size, int type, String domain, String path, long mode, long mtime, @@ -728,6 +753,7 @@ public abstract class BackupAgent extends ContextWrapper { try { BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime); } catch (IOException e) { + Log.d(TAG, "onRestoreFile (" + BackupAgent.this.getClass().getName() + ") threw", e); throw new RuntimeException(e); } finally { // Ensure that any side-effect SharedPreferences writes have landed @@ -735,7 +761,7 @@ public abstract class BackupAgent extends ContextWrapper { Binder.restoreCallingIdentity(ident); try { - callbackBinder.opComplete(token); + callbackBinder.opComplete(token, 0); } catch (RemoteException e) { // we'll time out anyway, so we're safe } @@ -747,13 +773,16 @@ public abstract class BackupAgent extends ContextWrapper { long ident = Binder.clearCallingIdentity(); try { BackupAgent.this.onRestoreFinished(); + } catch (Exception e) { + Log.d(TAG, "onRestoreFinished (" + BackupAgent.this.getClass().getName() + ") threw", e); + throw e; } finally { // Ensure that any side-effect SharedPreferences writes have landed waitForSharedPrefs(); Binder.restoreCallingIdentity(ident); try { - callbackBinder.opComplete(token); + callbackBinder.opComplete(token, 0); } catch (RemoteException e) { // we'll time out anyway, so we're safe } diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index e853540..ca6dc69 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -393,6 +393,26 @@ public class BackupTransport { } /** + * Called after {@link #performFullBackup} to make sure that the transport is willing to + * handle a full-data backup operation of the specified size on the current package. + * If the transport returns anything other than TRANSPORT_OK, the package's backup + * operation will be skipped (and {@link #finishBackup() invoked} with no data for that + * package being passed to {@link #sendBackupData}. + * + * Added in MNC (API 23). + * + * @param size The estimated size of the full-data payload for this app. This includes + * manifest and archive format overhead, but is not guaranteed to be precise. + * @return TRANSPORT_OK if the platform is to proceed with the full-data backup, + * TRANSPORT_PACKAGE_REJECTED if the proposed payload size is too large for + * the transport to handle, or TRANSPORT_ERROR to indicate a fatal error + * condition that means the platform cannot perform a backup at this time. + */ + public int checkFullBackupSize(long size) { + return BackupTransport.TRANSPORT_OK; + } + + /** * Tells the transport to read {@code numBytes} bytes of data from the socket file * descriptor provided in the {@link #performFullBackup(PackageInfo, ParcelFileDescriptor)} * call, and deliver those bytes to the datastore. @@ -588,6 +608,11 @@ public class BackupTransport { } @Override + public int checkFullBackupSize(long size) { + return BackupTransport.this.checkFullBackupSize(size); + } + + @Override public int sendBackupData(int numBytes) throws RemoteException { return BackupTransport.this.sendBackupData(numBytes); } diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index e5b47c6..259884e 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -58,7 +58,7 @@ public class FullBackup { * @hide */ static public native int backupToTar(String packageName, String domain, - String linkdomain, String rootpath, String path, BackupDataOutput output); + String linkdomain, String rootpath, String path, FullBackupDataOutput output); /** * Copy data from a socket to the given File location on permanent storage. The diff --git a/core/java/android/app/backup/FullBackupDataOutput.java b/core/java/android/app/backup/FullBackupDataOutput.java index 99dab1f..94704b9 100644 --- a/core/java/android/app/backup/FullBackupDataOutput.java +++ b/core/java/android/app/backup/FullBackupDataOutput.java @@ -9,7 +9,14 @@ import android.os.ParcelFileDescriptor; */ public class FullBackupDataOutput { // Currently a name-scoping shim around BackupDataOutput - private BackupDataOutput mData; + private final BackupDataOutput mData; + private long mSize; + + /** @hide - used only in measure operation */ + public FullBackupDataOutput() { + mData = null; + mSize = 0; + } /** @hide */ public FullBackupDataOutput(ParcelFileDescriptor fd) { @@ -18,4 +25,14 @@ public class FullBackupDataOutput { /** @hide */ public BackupDataOutput getData() { return mData; } + + /** @hide - used for measurement pass */ + public void addSize(long size) { + if (size > 0) { + mSize += size; + } + } + + /** @hide - used for measurement pass */ + public long getSize() { return mSize; } } diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index 41ad936..8f36dc4 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -286,11 +286,14 @@ interface IBackupManager { * Notify the backup manager that a BackupAgent has completed the operation * corresponding to the given token. * - * @param token The transaction token passed to a BackupAgent's doBackup() or - * doRestore() method. + * @param token The transaction token passed to the BackupAgent method being + * invoked. + * @param result In the case of a full backup measure operation, the estimated + * total file size that would result from the operation. Unused in all other + * cases. * {@hide} */ - void opComplete(int token); + void opComplete(int token, long result); /** * Make the device's backup and restore machinery (in)active. When it is inactive, diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 8f17845..2496e45 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -340,8 +340,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * cleartext network traffic, in which case platform components (e.g., HTTP stacks, * {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use cleartext traffic. * Third-party libraries are encouraged to honor this flag as well. - * - * @hide */ public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27; @@ -379,7 +377,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED}, * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED}, * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME}, - * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}. + * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_USES_CLEARTEXT_TRAFFIC}, + * {@link #FLAG_MULTIARCH}. */ public int flags = 0; @@ -655,7 +654,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } pw.println(prefix + "dataDir=" + dataDir); if (sharedLibraryFiles != null) { - pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles); + pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles)); } pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion + " versionCode=" + versionCode); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 59a16da..f0d1da9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1600,6 +1600,12 @@ public abstract class PackageManager { @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_GAMEPAD = "android.hardware.gamepad"; + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device has a full implementation of the android.media.midi.* APIs. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_MIDI = "android.software.midi"; /** * Action to external storage service to clean out removed apps. diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 14af584..b5eeb30 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1314,7 +1314,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction * corresponding to the Locale. * - * @see {@link View#LAYOUT_DIRECTION_LTR} and {@link View#LAYOUT_DIRECTION_RTL} + * @see View#LAYOUT_DIRECTION_LTR + * @see View#LAYOUT_DIRECTION_RTL */ public void setLayoutDirection(Locale locale) { // There is a "1" difference between the configuration values for diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 95ad57e..44018ff 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -111,12 +111,12 @@ public class Resources { // single-threaded, and after that these are immutable. private static final LongSparseArray<ConstantState>[] sPreloadedDrawables; private static final LongSparseArray<ConstantState> sPreloadedColorDrawables - = new LongSparseArray<ConstantState>(); + = new LongSparseArray<>(); private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists - = new LongSparseArray<ColorStateListFactory>(); + = new LongSparseArray<>(); // Pool of TypedArrays targeted to this Resources object. - final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<TypedArray>(5); + final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5); // Used by BridgeResources in layoutlib static Resources mSystem = null; @@ -128,21 +128,19 @@ public class Resources { private final Object mAccessLock = new Object(); private final Configuration mTmpConfig = new Configuration(); private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache = - new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>(); + new ArrayMap<>(); private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache = - new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>(); + new ArrayMap<>(); private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache = - new ConfigurationBoundResourceCache<ColorStateList>(this); + new ConfigurationBoundResourceCache<>(this); private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = - new ConfigurationBoundResourceCache<Animator>(this); + new ConfigurationBoundResourceCache<>(this); private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = - new ConfigurationBoundResourceCache<StateListAnimator>(this); + new ConfigurationBoundResourceCache<>(this); private TypedValue mTmpValue = new TypedValue(); private boolean mPreloading; - private TypedArray mCachedStyledAttributes = null; - private int mLastCachedXmlBlockIndex = -1; private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 }; private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4]; @@ -157,8 +155,8 @@ public class Resources { static { sPreloadedDrawables = new LongSparseArray[2]; - sPreloadedDrawables[0] = new LongSparseArray<ConstantState>(); - sPreloadedDrawables[1] = new LongSparseArray<ConstantState>(); + sPreloadedDrawables[0] = new LongSparseArray<>(); + sPreloadedDrawables[1] = new LongSparseArray<>(); } /** @@ -1876,7 +1874,7 @@ public class Resources { // the framework. mCompatibilityInfo.applyToDisplayMetrics(mMetrics); - int configChanges = calcConfigChanges(config); + final int configChanges = calcConfigChanges(config); if (mConfiguration.locale == null) { mConfiguration.locale = Locale.getDefault(); mConfiguration.setLayoutDirection(mConfiguration.locale); @@ -1891,7 +1889,8 @@ public class Resources { if (mConfiguration.locale != null) { locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag()); } - int width, height; + + final int width, height; if (mMetrics.widthPixels >= mMetrics.heightPixels) { width = mMetrics.widthPixels; height = mMetrics.heightPixels; @@ -1901,12 +1900,15 @@ public class Resources { //noinspection SuspiciousNameCombination height = mMetrics.widthPixels; } - int keyboardHidden = mConfiguration.keyboardHidden; - if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO - && mConfiguration.hardKeyboardHidden - == Configuration.HARDKEYBOARDHIDDEN_YES) { + + final int keyboardHidden; + if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO + && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; + } else { + keyboardHidden = mConfiguration.keyboardHidden; } + mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, locale, mConfiguration.orientation, mConfiguration.touchscreen, @@ -2508,10 +2510,10 @@ public class Resources { // Clean out the caches before we add more. This shouldn't // happen very often. pruneCaches(caches); - themedCache = new LongSparseArray<WeakReference<ConstantState>>(1); + themedCache = new LongSparseArray<>(1); caches.put(themeKey, themedCache); } - themedCache.put(key, new WeakReference<ConstantState>(cs)); + themedCache.put(key, new WeakReference<>(cs)); } } } @@ -2830,15 +2832,6 @@ public class Resources { + Integer.toHexString(id)); } - /*package*/ void recycleCachedStyledAttributes(TypedArray attrs) { - synchronized (mAccessLock) { - final TypedArray cached = mCachedStyledAttributes; - if (cached == null || cached.mData.length < attrs.mData.length) { - mCachedStyledAttributes = attrs; - } - } - } - /** * Obtains styled attributes from the theme, if available, or unstyled * resources if the theme is null. diff --git a/core/java/android/database/DatabaseErrorHandler.java b/core/java/android/database/DatabaseErrorHandler.java index f0c5452..55ad921 100644 --- a/core/java/android/database/DatabaseErrorHandler.java +++ b/core/java/android/database/DatabaseErrorHandler.java @@ -19,13 +19,12 @@ package android.database; import android.database.sqlite.SQLiteDatabase; /** - * An interface to let the apps define the actions to take when the following errors are detected - * database corruption + * An interface to let apps define an action to take when database corruption is detected. */ public interface DatabaseErrorHandler { /** - * defines the method to be invoked when database corruption is detected. + * The method invoked when database corruption is detected. * @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption * is detected. */ diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java index b234e34..7fa2b40 100755 --- a/core/java/android/database/DefaultDatabaseErrorHandler.java +++ b/core/java/android/database/DefaultDatabaseErrorHandler.java @@ -24,7 +24,7 @@ import android.util.Log; import android.util.Pair; /** - * Default class used to define the actions to take when the database corruption is reported + * Default class used to define the action to take when database corruption is reported * by sqlite. * <p> * An application can specify an implementation of {@link DatabaseErrorHandler} on the @@ -38,7 +38,7 @@ import android.util.Pair; * The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they * occur. * <p> - * If null is specified for DatabaeErrorHandler param in the above calls, then this class is used + * If null is specified for the DatabaseErrorHandler param in the above calls, this class is used * as the default {@link DatabaseErrorHandler}. */ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index a6c3ea4..88fa339 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -54,11 +54,13 @@ public class SystemSensorManager extends SensorManager { // Looper associated with the context in which this instance was created. private final Looper mMainLooper; private final int mTargetSdkLevel; + private final String mPackageName; /** {@hide} */ public SystemSensorManager(Context context, Looper mainLooper) { mMainLooper = mainLooper; mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion; + mPackageName = context.getPackageName(); synchronized(sSensorModuleLock) { if (!sSensorModuleInitialized) { sSensorModuleInitialized = true; @@ -117,14 +119,14 @@ public class SystemSensorManager extends SensorManager { if (queue == null) { Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; queue = new SensorEventQueue(listener, looper, this); - if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) { + if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { queue.dispose(); return false; } mSensorListeners.put(listener, queue); return true; } else { - return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags); + return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs); } } } @@ -165,14 +167,14 @@ public class SystemSensorManager extends SensorManager { TriggerEventQueue queue = mTriggerListeners.get(listener); if (queue == null) { queue = new TriggerEventQueue(listener, mMainLooper, this); - if (!queue.addSensor(sensor, 0, 0, 0)) { + if (!queue.addSensor(sensor, 0, 0)) { queue.dispose(); return false; } mTriggerListeners.put(listener, queue); return true; } else { - return queue.addSensor(sensor, 0, 0, 0); + return queue.addSensor(sensor, 0, 0); } } } @@ -223,9 +225,9 @@ public class SystemSensorManager extends SensorManager { */ private static abstract class BaseEventQueue { private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ, - float[] scratch); + float[] scratch, String packageName); private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, - int maxBatchReportLatencyUs, int reservedFlags); + int maxBatchReportLatencyUs); private static native int nativeDisableSensor(long eventQ, int handle); private static native void nativeDestroySensorEventQueue(long eventQ); private static native int nativeFlushSensor(long eventQ); @@ -238,7 +240,8 @@ public class SystemSensorManager extends SensorManager { protected final SystemSensorManager mManager; BaseEventQueue(Looper looper, SystemSensorManager manager) { - nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch); + nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch, + manager.mPackageName); mCloseGuard.open("dispose"); mManager = manager; } @@ -248,7 +251,7 @@ public class SystemSensorManager extends SensorManager { } public boolean addSensor( - Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) { + Sensor sensor, int delayUs, int maxBatchReportLatencyUs) { // Check if already present. int handle = sensor.getHandle(); if (mActiveSensors.get(handle)) return false; @@ -256,10 +259,10 @@ public class SystemSensorManager extends SensorManager { // Get ready to receive events before calling enable. mActiveSensors.put(handle, true); addSensorEvent(sensor); - if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) { + if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) { // Try continuous mode if batching fails. if (maxBatchReportLatencyUs == 0 || - maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) { + maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) { removeSensor(sensor, false); return false; } @@ -328,11 +331,11 @@ public class SystemSensorManager extends SensorManager { } private int enableSensor( - Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) { + Sensor sensor, int rateUs, int maxBatchReportLatencyUs) { if (nSensorEventQueue == 0) throw new NullPointerException(); if (sensor == null) throw new NullPointerException(); return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs, - maxBatchReportLatencyUs, reservedFlags); + maxBatchReportLatencyUs); } private int disableSensor(Sensor sensor) { diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 7569ea5..b8fb8e7 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1541,7 +1541,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * to the camera, that the JPEG picture needs to be rotated by, to be viewed * upright.</p> * <p>Camera devices may either encode this value into the JPEG EXIF header, or - * rotate the image data to match this orientation.</p> + * rotate the image data to match this orientation. When the image data is rotated, + * the thumbnail data will also be rotated.</p> * <p>Note that this orientation is relative to the orientation of the camera sensor, given * by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p> * <p>To translate from the device orientation given by the Android sensor APIs, the following diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index b84dc2e..e346dc2 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2230,7 +2230,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * to the camera, that the JPEG picture needs to be rotated by, to be viewed * upright.</p> * <p>Camera devices may either encode this value into the JPEG EXIF header, or - * rotate the image data to match this orientation.</p> + * rotate the image data to match this orientation. When the image data is rotated, + * the thumbnail data will also be rotated.</p> * <p>Note that this orientation is relative to the orientation of the camera sensor, given * by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p> * <p>To translate from the device orientation given by the Android sensor APIs, the following diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0766253..77d7e0c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -50,12 +50,19 @@ public class NetworkStats implements Parcelable { public static final int UID_ALL = -1; /** {@link #tag} value matching any tag. */ public static final int TAG_ALL = -1; - /** {@link #set} value when all sets combined. */ + /** {@link #set} value when all sets combined, not including debug sets. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; /** {@link #set} value where foreground data is accounted. */ public static final int SET_FOREGROUND = 1; + /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */ + public static final int SET_DEBUG_START = 1000; + /** Debug {@link #set} value when the VPN stats are moved in. */ + public static final int SET_DBG_VPN_IN = 1001; + /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ + public static final int SET_DBG_VPN_OUT = 1002; + /** {@link #tag} value for total data across all tags. */ public static final int TAG_NONE = 0; @@ -729,6 +736,10 @@ public class NetworkStats implements Parcelable { return "DEFAULT"; case SET_FOREGROUND: return "FOREGROUND"; + case SET_DBG_VPN_IN: + return "DBG_VPN_IN"; + case SET_DBG_VPN_OUT: + return "DBG_VPN_OUT"; default: return "UNKNOWN"; } @@ -745,12 +756,27 @@ public class NetworkStats implements Parcelable { return "def"; case SET_FOREGROUND: return "fg"; + case SET_DBG_VPN_IN: + return "vpnin"; + case SET_DBG_VPN_OUT: + return "vpnout"; default: return "unk"; } } /** + * @return true if the querySet matches the dataSet. + */ + public static boolean setMatches(int querySet, int dataSet) { + if (querySet == dataSet) { + return true; + } + // SET_ALL matches all non-debugging sets. + return querySet == SET_ALL && dataSet < SET_DEBUG_START; + } + + /** * Return text description of {@link #tag} value. */ public static String tagToString(int tag) { @@ -843,6 +869,9 @@ public class NetworkStats implements Parcelable { if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); + } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + throw new IllegalStateException( + "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } if (recycle.uid == tunUid && recycle.tag == TAG_NONE @@ -906,6 +935,9 @@ public class NetworkStats implements Parcelable { combineValues(tmpEntry); if (tag[i] == TAG_NONE) { moved.add(tmpEntry); + // Add debug info + tmpEntry.set = SET_DBG_VPN_IN; + combineValues(tmpEntry); } } } @@ -913,6 +945,13 @@ public class NetworkStats implements Parcelable { } private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { + // Add debug info + moved.uid = tunUid; + moved.set = SET_DBG_VPN_OUT; + moved.tag = TAG_NONE; + moved.iface = underlyingIface; + combineValues(moved); + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 26e6b85..8b3ecae 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.telephony.SignalStrength; import android.text.format.DateFormat; +import android.util.ArrayMap; import android.util.Printer; import android.util.SparseArray; import android.util.SparseIntArray; @@ -283,21 +284,21 @@ public abstract class BatteryStats implements Parcelable { * * @return a Map from Strings to Uid.Wakelock objects. */ - public abstract Map<String, ? extends Wakelock> getWakelockStats(); + public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats(); /** * Returns a mapping containing sync statistics. * * @return a Map from Strings to Timer objects. */ - public abstract Map<String, ? extends Timer> getSyncStats(); + public abstract ArrayMap<String, ? extends Timer> getSyncStats(); /** * Returns a mapping containing scheduled job statistics. * * @return a Map from Strings to Timer objects. */ - public abstract Map<String, ? extends Timer> getJobStats(); + public abstract ArrayMap<String, ? extends Timer> getJobStats(); /** * The statistics associated with a particular wake lock. @@ -323,14 +324,14 @@ public abstract class BatteryStats implements Parcelable { * * @return a Map from Strings to Uid.Proc objects. */ - public abstract Map<String, ? extends Proc> getProcessStats(); + public abstract ArrayMap<String, ? extends Proc> getProcessStats(); /** * Returns a mapping containing package statistics. * * @return a Map from Strings to Uid.Pkg objects. */ - public abstract Map<String, ? extends Pkg> getPackageStats(); + public abstract ArrayMap<String, ? extends Pkg> getPackageStats(); /** * {@hide} @@ -501,17 +502,16 @@ public abstract class BatteryStats implements Parcelable { public static abstract class Pkg { /** - * Returns the number of times this package has done something that could wake up the - * device from sleep. - * - * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. + * Returns information about all wakeup alarms that have been triggered for this + * package. The mapping keys are tag names for the alarms, the counter contains + * the number of times the alarm was triggered while on battery. */ - public abstract int getWakeups(int which); + public abstract ArrayMap<String, ? extends Counter> getWakeupAlarmStats(); /** * Returns a mapping containing service statistics. */ - public abstract Map<String, ? extends Serv> getServiceStats(); + public abstract ArrayMap<String, ? extends Serv> getServiceStats(); /** * The statistics associated with a particular service. @@ -1352,7 +1352,7 @@ public abstract class BatteryStats implements Parcelable { int idx = code&HistoryItem.EVENT_TYPE_MASK; HashMap<String, SparseIntArray> active = mActiveEvents[idx]; if (active == null) { - active = new HashMap<String, SparseIntArray>(); + active = new HashMap<>(); mActiveEvents[idx] = active; } SparseIntArray uids = active.get(name); @@ -2382,12 +2382,12 @@ public abstract class BatteryStats implements Parcelable { final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which); final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which); - StringBuilder sb = new StringBuilder(128); + final StringBuilder sb = new StringBuilder(128); - SparseArray<? extends Uid> uidStats = getUidStats(); + final SparseArray<? extends Uid> uidStats = getUidStats(); final int NU = uidStats.size(); - String category = STAT_NAMES[which]; + final String category = STAT_NAMES[which]; // Dump "battery" stat dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, @@ -2402,37 +2402,35 @@ public abstract class BatteryStats implements Parcelable { long partialWakeLockTimeTotal = 0; for (int iu = 0; iu < NU; iu++) { - Uid u = uidStats.valueAt(iu); - - Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent - : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - - Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); - if (fullWakeTimer != null) { - fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime, - which); - } + final Uid u = uidStats.valueAt(iu); - Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); - if (partialWakeTimer != null) { - partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( - rawRealtime, which); - } + final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks + = u.getWakelockStats(); + for (int iw=wakelocks.size()-1; iw>=0; iw--) { + final Uid.Wakelock wl = wakelocks.valueAt(iw); + + final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); + if (fullWakeTimer != null) { + fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime, + which); + } + + final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); + if (partialWakeTimer != null) { + partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked( + rawRealtime, which); } } } - long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); + final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); + final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); + final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); + final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); + final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); // Dump network stats dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA, @@ -2544,7 +2542,7 @@ public abstract class BatteryStats implements Parcelable { } if (reqUid < 0) { - Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats(); + final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats(); if (kernelWakelocks.size() > 0) { for (Map.Entry<String, ? extends Timer> ent : kernelWakelocks.entrySet()) { sb.setLength(0); @@ -2553,7 +2551,7 @@ public abstract class BatteryStats implements Parcelable { sb.toString()); } } - Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats(); + final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats(); if (wakeupReasons.size() > 0) { for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) { // Not doing the regular wake lock formatting to remain compatible @@ -2566,10 +2564,10 @@ public abstract class BatteryStats implements Parcelable { } } - BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); + final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); helper.create(this); helper.refreshStats(which, UserHandle.USER_ALL); - List<BatterySipper> sippers = helper.getUsageList(); + final List<BatterySipper> sippers = helper.getUsageList(); if (sippers != null && sippers.size() > 0) { dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA, BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()), @@ -2577,7 +2575,7 @@ public abstract class BatteryStats implements Parcelable { BatteryStatsHelper.makemAh(helper.getMinDrainedPower()), BatteryStatsHelper.makemAh(helper.getMaxDrainedPower())); for (int i=0; i<sippers.size(); i++) { - BatterySipper bs = sippers.get(i); + final BatterySipper bs = sippers.get(i); int uid = 0; String label; switch (bs.drainType) { @@ -2629,22 +2627,22 @@ public abstract class BatteryStats implements Parcelable { if (reqUid >= 0 && uid != reqUid) { continue; } - Uid u = uidStats.valueAt(iu); + final Uid u = uidStats.valueAt(iu); // Dump Network stats per uid, if any - long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long mobileActiveTime = u.getMobileRadioActiveTime(which); - int mobileActiveCount = u.getMobileRadioActiveCount(which); - long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); - long wifiScanTime = u.getWifiScanTime(rawRealtime, which); - int wifiScanCount = u.getWifiScanCount(which); - long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); + final long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); + final long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); + final long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); + final long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); + final long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); + final long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + final long mobileActiveTime = u.getMobileRadioActiveTime(which); + final int mobileActiveCount = u.getMobileRadioActiveCount(which); + final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); + final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); + final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); + final long wifiScanTime = u.getWifiScanTime(rawRealtime, which); + final int wifiScanCount = u.getWifiScanCount(which); + final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0 || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0 @@ -2675,93 +2673,90 @@ public abstract class BatteryStats implements Parcelable { } } - Map<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - String linePrefix = ""; - sb.setLength(0); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), - rawRealtime, "f", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), - rawRealtime, "p", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), - rawRealtime, "w", which, linePrefix); - - // Only log if we had at lease one wakelock... - if (sb.length() > 0) { - String name = ent.getKey(); - if (name.indexOf(',') >= 0) { - name = name.replace(',', '_'); - } - dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString()); + final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats(); + for (int iw=wakelocks.size()-1; iw>=0; iw--) { + final Uid.Wakelock wl = wakelocks.valueAt(iw); + String linePrefix = ""; + sb.setLength(0); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), + rawRealtime, "f", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), + rawRealtime, "p", which, linePrefix); + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), + rawRealtime, "w", which, linePrefix); + + // Only log if we had at lease one wakelock... + if (sb.length() > 0) { + String name = wakelocks.keyAt(iw); + if (name.indexOf(',') >= 0) { + name = name.replace(',', '_'); } + dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString()); } } - Map<String, ? extends Timer> syncs = u.getSyncStats(); - if (syncs.size() > 0) { - for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count); - } + final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats(); + for (int isy=syncs.size()-1; isy>=0; isy--) { + final Timer timer = syncs.valueAt(isy); + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + final int count = timer.getCountLocked(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, SYNC_DATA, syncs.keyAt(isy), totalTime, count); } } - Map<String, ? extends Timer> jobs = u.getJobStats(); - if (jobs.size() > 0) { - for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count); - } + final ArrayMap<String, ? extends Timer> jobs = u.getJobStats(); + for (int ij=jobs.size()-1; ij>=0; ij--) { + final Timer timer = jobs.valueAt(ij); + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + final int count = timer.getCountLocked(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, JOB_DATA, jobs.keyAt(ij), totalTime, count); } } - SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); - int NSE = sensors.size(); + final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); + final int NSE = sensors.size(); for (int ise=0; ise<NSE; ise++) { - Uid.Sensor se = sensors.valueAt(ise); - int sensorNumber = sensors.keyAt(ise); - Timer timer = se.getSensorTime(); + final Uid.Sensor se = sensors.valueAt(ise); + final int sensorNumber = sensors.keyAt(ise); + final Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) + / 1000; + final int count = timer.getCountLocked(which); if (totalTime != 0) { dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); } } } - Timer vibTimer = u.getVibratorOnTimer(); + final Timer vibTimer = u.getVibratorOnTimer(); if (vibTimer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = vibTimer.getCountLocked(which); + final long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) + / 1000; + final int count = vibTimer.getCountLocked(which); if (totalTime != 0) { dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count); } } - Timer fgTimer = u.getForegroundActivityTimer(); + final Timer fgTimer = u.getForegroundActivityTimer(); if (fgTimer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = fgTimer.getCountLocked(which); + final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) + / 1000; + final int count = fgTimer.getCountLocked(which); if (totalTime != 0) { dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count); } } - Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE]; + final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE]; long totalStateTime = 0; for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) { totalStateTime += u.getProcessStateTime(ips, rawRealtime, which); @@ -2771,50 +2766,48 @@ public abstract class BatteryStats implements Parcelable { dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes); } - Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); - if (processStats.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent - : processStats.entrySet()) { - Uid.Proc ps = ent.getValue(); - - final long userMillis = ps.getUserTime(which); - final long systemMillis = ps.getSystemTime(which); - final long foregroundMillis = ps.getForegroundTime(which); - final int starts = ps.getStarts(which); - final int numCrashes = ps.getNumCrashes(which); - final int numAnrs = ps.getNumAnrs(which); - - if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0 - || starts != 0 || numAnrs != 0 || numCrashes != 0) { - dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis, - systemMillis, foregroundMillis, starts, numAnrs, numCrashes); - } + final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats + = u.getProcessStats(); + for (int ipr=processStats.size()-1; ipr>=0; ipr--) { + final Uid.Proc ps = processStats.valueAt(ipr); + + final long userMillis = ps.getUserTime(which); + final long systemMillis = ps.getSystemTime(which); + final long foregroundMillis = ps.getForegroundTime(which); + final int starts = ps.getStarts(which); + final int numCrashes = ps.getNumCrashes(which); + final int numAnrs = ps.getNumAnrs(which); + + if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0 + || starts != 0 || numAnrs != 0 || numCrashes != 0) { + dumpLine(pw, uid, category, PROCESS_DATA, processStats.keyAt(ipr), userMillis, + systemMillis, foregroundMillis, starts, numAnrs, numCrashes); } } - Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats(); - if (packageStats.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent - : packageStats.entrySet()) { - - Uid.Pkg ps = ent.getValue(); - int wakeups = ps.getWakeups(which); - Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); - for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent - : serviceStats.entrySet()) { - BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); - int starts = ss.getStarts(which); - int launches = ss.getLaunches(which); - if (startTime != 0 || starts != 0 || launches != 0) { - dumpLine(pw, uid, category, APK_DATA, - wakeups, // wakeup alarms - ent.getKey(), // Apk - sent.getKey(), // service - startTime / 1000, // time spent started, in ms - starts, - launches); - } + final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats + = u.getPackageStats(); + for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) { + final Uid.Pkg ps = packageStats.valueAt(ipkg); + int wakeups = 0; + final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats(); + for (int iwa=alarms.size()-1; iwa>=0; iwa--) { + wakeups += alarms.valueAt(iwa).getCountLocked(which); + } + final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); + for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) { + final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc); + final long startTime = ss.getStartTime(batteryUptime, which); + final int starts = ss.getStarts(which); + final int launches = ss.getLaunches(which); + if (startTime != 0 || starts != 0 || launches != 0) { + dumpLine(pw, uid, category, APK_DATA, + wakeups, // wakeup alarms + packageStats.keyAt(ipkg), // Apk + serviceStats.keyAt(isvc), // service + startTime / 1000, // time spent started, in ms + starts, + launches); } } } @@ -2863,9 +2856,9 @@ public abstract class BatteryStats implements Parcelable { final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime); final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime); - StringBuilder sb = new StringBuilder(128); + final StringBuilder sb = new StringBuilder(128); - SparseArray<? extends Uid> uidStats = getUidStats(); + final SparseArray<? extends Uid> uidStats = getUidStats(); final int NU = uidStats.size(); sb.setLength(0); @@ -2992,7 +2985,7 @@ public abstract class BatteryStats implements Parcelable { sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime)); sb.append(") "); sb.append(getPhoneOnCount(which)); sb.append("x"); } - int connChanges = getNumConnectivityChange(which); + final int connChanges = getNumConnectivityChange(which); if (connChanges != 0) { pw.print(prefix); pw.print(" Connectivity changes: "); pw.println(connChanges); @@ -3002,50 +2995,48 @@ public abstract class BatteryStats implements Parcelable { long fullWakeLockTimeTotalMicros = 0; long partialWakeLockTimeTotalMicros = 0; - final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>(); + final ArrayList<TimerEntry> timers = new ArrayList<>(); for (int iu = 0; iu < NU; iu++) { - Uid u = uidStats.valueAt(iu); - - Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent - : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - - Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); - if (fullWakeTimer != null) { - fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( - rawRealtime, which); - } + final Uid u = uidStats.valueAt(iu); - Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); - if (partialWakeTimer != null) { - long totalTimeMicros = partialWakeTimer.getTotalTimeLocked( - rawRealtime, which); - if (totalTimeMicros > 0) { - if (reqUid < 0) { - // Only show the ordered list of all wake - // locks if the caller is not asking for data - // about a specific uid. - timers.add(new TimerEntry(ent.getKey(), u.getUid(), - partialWakeTimer, totalTimeMicros)); - } - partialWakeLockTimeTotalMicros += totalTimeMicros; + final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks + = u.getWakelockStats(); + for (int iw=wakelocks.size()-1; iw>=0; iw--) { + final Uid.Wakelock wl = wakelocks.valueAt(iw); + + final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL); + if (fullWakeTimer != null) { + fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked( + rawRealtime, which); + } + + final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL); + if (partialWakeTimer != null) { + final long totalTimeMicros = partialWakeTimer.getTotalTimeLocked( + rawRealtime, which); + if (totalTimeMicros > 0) { + if (reqUid < 0) { + // Only show the ordered list of all wake + // locks if the caller is not asking for data + // about a specific uid. + timers.add(new TimerEntry(wakelocks.keyAt(iw), u.getUid(), + partialWakeTimer, totalTimeMicros)); } + partialWakeLockTimeTotalMicros += totalTimeMicros; } } } } - long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); + final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); + final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); + final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); + final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); + final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); if (fullWakeLockTimeTotalMicros != 0) { sb.setLength(0); @@ -3242,9 +3233,9 @@ public abstract class BatteryStats implements Parcelable { if (!didOne) sb.append(" (no activity)"); pw.println(sb.toString()); - final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which); - final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which); - final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which); + final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which); + final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which); + final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which); final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs; sb.setLength(0); @@ -3367,7 +3358,7 @@ public abstract class BatteryStats implements Parcelable { pw.println(); } - BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); + final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); helper.create(this); helper.refreshStats(which, UserHandle.USER_ALL); List<BatterySipper> sippers = helper.getUsageList(); @@ -3382,7 +3373,7 @@ public abstract class BatteryStats implements Parcelable { } pw.println(); for (int i=0; i<sippers.size(); i++) { - BatterySipper bs = sippers.get(i); + final BatterySipper bs = sippers.get(i); switch (bs.drainType) { case IDLE: pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.value); @@ -3439,7 +3430,7 @@ public abstract class BatteryStats implements Parcelable { pw.print(prefix); pw.println(" Per-app mobile ms per packet:"); long totalTime = 0; for (int i=0; i<sippers.size(); i++) { - BatterySipper bs = sippers.get(i); + final BatterySipper bs = sippers.get(i); sb.setLength(0); sb.append(prefix); sb.append(" Uid "); UserHandle.formatUid(sb, bs.uidObj.getUid()); @@ -3476,12 +3467,14 @@ public abstract class BatteryStats implements Parcelable { }; if (reqUid < 0) { - Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); + final Map<String, ? extends BatteryStats.Timer> kernelWakelocks + = getKernelWakelockStats(); if (kernelWakelocks.size() > 0) { - final ArrayList<TimerEntry> ktimers = new ArrayList<TimerEntry>(); - for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { - BatteryStats.Timer timer = ent.getValue(); - long totalTimeMillis = computeWakeLock(timer, rawRealtime, which); + final ArrayList<TimerEntry> ktimers = new ArrayList<>(); + for (Map.Entry<String, ? extends BatteryStats.Timer> ent + : kernelWakelocks.entrySet()) { + final BatteryStats.Timer timer = ent.getValue(); + final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which); if (totalTimeMillis > 0) { ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis)); } @@ -3490,7 +3483,7 @@ public abstract class BatteryStats implements Parcelable { Collections.sort(ktimers, timerComparator); pw.print(prefix); pw.println(" All kernel wake locks:"); for (int i=0; i<ktimers.size(); i++) { - TimerEntry timer = ktimers.get(i); + final TimerEntry timer = ktimers.get(i); String linePrefix = ": "; sb.setLength(0); sb.append(prefix); @@ -3526,12 +3519,12 @@ public abstract class BatteryStats implements Parcelable { pw.println(); } - Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats(); + final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats(); if (wakeupReasons.size() > 0) { pw.print(prefix); pw.println(" All wakeup reasons:"); - final ArrayList<TimerEntry> reasons = new ArrayList<TimerEntry>(); + final ArrayList<TimerEntry> reasons = new ArrayList<>(); for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) { - Timer timer = ent.getValue(); + final Timer timer = ent.getValue(); reasons.add(new TimerEntry(ent.getKey(), 0, timer, timer.getCountLocked(which))); } @@ -3557,7 +3550,7 @@ public abstract class BatteryStats implements Parcelable { continue; } - Uid u = uidStats.valueAt(iu); + final Uid u = uidStats.valueAt(iu); pw.print(prefix); pw.print(" "); @@ -3565,20 +3558,20 @@ public abstract class BatteryStats implements Parcelable { pw.println(":"); boolean uidActivity = false; - long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); - long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); - long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); - long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); - long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); - long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); - long uidMobileActiveTime = u.getMobileRadioActiveTime(which); - int uidMobileActiveCount = u.getMobileRadioActiveCount(which); - long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); - long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); - long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); - long wifiScanTime = u.getWifiScanTime(rawRealtime, which); - int wifiScanCount = u.getWifiScanCount(which); - long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); + final long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which); + final long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which); + final long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which); + final long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which); + final long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which); + final long uidMobileActiveTime = u.getMobileRadioActiveTime(which); + final int uidMobileActiveCount = u.getMobileRadioActiveCount(which); + final long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which); + final long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which); + final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which); + final long wifiScanTime = u.getWifiScanTime(rawRealtime, which); + final int wifiScanCount = u.getWifiScanCount(which); + final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which); if (mobileRxBytes > 0 || mobileTxBytes > 0 || mobileRxPackets > 0 || mobileTxPackets > 0) { @@ -3636,7 +3629,7 @@ public abstract class BatteryStats implements Parcelable { if (u.hasUserActivity()) { boolean hasData = false; for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) { - int val = u.getUserActivityCount(i, which); + final int val = u.getUserActivityCount(i, which); if (val != 0) { if (!hasData) { sb.setLength(0); @@ -3655,125 +3648,121 @@ public abstract class BatteryStats implements Parcelable { } } - Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats(); - if (wakelocks.size() > 0) { - long totalFull = 0, totalPartial = 0, totalWindow = 0; - int count = 0; - for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) { - Uid.Wakelock wl = ent.getValue(); - String linePrefix = ": "; + final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks + = u.getWakelockStats(); + long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0; + int countWakelock = 0; + for (int iw=wakelocks.size()-1; iw>=0; iw--) { + final Uid.Wakelock wl = wakelocks.valueAt(iw); + String linePrefix = ": "; + sb.setLength(0); + sb.append(prefix); + sb.append(" Wake lock "); + sb.append(wakelocks.keyAt(iw)); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime, + "full", which, linePrefix); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime, + "partial", which, linePrefix); + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime, + "window", which, linePrefix); + if (true || !linePrefix.equals(": ")) { + sb.append(" realtime"); + // Only print out wake locks that were held + pw.println(sb.toString()); + uidActivity = true; + countWakelock++; + } + totalFullWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL), + rawRealtime, which); + totalPartialWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL), + rawRealtime, which); + totalWindowWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW), + rawRealtime, which); + } + if (countWakelock > 1) { + if (totalFullWakelock != 0 || totalPartialWakelock != 0 + || totalWindowWakelock != 0) { sb.setLength(0); sb.append(prefix); - sb.append(" Wake lock "); - sb.append(ent.getKey()); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime, - "full", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime, - "partial", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime, - "window", which, linePrefix); - if (true || !linePrefix.equals(": ")) { - sb.append(" realtime"); - // Only print out wake locks that were held - pw.println(sb.toString()); - uidActivity = true; - count++; + sb.append(" TOTAL wake: "); + boolean needComma = false; + if (totalFullWakelock != 0) { + needComma = true; + formatTimeMs(sb, totalFullWakelock); + sb.append("full"); } - totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL), - rawRealtime, which); - totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL), - rawRealtime, which); - totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW), - rawRealtime, which); - } - if (count > 1) { - if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" TOTAL wake: "); - boolean needComma = false; - if (totalFull != 0) { - needComma = true; - formatTimeMs(sb, totalFull); - sb.append("full"); - } - if (totalPartial != 0) { - if (needComma) { - sb.append(", "); - } - needComma = true; - formatTimeMs(sb, totalPartial); - sb.append("partial"); + if (totalPartialWakelock != 0) { + if (needComma) { + sb.append(", "); } - if (totalWindow != 0) { - if (needComma) { - sb.append(", "); - } - needComma = true; - formatTimeMs(sb, totalWindow); - sb.append("window"); + needComma = true; + formatTimeMs(sb, totalPartialWakelock); + sb.append("partial"); + } + if (totalWindowWakelock != 0) { + if (needComma) { + sb.append(", "); } - sb.append(" realtime"); - pw.println(sb.toString()); + needComma = true; + formatTimeMs(sb, totalWindowWakelock); + sb.append("window"); } + sb.append(" realtime"); + pw.println(sb.toString()); } } - Map<String, ? extends Timer> syncs = u.getSyncStats(); - if (syncs.size() > 0) { - for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - sb.setLength(0); - sb.append(prefix); - sb.append(" Sync "); - sb.append(ent.getKey()); - sb.append(": "); - if (totalTime != 0) { - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - } else { - sb.append("(not used)"); - } - pw.println(sb.toString()); - uidActivity = true; + final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats(); + for (int isy=syncs.size()-1; isy>=0; isy--) { + final Timer timer = syncs.valueAt(isy); + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + final int count = timer.getCountLocked(which); + sb.setLength(0); + sb.append(prefix); + sb.append(" Sync "); + sb.append(syncs.keyAt(isy)); + sb.append(": "); + if (totalTime != 0) { + formatTimeMs(sb, totalTime); + sb.append("realtime ("); + sb.append(count); + sb.append(" times)"); + } else { + sb.append("(not used)"); } + pw.println(sb.toString()); + uidActivity = true; } - Map<String, ? extends Timer> jobs = u.getJobStats(); - if (jobs.size() > 0) { - for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) { - Timer timer = ent.getValue(); - // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); - sb.setLength(0); - sb.append(prefix); - sb.append(" Job "); - sb.append(ent.getKey()); - sb.append(": "); - if (totalTime != 0) { - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - } else { - sb.append("(not used)"); - } - pw.println(sb.toString()); - uidActivity = true; + final ArrayMap<String, ? extends Timer> jobs = u.getJobStats(); + for (int ij=jobs.size()-1; ij>=0; ij--) { + final Timer timer = jobs.valueAt(ij); + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; + final int count = timer.getCountLocked(which); + sb.setLength(0); + sb.append(prefix); + sb.append(" Job "); + sb.append(jobs.keyAt(ij)); + sb.append(": "); + if (totalTime != 0) { + formatTimeMs(sb, totalTime); + sb.append("realtime ("); + sb.append(count); + sb.append(" times)"); + } else { + sb.append("(not used)"); } + pw.println(sb.toString()); + uidActivity = true; } - SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); - int NSE = sensors.size(); + final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); + final int NSE = sensors.size(); for (int ise=0; ise<NSE; ise++) { - Uid.Sensor se = sensors.valueAt(ise); - int sensorNumber = sensors.keyAt(ise); + final Uid.Sensor se = sensors.valueAt(ise); + final int sensorNumber = sensors.keyAt(ise); sb.setLength(0); sb.append(prefix); sb.append(" Sensor "); @@ -3785,12 +3774,12 @@ public abstract class BatteryStats implements Parcelable { } sb.append(": "); - Timer timer = se.getSensorTime(); + final Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTimeLocked( + final long totalTime = (timer.getTotalTimeLocked( rawRealtime, which) + 500) / 1000; - int count = timer.getCountLocked(which); + final int count = timer.getCountLocked(which); //timer.logState(); if (totalTime != 0) { formatTimeMs(sb, totalTime); @@ -3808,12 +3797,12 @@ public abstract class BatteryStats implements Parcelable { uidActivity = true; } - Timer vibTimer = u.getVibratorOnTimer(); + final Timer vibTimer = u.getVibratorOnTimer(); if (vibTimer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (vibTimer.getTotalTimeLocked( + final long totalTime = (vibTimer.getTotalTimeLocked( rawRealtime, which) + 500) / 1000; - int count = vibTimer.getCountLocked(which); + final int count = vibTimer.getCountLocked(which); //timer.logState(); if (totalTime != 0) { sb.setLength(0); @@ -3828,11 +3817,12 @@ public abstract class BatteryStats implements Parcelable { } } - Timer fgTimer = u.getForegroundActivityTimer(); + final Timer fgTimer = u.getForegroundActivityTimer(); if (fgTimer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; - int count = fgTimer.getCountLocked(which); + final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) + / 1000; + final int count = fgTimer.getCountLocked(which); if (totalTime != 0) { sb.setLength(0); sb.append(prefix); @@ -3862,125 +3852,121 @@ public abstract class BatteryStats implements Parcelable { } } - Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats(); - if (processStats.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent - : processStats.entrySet()) { - Uid.Proc ps = ent.getValue(); - long userTime; - long systemTime; - long foregroundTime; - int starts; - int numExcessive; - - userTime = ps.getUserTime(which); - systemTime = ps.getSystemTime(which); - foregroundTime = ps.getForegroundTime(which); - starts = ps.getStarts(which); - final int numCrashes = ps.getNumCrashes(which); - final int numAnrs = ps.getNumAnrs(which); - numExcessive = which == STATS_SINCE_CHARGED - ? ps.countExcessivePowers() : 0; - - if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0 - || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Proc "); - sb.append(ent.getKey()); sb.append(":\n"); - sb.append(prefix); sb.append(" CPU: "); - formatTimeMs(sb, userTime); sb.append("usr + "); - formatTimeMs(sb, systemTime); sb.append("krn ; "); - formatTimeMs(sb, foregroundTime); sb.append("fg"); - if (starts != 0 || numCrashes != 0 || numAnrs != 0) { - sb.append("\n"); sb.append(prefix); sb.append(" "); - boolean hasOne = false; - if (starts != 0) { - hasOne = true; - sb.append(starts); sb.append(" starts"); - } - if (numCrashes != 0) { - if (hasOne) { - sb.append(", "); - } - hasOne = true; - sb.append(numCrashes); sb.append(" crashes"); - } - if (numAnrs != 0) { - if (hasOne) { - sb.append(", "); - } - sb.append(numAnrs); sb.append(" anrs"); + final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats + = u.getProcessStats(); + for (int ipr=processStats.size()-1; ipr>=0; ipr--) { + final Uid.Proc ps = processStats.valueAt(ipr); + long userTime; + long systemTime; + long foregroundTime; + int starts; + int numExcessive; + + userTime = ps.getUserTime(which); + systemTime = ps.getSystemTime(which); + foregroundTime = ps.getForegroundTime(which); + starts = ps.getStarts(which); + final int numCrashes = ps.getNumCrashes(which); + final int numAnrs = ps.getNumAnrs(which); + numExcessive = which == STATS_SINCE_CHARGED + ? ps.countExcessivePowers() : 0; + + if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0 + || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) { + sb.setLength(0); + sb.append(prefix); sb.append(" Proc "); + sb.append(processStats.keyAt(ipr)); sb.append(":\n"); + sb.append(prefix); sb.append(" CPU: "); + formatTimeMs(sb, userTime); sb.append("usr + "); + formatTimeMs(sb, systemTime); sb.append("krn ; "); + formatTimeMs(sb, foregroundTime); sb.append("fg"); + if (starts != 0 || numCrashes != 0 || numAnrs != 0) { + sb.append("\n"); sb.append(prefix); sb.append(" "); + boolean hasOne = false; + if (starts != 0) { + hasOne = true; + sb.append(starts); sb.append(" starts"); + } + if (numCrashes != 0) { + if (hasOne) { + sb.append(", "); } + hasOne = true; + sb.append(numCrashes); sb.append(" crashes"); } - pw.println(sb.toString()); - for (int e=0; e<numExcessive; e++) { - Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e); - if (ew != null) { - pw.print(prefix); pw.print(" * Killed for "); - if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) { - pw.print("wake lock"); - } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) { - pw.print("cpu"); - } else { - pw.print("unknown"); - } - pw.print(" use: "); - TimeUtils.formatDuration(ew.usedTime, pw); - pw.print(" over "); - TimeUtils.formatDuration(ew.overTime, pw); - if (ew.overTime != 0) { - pw.print(" ("); - pw.print((ew.usedTime*100)/ew.overTime); - pw.println("%)"); - } + if (numAnrs != 0) { + if (hasOne) { + sb.append(", "); } + sb.append(numAnrs); sb.append(" anrs"); } - uidActivity = true; } + pw.println(sb.toString()); + for (int e=0; e<numExcessive; e++) { + Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e); + if (ew != null) { + pw.print(prefix); pw.print(" * Killed for "); + if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) { + pw.print("wake lock"); + } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) { + pw.print("cpu"); + } else { + pw.print("unknown"); + } + pw.print(" use: "); + TimeUtils.formatDuration(ew.usedTime, pw); + pw.print(" over "); + TimeUtils.formatDuration(ew.overTime, pw); + if (ew.overTime != 0) { + pw.print(" ("); + pw.print((ew.usedTime*100)/ew.overTime); + pw.println("%)"); + } + } + } + uidActivity = true; } } - Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats(); - if (packageStats.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent - : packageStats.entrySet()) { - pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":"); - boolean apkActivity = false; - Uid.Pkg ps = ent.getValue(); - int wakeups = ps.getWakeups(which); - if (wakeups != 0) { - pw.print(prefix); pw.print(" "); - pw.print(wakeups); pw.println(" wakeup alarms"); + final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats + = u.getPackageStats(); + for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) { + pw.print(prefix); pw.print(" Apk "); pw.print(packageStats.keyAt(ipkg)); + pw.println(":"); + boolean apkActivity = false; + final Uid.Pkg ps = packageStats.valueAt(ipkg); + final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats(); + for (int iwa=alarms.size()-1; iwa>=0; iwa--) { + pw.print(prefix); pw.print(" Wakeup alarm "); + pw.print(alarms.keyAt(iwa)); pw.print(": "); + pw.print(alarms.valueAt(iwa).getCountLocked(which)); + pw.println(" times"); + apkActivity = true; + } + final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); + for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) { + final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc); + final long startTime = ss.getStartTime(batteryUptime, which); + final int starts = ss.getStarts(which); + final int launches = ss.getLaunches(which); + if (startTime != 0 || starts != 0 || launches != 0) { + sb.setLength(0); + sb.append(prefix); sb.append(" Service "); + sb.append(serviceStats.keyAt(isvc)); sb.append(":\n"); + sb.append(prefix); sb.append(" Created for: "); + formatTimeMs(sb, startTime / 1000); + sb.append("uptime\n"); + sb.append(prefix); sb.append(" Starts: "); + sb.append(starts); + sb.append(", launches: "); sb.append(launches); + pw.println(sb.toString()); apkActivity = true; } - Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats(); - if (serviceStats.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent - : serviceStats.entrySet()) { - BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); - int starts = ss.getStarts(which); - int launches = ss.getLaunches(which); - if (startTime != 0 || starts != 0 || launches != 0) { - sb.setLength(0); - sb.append(prefix); sb.append(" Service "); - sb.append(sent.getKey()); sb.append(":\n"); - sb.append(prefix); sb.append(" Created for: "); - formatTimeMs(sb, startTime / 1000); - sb.append("uptime\n"); - sb.append(prefix); sb.append(" Starts: "); - sb.append(starts); - sb.append(", launches: "); sb.append(launches); - pw.println(sb.toString()); - apkActivity = true; - } - } - } - if (!apkActivity) { - pw.print(prefix); pw.println(" (nothing executed)"); - } - uidActivity = true; } + if (!apkActivity) { + pw.print(prefix); pw.println(" (nothing executed)"); + } + uidActivity = true; } if (!uidActivity) { pw.print(prefix); pw.println(" (nothing executed)"); @@ -4498,7 +4484,6 @@ public abstract class BatteryStats implements Parcelable { return true; } - public static final int DUMP_UNPLUGGED_ONLY = 1<<0; public static final int DUMP_CHARGED_ONLY = 1<<1; public static final int DUMP_DAILY_ONLY = 1<<2; public static final int DUMP_HISTORY_ONLY = 1<<3; @@ -4647,7 +4632,7 @@ public abstract class BatteryStats implements Parcelable { prepareForDumpLocked(); final boolean filtering = (flags - & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0; + & (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0; if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) { final long historyTotalSize = getHistoryTotalSize(); @@ -4691,7 +4676,7 @@ public abstract class BatteryStats implements Parcelable { } } - if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) { + if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) { return; } @@ -4769,7 +4754,7 @@ public abstract class BatteryStats implements Parcelable { LevelStepTracker csteps = getDailyChargeLevelStepTracker(); ArrayList<PackageChange> pkgc = getDailyPackageChanges(); if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0 || pkgc != null) { - if ((flags&DUMP_DAILY_ONLY) != 0) { + if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) { if (dumpDurationSteps(pw, " ", " Current daily discharge step durations:", dsteps, false)) { dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps, @@ -4801,7 +4786,7 @@ public abstract class BatteryStats implements Parcelable { pw.print(" to "); pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString()); pw.println(":"); - if ((flags&DUMP_DAILY_ONLY) != 0) { + if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) { if (dumpDurationSteps(pw, " ", " Discharge step durations:", dit.mDischargeSteps, false)) { dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps, @@ -4830,11 +4815,6 @@ public abstract class BatteryStats implements Parcelable { (flags&DUMP_DEVICE_WIFI_ONLY) != 0); pw.println(); } - if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) { - pw.println("Statistics since last unplugged:"); - dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - } } @SuppressWarnings("unused") @@ -4848,7 +4828,7 @@ public abstract class BatteryStats implements Parcelable { long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); final boolean filtering = (flags & - (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0; + (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0; if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) { if (startIteratingHistoryLocked()) { @@ -4874,7 +4854,7 @@ public abstract class BatteryStats implements Parcelable { } } - if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) { + if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) { return; } @@ -4924,9 +4904,5 @@ public abstract class BatteryStats implements Parcelable { dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1, (flags&DUMP_DEVICE_WIFI_ONLY) != 0); } - if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) { - dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1, - (flags&DUMP_DEVICE_WIFI_ONLY) != 0); - } } } diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index f32e8cf..3b482eb 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -1438,7 +1438,7 @@ public class Preference implements Comparable<Preference> { protected boolean persistString(String value) { if (shouldPersist()) { // Shouldn't store null - if (value == getPersistedString(null)) { + if (TextUtils.equals(value, getPersistedString(null))) { // It's already there, so the same as persisting return true; } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 74b0a1c..e4a6f07 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -4809,6 +4809,14 @@ public final class ContactsContract { Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities"); /** + * The content:// style URI for this table in corp profile + * + * @hide + */ + public static final Uri CORP_CONTENT_URI = + Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities_corp"); + + /** * The content:// style URI for this table, specific to the user's profile. */ public static final Uri PROFILE_CONTENT_URI = diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index de536bd..fb51528 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5255,6 +5255,15 @@ public final class Settings { public static final String SMS_DEFAULT_APPLICATION = "sms_default_application"; /** + * Specifies the package name currently configured to be the emergency assistance application + * + * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE + * + * @hide + */ + public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application"; + + /** * Names of the packages that the current user has explicitly allowed to * see all of the user's notifications, separated by ':'. * diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl index ac6bbb7..14b5748 100644 --- a/core/java/android/security/IKeystoreService.aidl +++ b/core/java/android/security/IKeystoreService.aidl @@ -19,6 +19,7 @@ package android.security; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; +import android.security.keymaster.KeymasterBlob; import android.security.keymaster.OperationResult; import android.security.KeystoreArguments; @@ -59,15 +60,16 @@ interface IKeystoreService { // Keymaster 0.4 methods int addRngEntropy(in byte[] data); - int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags, + int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid, + int flags, out KeyCharacteristics characteristics); + int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId, out KeyCharacteristics characteristics); - int getKeyCharacteristics(String alias, in byte[] clientId, - in byte[] appId, out KeyCharacteristics characteristics); int importKey(String alias, in KeymasterArguments arguments, int format, in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics); - ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId); + ExportResult exportKey(String alias, int format, in KeymasterBlob clientId, + in KeymasterBlob appId); OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable, - in KeymasterArguments params, out KeymasterArguments operationParams); + in KeymasterArguments params, in byte[] entropy, out KeymasterArguments operationParams); OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input); OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature); int abort(IBinder handle); diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java index b26b10c..0b3bf45 100644 --- a/core/java/android/security/NetworkSecurityPolicy.java +++ b/core/java/android/security/NetworkSecurityPolicy.java @@ -24,15 +24,11 @@ package android.security; * * <p>The policy currently consists of a single flag: whether cleartext network traffic is * permitted. See {@link #isCleartextTrafficPermitted()}. - * - * @hide */ public class NetworkSecurityPolicy { private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy(); - private volatile boolean mCleartextTrafficPermitted = true; - private NetworkSecurityPolicy() {} /** @@ -50,9 +46,9 @@ public class NetworkSecurityPolicy { * without TLS or STARTTLS) is permitted for this process. * * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and - * FTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use - * cleartext traffic. Third-party libraries are strongly encouraged to honor this setting as - * well. + * FTP stacks, {@link android.webkit.WebView}, {@link android.media.MediaPlayer}) will refuse + * this process's requests to use cleartext traffic. Third-party libraries are strongly + * encouraged to honor this setting as well. * * <p>This flag is honored on a best effort basis because it's impossible to prevent all * cleartext traffic from Android applications given the level of access provided to them. For @@ -62,7 +58,7 @@ public class NetworkSecurityPolicy { * honor this aspect of the policy. */ public boolean isCleartextTrafficPermitted() { - return mCleartextTrafficPermitted; + return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted(); } /** @@ -74,6 +70,6 @@ public class NetworkSecurityPolicy { * @hide */ public void setCleartextTrafficPermitted(boolean permitted) { - mCleartextTrafficPermitted = permitted; + libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted); } } diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl new file mode 100644 index 0000000..8f70f7c --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBlob.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keymaster; + +/* @hide */ +parcelable KeymasterBlob; diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java new file mode 100644 index 0000000..cb95604 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBlob.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class KeymasterBlob implements Parcelable { + public byte[] blob; + + public KeymasterBlob(byte[] blob) { + this.blob = blob; + } + public static final Parcelable.Creator<KeymasterBlob> CREATOR = new + Parcelable.Creator<KeymasterBlob>() { + public KeymasterBlob createFromParcel(Parcel in) { + return new KeymasterBlob(in); + } + + public KeymasterBlob[] newArray(int length) { + return new KeymasterBlob[length]; + } + }; + + protected KeymasterBlob(Parcel in) { + blob = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeByteArray(blob); + } +} diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java index 9af4445..7d587bf 100644 --- a/core/java/android/security/keymaster/KeymasterBlobArgument.java +++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java @@ -26,6 +26,13 @@ class KeymasterBlobArgument extends KeymasterArgument { public KeymasterBlobArgument(int tag, byte[] blob) { super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_BIGNUM: + case KeymasterDefs.KM_BYTES: + break; // OK. + default: + throw new IllegalArgumentException("Bad blob tag " + tag); + } this.blob = blob; } diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java index 5481e8f..9c03674 100644 --- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java +++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java @@ -28,6 +28,12 @@ class KeymasterBooleanArgument extends KeymasterArgument { public KeymasterBooleanArgument(int tag) { super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_BOOL: + break; // OK. + default: + throw new IllegalArgumentException("Bad bool tag " + tag); + } } public KeymasterBooleanArgument(int tag, Parcel in) { diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java index 310f546..bffd24d 100644 --- a/core/java/android/security/keymaster/KeymasterDateArgument.java +++ b/core/java/android/security/keymaster/KeymasterDateArgument.java @@ -27,6 +27,12 @@ class KeymasterDateArgument extends KeymasterArgument { public KeymasterDateArgument(int tag, Date date) { super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_DATE: + break; // OK. + default: + throw new IllegalArgumentException("Bad date tag " + tag); + } this.date = date; } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index e653b74..c2ebbc6 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -16,6 +16,9 @@ package android.security.keymaster; +import java.util.HashMap; +import java.util.Map; + /** * Class tracking all the keymaster enum values needed for the binder API to keystore. * This must be kept in sync with hardware/libhardware/include/hardware/keymaster_defs.h @@ -224,7 +227,53 @@ public final class KeymasterDefs { public static final int KM_ERROR_VERSION_MISMATCH = -101; public static final int KM_ERROR_UNKNOWN_ERROR = -1000; + public static final Map<Integer, String> sErrorCodeToString = new HashMap<Integer, String>(); + static { + sErrorCodeToString.put(KM_ERROR_OK, "OK"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PURPOSE, "Unsupported purpose"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PURPOSE, "Incompatible purpose"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_ALGORITHM, "Unsupported algorithm"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_ALGORITHM, "Incompatible algorithm"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_SIZE, "Unsupported key size"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_BLOCK_MODE, "Unsupported block mode"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, "Incompatible block mode"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG_LENGTH, + "Unsupported authentication tag length"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PADDING_MODE, "Unsupported padding mode"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PADDING_MODE, "Incompatible padding mode"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_DIGEST, "Unsupported digest"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_DIGEST, "Incompatible digest"); + sErrorCodeToString.put(KM_ERROR_INVALID_EXPIRATION_TIME, "Invalid expiration time"); + sErrorCodeToString.put(KM_ERROR_INVALID_USER_ID, "Invalid user ID"); + sErrorCodeToString.put(KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT, + "Invalid user authorization timeout"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_FORMAT, "Unsupported key format"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_KEY_FORMAT, "Incompatible key format"); + sErrorCodeToString.put(KM_ERROR_INVALID_INPUT_LENGTH, "Invalid input length"); + sErrorCodeToString.put(KM_ERROR_KEY_NOT_YET_VALID, "Key not yet valid"); + sErrorCodeToString.put(KM_ERROR_KEY_EXPIRED, "Key expired"); + sErrorCodeToString.put(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, "Key user not authenticated"); + sErrorCodeToString.put(KM_ERROR_INVALID_OPERATION_HANDLE, "Invalid operation handle"); + sErrorCodeToString.put(KM_ERROR_VERIFICATION_FAILED, "Signature/MAC verification failed"); + sErrorCodeToString.put(KM_ERROR_TOO_MANY_OPERATIONS, "Too many operations"); + sErrorCodeToString.put(KM_ERROR_INVALID_KEY_BLOB, "Invalid key blob"); + sErrorCodeToString.put(KM_ERROR_INVALID_ARGUMENT, "Invalid argument"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG, "Unsupported tag"); + sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag"); + sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed"); + sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); + sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); + } + public static int getTagType(int tag) { return tag & (0xF << 28); } + + public static String getErrorMessage(int errorCode) { + String result = sErrorCodeToString.get(errorCode); + if (result != null) { + return result; + } + return String.valueOf(errorCode); + } } diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java index c3738d7..da81715 100644 --- a/core/java/android/security/keymaster/KeymasterIntArgument.java +++ b/core/java/android/security/keymaster/KeymasterIntArgument.java @@ -26,6 +26,15 @@ class KeymasterIntArgument extends KeymasterArgument { public KeymasterIntArgument(int tag, int value) { super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_INT: + case KeymasterDefs.KM_INT_REP: + case KeymasterDefs.KM_ENUM: + case KeymasterDefs.KM_ENUM_REP: + break; // OK. + default: + throw new IllegalArgumentException("Bad int tag " + tag); + } this.value = value; } diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java index 3c565b8..9d2be09 100644 --- a/core/java/android/security/keymaster/KeymasterLongArgument.java +++ b/core/java/android/security/keymaster/KeymasterLongArgument.java @@ -26,6 +26,12 @@ class KeymasterLongArgument extends KeymasterArgument { public KeymasterLongArgument(int tag, long value) { super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_LONG: + break; // OK. + default: + throw new IllegalArgumentException("Bad long tag " + tag); + } this.value = value; } diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java index 26673ab..bb90e40 100644 --- a/core/java/android/service/fingerprint/FingerprintManager.java +++ b/core/java/android/service/fingerprint/FingerprintManager.java @@ -202,7 +202,7 @@ public class FingerprintManager { /** * Called when the given fingerprint can't be removed. * @param fp the fingerprint that the call attempted to remove. - * @parame errMsgId an associated error message id. + * @param errMsgId an associated error message id. * @param errString an error message indicating why the fingerprint id can't be removed. */ public abstract void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString); diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 7a5bb90..3245f55 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -512,11 +512,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { Request removeRequest(IBinder reqInterface) { synchronized (this) { - Request req = mActiveRequests.get(reqInterface); - if (req != null) { - mActiveRequests.remove(req); - } - return req; + return mActiveRequests.remove(reqInterface); } } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index d46b6f5..1674950 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -155,7 +155,6 @@ public abstract class WallpaperService extends Service { WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; int mCurWindowFlags = mWindowFlags; int mCurWindowPrivateFlags = mWindowPrivateFlags; - int mOutsetBottomPx; final Rect mVisibleInsets = new Rect(); final Rect mWinFrame = new Rect(); final Rect mOverscanInsets = new Rect(); @@ -624,18 +623,9 @@ public abstract class WallpaperService extends Service { mLayout.token = mWindowToken; if (!mCreated) { - // Retrieve watch round and outset info - final WindowManager windowService = (WindowManager)getSystemService( - Context.WINDOW_SERVICE); + // Retrieve watch round info TypedArray windowStyle = obtainStyledAttributes( com.android.internal.R.styleable.Window); - final Display display = windowService.getDefaultDisplay(); - final boolean shouldUseBottomOutset = - display.getDisplayId() == Display.DEFAULT_DISPLAY; - if (shouldUseBottomOutset) { - mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx( - getResources().getDisplayMetrics(), windowStyle); - } mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources()); windowStyle.recycle(); @@ -770,10 +760,7 @@ public abstract class WallpaperService extends Service { mDispatchedStableInsets.set(mStableInsets); mFinalSystemInsets.set(mDispatchedOverscanInsets); mFinalStableInsets.set(mDispatchedStableInsets); - if (mOutsetBottomPx != 0) { - mFinalSystemInsets.bottom = - mIWallpaperEngine.mDisplayPadding.bottom + mOutsetBottomPx; - } + mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom; WindowInsets insets = new WindowInsets(mFinalSystemInsets, null, mFinalStableInsets, mWindowIsRound); onApplyWindowInsets(insets); diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index fcf1828..928bf16 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1153,7 +1153,10 @@ public abstract class Layout { return end - 1; } - if (ch != ' ' && ch != '\t') { + // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace() + if (!(ch == ' ' || ch == '\t' || ch == 0x1680 || + (0x2000 <= ch && ch <= 0x200A && ch != 0x2007) || + ch == 0x205F || ch == 0x3000)) { break; } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index ee39e27..b47418f 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -170,8 +170,9 @@ public class StaticLayout extends Layout { * Measurement and break iteration is done in native code. The protocol for using * the native code is as follows. * - * For each paragraph, do a nSetText of the paragraph text. Then, for each run within the - * paragraph: + * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth. + * + * Then, for each run within the paragraph: * - setLocale (this must be done at least for the first run, optional afterwards) * - one of the following, depending on the type of run: * + addStyleRun (a text run, to be measured in native code) @@ -459,7 +460,26 @@ public class StaticLayout extends Layout { byte[] chdirs = measured.mLevels; int dir = measured.mDir; boolean easy = measured.mEasy; - nSetText(b.mNativePtr, chs, paraEnd - paraStart); + + // tab stop locations + int[] variableTabStops = null; + if (spanned != null) { + TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, + paraEnd, TabStopSpan.class); + if (spans.length > 0) { + int[] stops = new int[spans.length]; + for (int i = 0; i < spans.length; i++) { + stops[i] = spans[i].getTabStop(); + } + Arrays.sort(stops, 0, stops.length); + variableTabStops = stops; + } + } + + int breakStrategy = 0; // 0 = kBreakStrategy_Greedy + nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart, + firstWidth, firstWidthLineCount, restWidth, + variableTabStops, TAB_INCREMENT, breakStrategy); // measurement has to be done before performing line breaking // but we don't want to recompute fontmetrics or span ranges the @@ -505,25 +525,9 @@ public class StaticLayout extends Layout { spanEndCacheCount++; } - // tab stop locations - int[] variableTabStops = null; - if (spanned != null) { - TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, - paraEnd, TabStopSpan.class); - if (spans.length > 0) { - int[] stops = new int[spans.length]; - for (int i = 0; i < spans.length; i++) { - stops[i] = spans[i].getTabStop(); - } - Arrays.sort(stops, 0, stops.length); - variableTabStops = stops; - } - } - nGetWidths(b.mNativePtr, widths); - int breakCount = nComputeLineBreaks(b.mNativePtr, paraEnd - paraStart, firstWidth, - firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks, - lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length); + int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks, + lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length); int[] breaks = lineBreaks.breaks; float[] lineWidths = lineBreaks.widths; @@ -966,7 +970,10 @@ public class StaticLayout extends Layout { private static native void nFinishBuilder(long nativePtr); private static native void nSetLocale(long nativePtr, String locale); - private static native void nSetText(long nativePtr, char[] text, int length); + // Set up paragraph text and settings; done as one big method to minimize jni crossings + private static native void nSetupParagraph(long nativePtr, char[] text, int length, + float firstWidth, int firstWidthLineCount, float restWidth, + int[] variableTabStops, int defaultTabStop, int breakStrategy); private static native float nAddStyleRun(long nativePtr, long nativePaint, long nativeTypeface, int start, int end, boolean isRtl); @@ -983,9 +990,7 @@ public class StaticLayout extends Layout { // the arrays inside the LineBreaks objects are passed in as well // to reduce the number of JNI calls in the common case where the // arrays do not have to be resized - private static native int nComputeLineBreaks(long nativePtr, - int length, float firstWidth, int firstWidthLineCount, float restWidth, - int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle, + private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle, int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength); private int mLineCount; diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 0c66709..d567d90 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -47,6 +47,7 @@ import libcore.util.ZoneInfoDB; * before 1st Jan 1970 UTC).</li> * <li>Much of the formatting / parsing assumes ASCII text and is therefore not suitable for * use with non-ASCII scripts.</li> + * <li>No support for pseudo-zones like "GMT-07:00".</li> * </ul> * * @deprecated Use {@link java.util.GregorianCalendar} instead. diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java index d29bfb6..0669b6f 100644 --- a/core/java/android/text/style/URLSpan.java +++ b/core/java/android/text/style/URLSpan.java @@ -16,6 +16,7 @@ package android.text.style; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -23,6 +24,7 @@ import android.os.Parcel; import android.provider.Browser; import android.text.ParcelableSpan; import android.text.TextUtils; +import android.util.Log; import android.view.View; public class URLSpan extends ClickableSpan implements ParcelableSpan { @@ -59,6 +61,10 @@ public class URLSpan extends ClickableSpan implements ParcelableSpan { Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); - context.startActivity(intent); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString()); + } } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8538609..cfcc6fe 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -83,6 +83,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityNodeProvider; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -3195,9 +3196,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static class ForegroundInfo { private Drawable mDrawable; private TintInfo mTintInfo; - private int mGravity = Gravity.START | Gravity.TOP; + private int mGravity = Gravity.FILL; private boolean mInsidePadding = true; - private boolean mBoundsChanged; + private boolean mBoundsChanged = true; private final Rect mSelfBounds = new Rect(); private final Rect mOverlayBounds = new Rect(); } @@ -5814,6 +5815,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); } + + info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); } private View findLabelForView(View view, int labeledId) { @@ -8261,6 +8264,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; } } break; + case R.id.accessibility_action_show_on_screen: { + if (mAttachInfo != null) { + final Rect r = mAttachInfo.mTmpInvalRect; + getDrawingRect(r); + return requestRectangleOnScreen(r, true); + } + } break; } return false; } @@ -16664,6 +16674,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mForegroundInfo.mDrawable = foreground; + mForegroundInfo.mBoundsChanged = true; if (foreground != null) { setWillNotDraw(false); foreground.setCallback(this); diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 9a92932..36f047e 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1856,14 +1856,14 @@ public abstract class Window { public abstract int getStatusBarColor(); /** - * Sets the color of the status bar to {@param color}. + * Sets the color of the status bar to {@code color}. * * For this to take effect, * the window must be drawing the system bar backgrounds with * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set. * - * If {@param color} is not opaque, consider setting + * If {@code color} is not opaque, consider setting * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}. * <p> diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 6096d7d..77082b0 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -29,6 +29,8 @@ import android.util.LongArray; import android.util.Pools.SynchronizedPool; import android.view.View; +import com.android.internal.R; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -3402,6 +3404,15 @@ public class AccessibilityNodeInfo implements Parcelable { new AccessibilityAction( AccessibilityNodeInfo.ACTION_SET_TEXT, null); + /** + * Action that requests the node make its bounding rectangle visible + * on the screen, scrolling if necessary just enough. + * + * @see View#requestRectangleOnScreen(Rect) + */ + public static final AccessibilityAction ACTION_SHOW_ON_SCREEN = + new AccessibilityAction(R.id.accessibility_action_show_on_screen, null); + private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>(); static { sStandardActions.add(ACTION_FOCUS); @@ -3426,6 +3437,7 @@ public class AccessibilityNodeInfo implements Parcelable { sStandardActions.add(ACTION_COLLAPSE); sStandardActions.add(ACTION_DISMISS); sStandardActions.add(ACTION_SET_TEXT); + sStandardActions.add(ACTION_SHOW_ON_SCREEN); } private final int mActionId; diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 4737e9b..0b18bb8 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -284,13 +284,19 @@ public class WebChromeClient { * currently set for that origin. The host application should invoke the * specified callback with the desired permission state. See * {@link GeolocationPermissions} for details. + * + * If this method isn't overridden, the callback is invoked with permission + * denied state. + * * @param origin The origin of the web content attempting to use the * Geolocation API. * @param callback The callback to use to set the permission state for the * origin. */ public void onGeolocationPermissionsShowPrompt(String origin, - GeolocationPermissions.Callback callback) {} + GeolocationPermissions.Callback callback) { + callback.invoke(origin, false, false); + } /** * Notify the host application that a request for Geolocation permissions, diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 87fcd81..6e24837 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -4664,8 +4664,8 @@ public class Editor { // Otherwise the user inserted the composition. String newText = TextUtils.substring(source, start, end); - EditOperation edit = new EditOperation(mEditor, false, "", dstart, newText); - recordEdit(edit); + EditOperation edit = new EditOperation(mEditor, "", dstart, newText); + recordEdit(edit, false /* forceMerge */); return true; } @@ -4684,11 +4684,15 @@ public class Editor { // Build a new operation with all the information from this edit. String newText = TextUtils.substring(source, start, end); String oldText = TextUtils.substring(dest, dstart, dend); - EditOperation edit = new EditOperation(mEditor, forceMerge, oldText, dstart, newText); - recordEdit(edit); + EditOperation edit = new EditOperation(mEditor, oldText, dstart, newText); + recordEdit(edit, forceMerge); } - private void recordEdit(EditOperation edit) { + /** + * Fetches the last undo operation and checks to see if a new edit should be merged into it. + * If forceMerge is true then the new edit is always merged. + */ + private void recordEdit(EditOperation edit, boolean forceMerge) { // Fetch the last edit operation and attempt to merge in the new edit. final UndoManager um = mEditor.mUndoManager; um.beginUpdate("Edit text"); @@ -4698,6 +4702,11 @@ public class Editor { // Add this as the first edit. if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit); um.addOperation(edit, UndoManager.MERGE_MODE_NONE); + } else if (forceMerge) { + // Forced merges take priority because they could be the result of a non-user-edit + // change and this case should not create a new undo operation. + if (DEBUG_UNDO) Log.d(TAG, "filter: force merge " + edit); + lastEdit.forceMergeWith(edit); } else if (!mIsUserEdit) { // An application directly modified the Editable outside of a text edit. Treat this // as a new change and don't attempt to merge. @@ -4773,7 +4782,6 @@ public class Editor { private static final int TYPE_REPLACE = 2; private int mType; - private boolean mForceMerge; private String mOldText; private int mOldTextStart; private String mNewText; @@ -4784,13 +4792,10 @@ public class Editor { /** * Constructs an edit operation from a text input operation on editor that replaces the - * oldText starting at dstart with newText. If forceMerge is true then always forcibly - * merge this operation with any previous one. + * oldText starting at dstart with newText. */ - public EditOperation(Editor editor, boolean forceMerge, String oldText, int dstart, - String newText) { + public EditOperation(Editor editor, String oldText, int dstart, String newText) { super(editor.mUndoOwner); - mForceMerge = forceMerge; mOldText = oldText; mNewText = newText; @@ -4817,7 +4822,6 @@ public class Editor { public EditOperation(Parcel src, ClassLoader loader) { super(src, loader); mType = src.readInt(); - mForceMerge = src.readInt() != 0; mOldText = src.readString(); mOldTextStart = src.readInt(); mNewText = src.readString(); @@ -4829,7 +4833,6 @@ public class Editor { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); - dest.writeInt(mForceMerge ? 1 : 0); dest.writeString(mOldText); dest.writeInt(mOldTextStart); dest.writeString(mNewText); @@ -4881,10 +4884,6 @@ public class Editor { Log.d(TAG, "mergeWith old " + this); Log.d(TAG, "mergeWith new " + edit); } - if (edit.mForceMerge) { - forceMergeWith(edit); - return true; - } switch (mType) { case TYPE_INSERT: return mergeInsertWith(edit); @@ -4942,7 +4941,7 @@ public class Editor { * Forcibly creates a single merged edit operation by simulating the entire text * contents being replaced. */ - private void forceMergeWith(EditOperation edit) { + public void forceMergeWith(EditOperation edit) { if (DEBUG_UNDO) Log.d(TAG, "forceMerge"); Editor editor = getOwnerData(); diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index af5a8bf..b187c1c 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -1209,13 +1209,13 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: - if (movePrevious()) { + if (moveDirection(-1)) { playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); return true; } break; case KeyEvent.KEYCODE_DPAD_RIGHT: - if (moveNext()) { + if (moveDirection(1)) { playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); return true; } @@ -1255,18 +1255,12 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList return super.onKeyUp(keyCode, event); } - boolean movePrevious() { - if (mItemCount > 0 && mSelectedPosition > 0) { - scrollToChild(mSelectedPosition - mFirstPosition - 1); - return true; - } else { - return false; - } - } + boolean moveDirection(int direction) { + direction = isLayoutRtl() ? -direction : direction; + int targetPosition = mSelectedPosition + direction; - boolean moveNext() { - if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) { - scrollToChild(mSelectedPosition - mFirstPosition + 1); + if (mItemCount > 0 && targetPosition >= 0 && targetPosition < mItemCount) { + scrollToChild(targetPosition - mFirstPosition); return true; } else { return false; diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index 6158a7b..083d6c7 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -238,6 +238,7 @@ interface IBackupTransport { long requestFullBackupTime(); int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket); + int checkFullBackupSize(long size); int sendBackupData(int numBytes); void cancelFullBackup(); diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags new file mode 100644 index 0000000..9e178df --- /dev/null +++ b/core/java/com/android/internal/logging/EventLogTags.logtags @@ -0,0 +1,7 @@ +# See system/core/logcat/event.logtags for a description of the format of this file. + +option java_package com.android.internal.logging; + +# interaction logs +524287 sysui_view_visibility (category|1|5),(visible|1|6) +524288 sysui_action (category|1|5),(type|1|6) diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java new file mode 100644 index 0000000..e5cba84 --- /dev/null +++ b/core/java/com/android/internal/logging/MetricsConstants.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.logging; + +/** + * Constants for mestrics logs. + * + * @hide + */ +public interface MetricsConstants { + // These constants must match those in the analytic pipeline. + public static final int ACCESSIBILITY = 2; + public static final int ACCESSIBILITY_CAPTION_PROPERTIES = 3; + public static final int ACCESSIBILITY_SERVICE = 4; + public static final int ACCESSIBILITY_TOGGLE_DALTONIZER = 5; + public static final int ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6; + public static final int ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7; + public static final int ACCOUNT = 8; + public static final int ACCOUNTS_ACCOUNT_SYNC = 9; + public static final int ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10; + public static final int ACCOUNTS_MANAGE_ACCOUNTS = 11; + public static final int APN = 12; + public static final int APN_EDITOR = 13; + public static final int APPLICATION = 16; + public static final int APPLICATIONS_APP_LAUNCH = 17; + public static final int APPLICATIONS_APP_PERMISSION = 18; + public static final int APPLICATIONS_APP_STORAGE = 19; + public static final int APPLICATIONS_INSTALLED_APP_DETAILS = 20; + public static final int APPLICATIONS_PROCESS_STATS_DETAIL = 21; + public static final int APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22; + public static final int APPLICATIONS_PROCESS_STATS_UI = 23; + public static final int APP_OPS_DETAILS = 14; + public static final int APP_OPS_SUMMARY = 15; + public static final int BLUETOOTH = 24; + public static final int BLUETOOTH_DEVICE_PICKER = 25; + public static final int BLUETOOTH_DEVICE_PROFILES = 26; + public static final int CHOOSE_LOCK_GENERIC = 27; + public static final int CHOOSE_LOCK_PASSWORD = 28; + public static final int CHOOSE_LOCK_PATTERN = 29; + public static final int CONFIRM_LOCK_PASSWORD = 30; + public static final int CONFIRM_LOCK_PATTERN = 31; + public static final int CRYPT_KEEPER = 32; + public static final int CRYPT_KEEPER_CONFIRM = 33; + public static final int DASHBOARD_SEARCH_RESULTS = 34; + public static final int DASHBOARD_SUMMARY = 35; + public static final int DATA_USAGE = 36; + public static final int DATA_USAGE_SUMMARY = 37; + public static final int DATE_TIME = 38; + public static final int DEVELOPMENT = 39; + public static final int DEVICEINFO = 40; + public static final int DEVICEINFO_IMEI_INFORMATION = 41; + public static final int DEVICEINFO_MEMORY = 42; + public static final int DEVICEINFO_SIM_STATUS = 43; + public static final int DEVICEINFO_STATUS = 44; + public static final int DEVICEINFO_USB = 45; + public static final int DISPLAY = 46; + public static final int DREAM = 47; + public static final int ENCRYPTION = 48; + public static final int FINGERPRINT = 49; + public static final int FINGERPRINT_ENROLL = 50; + public static final int FUELGAUGE_BATTERY_HISTORY_DETAIL = 51; + public static final int FUELGAUGE_BATTERY_SAVER = 52; + public static final int FUELGAUGE_POWER_USAGE_DETAIL = 53; + public static final int FUELGAUGE_POWER_USAGE_SUMMARY = 54; + public static final int HOME = 55; + public static final int ICC_LOCK = 56; + public static final int INPUTMETHOD_KEYBOARD = 58; + public static final int INPUTMETHOD_LANGUAGE = 57; + public static final int INPUTMETHOD_SPELL_CHECKERS = 59; + public static final int INPUTMETHOD_SUBTYPE_ENABLER = 60; + public static final int INPUTMETHOD_USER_DICTIONARY = 61; + public static final int INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62; + public static final int LOCATION = 63; + public static final int LOCATION_MODE = 64; + public static final int MAIN_SETTINGS = 1; + public static final int MANAGE_APPLICATIONS = 65; + public static final int MASTER_CLEAR = 66; + public static final int MASTER_CLEAR_CONFIRM = 67; + public static final int NET_DATA_USAGE_METERED = 68; + public static final int NFC_BEAM = 69; + public static final int NFC_PAYMENT = 70; + public static final int NOTIFICATION = 71; + public static final int NOTIFICATION_APP_NOTIFICATION = 72; + public static final int NOTIFICATION_OTHER_SOUND = 73; + public static final int NOTIFICATION_REDACTION = 74; + public static final int NOTIFICATION_STATION = 75; + public static final int NOTIFICATION_ZEN_MODE = 76; + public static final int OWNER_INFO = 77; + public static final int PRINT_JOB_SETTINGS = 78; + public static final int PRINT_SERVICE_SETTINGS = 79; + public static final int PRINT_SETTINGS = 80; + public static final int PRIVACY = 81; + public static final int PROXY_SELECTOR = 82; + public static final int QS_AIRPLANEMODE = 112; + public static final int QS_BLUETOOTH = 113; + public static final int QS_CAST = 114; + public static final int QS_CELLULAR = 115; + public static final int QS_COLORINVERSION = 116; + public static final int QS_DATAUSAGEDETAIL = 117; + public static final int QS_DND = 118; + public static final int QS_FLASHLIGHT = 119; + public static final int QS_HOTSPOT = 120; + public static final int QS_INTENT = 121; + public static final int QS_LOCATION = 122; + public static final int QS_PANEL = 111; + public static final int QS_ROTATIONLOCK = 123; + public static final int QS_USERDETAIL = 125; + public static final int QS_USERDETAILITE = 124; + public static final int QS_WIFI = 126; + public static final int RESET_NETWORK = 83; + public static final int RESET_NETWORK_CONFIRM = 84; + public static final int RUNNING_SERVICE_DETAILS = 85; + public static final int SCREEN_PINNING = 86; + public static final int SECURITY = 87; + public static final int SIM = 88; + public static final int TESTING = 89; + public static final int TETHER = 90; + public static final int TRUSTED_CREDENTIALS = 92; + public static final int TRUST_AGENT = 91; + public static final int TTS_ENGINE_SETTINGS = 93; + public static final int TTS_TEXT_TO_SPEECH = 94; + public static final int TYPE_UNKNOWN = 0; + public static final int USAGE_ACCESS = 95; + public static final int USER = 96; + public static final int USERS_APP_RESTRICTIONS = 97; + public static final int USER_DETAILS = 98; + public static final int VIEW_UNKNOWN = 0; + public static final int VOICE_INPUT = 99; + public static final int VPN = 100; + public static final int WALLPAPER_TYPE = 101; + public static final int WFD_WIFI_DISPLAY = 102; + public static final int WIFI = 103; + public static final int WIFI_ADVANCED = 104; + public static final int WIFI_APITEST = 107; + public static final int WIFI_CALLING = 105; + public static final int WIFI_INFO = 108; + public static final int WIFI_P2P = 109; + public static final int WIFI_SAVED_ACCESS_POINTS = 106; + public static final int WIRELESS = 110; +} diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java new file mode 100644 index 0000000..2de7394 --- /dev/null +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.logging; + + +import android.content.Context; +import android.os.Build; + +/** + * Log all the things. + * + * @hide + */ +public class MetricsLogger implements MetricsConstants { + // These constants are temporary, they should migrate to MetricsConstants. + public static final int APPLICATIONS_ADVANCED = 132; + public static final int LOCATION_SCANNING = 133; + public static final int MANAGE_APPLICATIONS_ALL = 134; + public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 135; + + public static void visible(Context context, int category) throws IllegalArgumentException { + if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { + throw new IllegalArgumentException("Must define metric category"); + } + EventLogTags.writeSysuiViewVisibility(category, 100); + } + + public static void hidden(Context context, int category) { + if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { + throw new IllegalArgumentException("Must define metric category"); + } + EventLogTags.writeSysuiViewVisibility(category, 0); + } +} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index eaa0dc7..93dc995 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -16,18 +16,14 @@ package com.android.internal.os; -import static android.net.NetworkStats.UID_ALL; -import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; - +import android.annotation.Nullable; import android.app.ActivityManager; import android.bluetooth.BluetoothActivityEnergyInfo; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkStats; -import android.net.wifi.IWifiManager; import android.net.wifi.WifiActivityEnergyInfo; import android.net.wifi.WifiManager; import android.os.BadParcelableException; @@ -42,8 +38,6 @@ import android.os.Parcel; import android.os.ParcelFormatException; import android.os.Parcelable; import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.WorkSource; @@ -65,13 +59,14 @@ import android.util.TimeUtils; import android.util.Xml; import android.view.Display; -import com.android.internal.annotations.GuardedBy; import com.android.internal.net.NetworkStatsFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; +import com.android.server.NetworkManagementSocketTagger; +import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -109,7 +104,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 121 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -132,6 +127,9 @@ public final class BatteryStatsImpl extends BatteryStats { static final int MSG_REPORT_POWER_CHANGE = 2; static final long DELAY_UPDATE_WAKELOCKS = 5*1000; + private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); + private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); + public interface BatteryCallback { public void batteryNeedsCpuUpdate(); public void batteryPowerChanged(boolean onBattery); @@ -160,7 +158,12 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public interface ExternalStatsSync { + void scheduleSync(); + } + public final MyHandler mHandler; + private final ExternalStatsSync mExternalSync; private BatteryCallback mCallback; @@ -330,7 +333,7 @@ public final class BatteryStatsImpl extends BatteryStats { int mPhoneSignalStrengthBin = -1; int mPhoneSignalStrengthBinRaw = -1; - final StopwatchTimer[] mPhoneSignalStrengthsTimer = + final StopwatchTimer[] mPhoneSignalStrengthsTimer = new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS]; StopwatchTimer mPhoneSignalScanningTimer; @@ -445,18 +448,17 @@ public final class BatteryStatsImpl extends BatteryStats { private int mLoadedNumConnectivityChange; private int mUnpluggedNumConnectivityChange; + private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry(); + /* * Holds a SamplingTimer associated with each kernel wakelock name being tracked. */ - private final HashMap<String, SamplingTimer> mKernelWakelockStats = - new HashMap<String, SamplingTimer>(); + private final HashMap<String, SamplingTimer> mKernelWakelockStats = new HashMap<>(); public Map<String, ? extends Timer> getKernelWakelockStats() { return mKernelWakelockStats; } - private static int sKernelWakelockUpdateVersion = 0; - String mLastWakeupReason = null; long mLastWakeupUptimeMs = 0; private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>(); @@ -465,56 +467,12 @@ public final class BatteryStatsImpl extends BatteryStats { return mWakeupReasonStats; } - private static final int[] PROC_WAKELOCKS_FORMAT = new int[] { - Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name - Process.PROC_QUOTES, - Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count - Process.PROC_TAB_TERM, - Process.PROC_TAB_TERM, - Process.PROC_TAB_TERM, - Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime - }; - - private static final int[] WAKEUP_SOURCES_FORMAT = new int[] { - Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name - Process.PROC_TAB_TERM|Process.PROC_COMBINE| - Process.PROC_OUT_LONG, // 1: count - Process.PROC_TAB_TERM|Process.PROC_COMBINE, - Process.PROC_TAB_TERM|Process.PROC_COMBINE, - Process.PROC_TAB_TERM|Process.PROC_COMBINE, - Process.PROC_TAB_TERM|Process.PROC_COMBINE, - Process.PROC_TAB_TERM|Process.PROC_COMBINE - |Process.PROC_OUT_LONG, // 6: totalTime - }; - - private final String[] mProcWakelocksName = new String[3]; - private final long[] mProcWakelocksData = new long[3]; - - /* - * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added - * to mKernelWakelockStats. - */ - private final Map<String, KernelWakelockStats> mProcWakelockFileStats = - new HashMap<String, KernelWakelockStats>(); - - private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory(); - private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50); - private NetworkStats mLastMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50); - private NetworkStats mCurWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50); - private NetworkStats mLastWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50); - private NetworkStats mTmpNetworkStats; - private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry(); - - @GuardedBy("this") - private String[] mMobileIfaces = new String[0]; - @GuardedBy("this") - private String[] mWifiIfaces = new String[0]; - public BatteryStatsImpl() { mFile = null; mCheckinFile = null; mDailyFile = null; mHandler = null; + mExternalSync = null; clearHistoryLocked(); } @@ -524,7 +482,7 @@ public final class BatteryStatsImpl extends BatteryStats { } static class TimeBase { - private final ArrayList<TimeBaseObs> mObservers = new ArrayList<TimeBaseObs>(); + private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>(); private long mUptime; private long mRealtime; @@ -1779,147 +1737,6 @@ public final class BatteryStatsImpl extends BatteryStats { return timer; } - private final Map<String, KernelWakelockStats> readKernelWakelockStats() { - - FileInputStream is; - byte[] buffer = new byte[32*1024]; - int len; - boolean wakeup_sources; - - try { - try { - is = new FileInputStream("/d/wakeup_sources"); - wakeup_sources = true; - } catch (java.io.FileNotFoundException e) { - try { - is = new FileInputStream("/proc/wakelocks"); - wakeup_sources = false; - } catch (java.io.FileNotFoundException e2) { - return null; - } - } - - len = is.read(buffer); - is.close(); - } catch (java.io.IOException e) { - return null; - } - - if (len > 0) { - if (len >= buffer.length) { - Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length); - } - int i; - for (i=0; i<len; i++) { - if (buffer[i] == '\0') { - len = i; - break; - } - } - } - - return parseProcWakelocks(buffer, len, wakeup_sources); - } - - private final Map<String, KernelWakelockStats> parseProcWakelocks( - byte[] wlBuffer, int len, boolean wakeup_sources) { - String name; - int count; - long totalTime; - int startIndex; - int endIndex; - int numUpdatedWlNames = 0; - - // Advance past the first line. - int i; - for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++); - startIndex = endIndex = i + 1; - - synchronized(this) { - Map<String, KernelWakelockStats> m = mProcWakelockFileStats; - - sKernelWakelockUpdateVersion++; - while (endIndex < len) { - for (endIndex=startIndex; - endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; - endIndex++); - endIndex++; // endIndex is an exclusive upper bound. - // Don't go over the end of the buffer, Process.parseProcLine might - // write to wlBuffer[endIndex] - if (endIndex >= (len - 1) ) { - return m; - } - - String[] nameStringArray = mProcWakelocksName; - long[] wlData = mProcWakelocksData; - // Stomp out any bad characters since this is from a circular buffer - // A corruption is seen sometimes that results in the vm crashing - // This should prevent crashes and the line will probably fail to parse - for (int j = startIndex; j < endIndex; j++) { - if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?'; - } - boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex, - wakeup_sources ? WAKEUP_SOURCES_FORMAT : - PROC_WAKELOCKS_FORMAT, - nameStringArray, wlData, null); - - name = nameStringArray[0]; - count = (int) wlData[1]; - - if (wakeup_sources) { - // convert milliseconds to microseconds - totalTime = wlData[2] * 1000; - } else { - // convert nanoseconds to microseconds with rounding. - totalTime = (wlData[2] + 500) / 1000; - } - - if (parsed && name.length() > 0) { - if (!m.containsKey(name)) { - m.put(name, new KernelWakelockStats(count, totalTime, - sKernelWakelockUpdateVersion)); - numUpdatedWlNames++; - } else { - KernelWakelockStats kwlStats = m.get(name); - if (kwlStats.mVersion == sKernelWakelockUpdateVersion) { - kwlStats.mCount += count; - kwlStats.mTotalTime += totalTime; - } else { - kwlStats.mCount = count; - kwlStats.mTotalTime = totalTime; - kwlStats.mVersion = sKernelWakelockUpdateVersion; - numUpdatedWlNames++; - } - } - } - startIndex = endIndex; - } - - if (m.size() != numUpdatedWlNames) { - // Don't report old data. - Iterator<KernelWakelockStats> itr = m.values().iterator(); - while (itr.hasNext()) { - if (itr.next().mVersion != sKernelWakelockUpdateVersion) { - itr.remove(); - } - } - } - return m; - } - } - - private class KernelWakelockStats { - public int mCount; - public long mTotalTime; - public int mVersion; - - KernelWakelockStats(int count, long totalTime, int version) { - mCount = count; - mTotalTime = totalTime; - mVersion = version; - } - } - /* * Get the KernelWakelockTimer associated with name, and create a new one if one * doesn't already exist. @@ -3391,7 +3208,7 @@ public final class BatteryStatsImpl extends BatteryStats { mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime); } else { mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs); - updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs); + updateMobileRadioStateLocked(realElapsedRealtimeMs); mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs); } } @@ -3729,6 +3546,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mWifiOn = true; mWifiOnTimer.startRunningLocked(elapsedRealtime); + scheduleSyncExternalStatsLocked(); } } @@ -3742,6 +3560,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtime); + scheduleSyncExternalStatsLocked(); } } @@ -3904,6 +3723,7 @@ public final class BatteryStatsImpl extends BatteryStats { int uid = mapUid(ws.get(i)); getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime); } + scheduleSyncExternalStatsLocked(); } else { Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running"); } @@ -3942,6 +3762,7 @@ public final class BatteryStatsImpl extends BatteryStats { int uid = mapUid(ws.get(i)); getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime); } + scheduleSyncExternalStatsLocked(); } else { Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running"); } @@ -3956,6 +3777,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mWifiState = wifiState; mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime); + scheduleSyncExternalStatsLocked(); } } @@ -4027,6 +3849,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mBluetoothOn = true; mBluetoothOnTimer.startRunningLocked(elapsedRealtime); + scheduleSyncExternalStatsLocked(); } } @@ -4040,6 +3863,7 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtime, uptime); mBluetoothOn = false; mBluetoothOnTimer.stopRunningLocked(elapsedRealtime); + scheduleSyncExternalStatsLocked(); } } @@ -4066,6 +3890,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } mWifiFullLockNesting++; getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime); @@ -4081,6 +3906,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime); } @@ -4138,6 +3964,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } mWifiMulticastNesting++; getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime); @@ -4153,6 +3980,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: " + Integer.toHexString(mHistoryCur.states)); addHistoryRecordLocked(elapsedRealtime, uptime); + scheduleSyncExternalStatsLocked(); } getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime); } @@ -4260,7 +4088,8 @@ public final class BatteryStatsImpl extends BatteryStats { // During device boot, qtaguid isn't enabled until after the inital // loading of battery stats. Now that they're enabled, take our initial // snapshot for future delta calculation. - updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime()); + updateMobileRadioStateLocked(SystemClock.elapsedRealtime()); + updateWifiStateLocked(null); } @Override public long getScreenOnTime(long elapsedRealtimeUs, int which) { @@ -4607,17 +4436,17 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { + public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() { return mWakelockStats.getMap(); } @Override - public Map<String, ? extends BatteryStats.Timer> getSyncStats() { + public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() { return mSyncStats.getMap(); } @Override - public Map<String, ? extends BatteryStats.Timer> getJobStats() { + public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() { return mJobStats.getMap(); } @@ -4627,12 +4456,12 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() { + public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() { return mProcessStats; } @Override - public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() { + public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() { return mPackageStats; } @@ -5950,7 +5779,7 @@ public final class BatteryStatsImpl extends BatteryStats { Slog.w(TAG, "File corrupt: too many excessive power entries " + N); return false; } - + mExcessivePower = new ArrayList<ExcessivePower>(); for (int i=0; i<N; i++) { ExcessivePower ew = new ExcessivePower(); @@ -6153,40 +5982,20 @@ public final class BatteryStatsImpl extends BatteryStats { */ public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs { /** - * Number of times this package has done something that could wake up the - * device from sleep. - */ - int mWakeups; - - /** - * Number of things that could wake up the device loaded from a - * previous save. - */ - int mLoadedWakeups; - - /** - * Number of things that could wake up the device as of the - * last run. - */ - int mLastWakeups; - - /** - * Number of things that could wake up the device as of the - * last run. + * Number of times wakeup alarms have occurred for this app. */ - int mUnpluggedWakeups; + ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>(); /** * The statics we have collected for this package's services. */ - final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>(); + final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>(); Pkg() { mOnBatteryScreenOffTimeBase.add(this); } public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { - mUnpluggedWakeups = mWakeups; } public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { @@ -6197,10 +6006,12 @@ public final class BatteryStatsImpl extends BatteryStats { } void readFromParcelLocked(Parcel in) { - mWakeups = in.readInt(); - mLoadedWakeups = in.readInt(); - mLastWakeups = 0; - mUnpluggedWakeups = in.readInt(); + int numWA = in.readInt(); + mWakeupAlarms.clear(); + for (int i=0; i<numWA; i++) { + String tag = in.readString(); + mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in)); + } int numServs = in.readInt(); mServiceStats.clear(); @@ -6214,34 +6025,39 @@ public final class BatteryStatsImpl extends BatteryStats { } void writeToParcelLocked(Parcel out) { - out.writeInt(mWakeups); - out.writeInt(mLoadedWakeups); - out.writeInt(mUnpluggedWakeups); - - out.writeInt(mServiceStats.size()); - for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) { - out.writeString(servEntry.getKey()); - Uid.Pkg.Serv serv = servEntry.getValue(); - + int numWA = mWakeupAlarms.size(); + out.writeInt(numWA); + for (int i=0; i<numWA; i++) { + out.writeString(mWakeupAlarms.keyAt(i)); + mWakeupAlarms.valueAt(i).writeToParcel(out); + } + + final int NS = mServiceStats.size(); + out.writeInt(NS); + for (int i=0; i<NS; i++) { + out.writeString(mServiceStats.keyAt(i)); + Uid.Pkg.Serv serv = mServiceStats.valueAt(i); serv.writeToParcelLocked(out); } } @Override - public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() { - return mServiceStats; + public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() { + return mWakeupAlarms; } - @Override - public int getWakeups(int which) { - int val = mWakeups; - if (which == STATS_CURRENT) { - val -= mLoadedWakeups; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedWakeups; + public void noteWakeupAlarmLocked(String tag) { + Counter c = mWakeupAlarms.get(tag); + if (c == null) { + c = new Counter(mOnBatteryTimeBase); + mWakeupAlarms.put(tag, c); } + c.stepAtomic(); + } - return val; + @Override + public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() { + return mServiceStats; } /** @@ -6483,14 +6299,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public BatteryStatsImpl getBatteryStats() { - return BatteryStatsImpl.this; - } - - public void incWakeupsLocked() { - mWakeups++; - } - final Serv newServiceStatsLocked() { return new Serv(); } @@ -6749,7 +6557,7 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public BatteryStatsImpl(File systemDir, Handler handler) { + public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { if (systemDir != null) { mFile = new JournaledFile(new File(systemDir, "batterystats.bin"), new File(systemDir, "batterystats.bin.tmp")); @@ -6758,6 +6566,7 @@ public final class BatteryStatsImpl extends BatteryStats { } mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin")); mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml")); + mExternalSync = externalSync; mHandler = new MyHandler(handler.getLooper()); mStartCount++; mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase); @@ -6830,6 +6639,7 @@ public final class BatteryStatsImpl extends BatteryStats { mCheckinFile = null; mDailyFile = null; mHandler = null; + mExternalSync = null; clearHistoryLocked(); readFromParcel(p); } @@ -7501,21 +7311,233 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel; } } - + public void pullPendingStateUpdatesLocked() { - updateKernelWakelocksLocked(); - updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime()); - // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786 - // updateBluetoothControllerActivityLocked(); - // TODO(adamlesinski): disabled to avoid deadlock. Need to change how external - // data is pulled/accessed from BatteryStats. b/19729960 - // updateWifiControllerActivityLocked(); if (mOnBatteryInternal) { final boolean screenOn = mScreenState == Display.STATE_ON; updateDischargeScreenLevelsLocked(screenOn, screenOn); } } + private String[] mMobileIfaces = EmptyArray.STRING; + private String[] mWifiIfaces = EmptyArray.STRING; + + private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory(); + + private static final int NETWORK_STATS_LAST = 0; + private static final int NETWORK_STATS_NEXT = 1; + private static final int NETWORK_STATS_DELTA = 2; + + private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] { + new NetworkStats(SystemClock.elapsedRealtime(), 50), + new NetworkStats(SystemClock.elapsedRealtime(), 50), + new NetworkStats(SystemClock.elapsedRealtime(), 50) + }; + + private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] { + new NetworkStats(SystemClock.elapsedRealtime(), 50), + new NetworkStats(SystemClock.elapsedRealtime(), 50), + new NetworkStats(SystemClock.elapsedRealtime(), 50) + }; + + /** + * Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer + * as a buffer of NetworkStats objects to cycle through when computing deltas. + */ + private NetworkStats getNetworkStatsDeltaLocked(String[] ifaces, + NetworkStats[] networkStatsBuffer) + throws IOException { + if (!SystemProperties.getBoolean(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED, + false)) { + return null; + } + + final NetworkStats stats = mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL, + ifaces, NetworkStats.TAG_NONE, networkStatsBuffer[NETWORK_STATS_NEXT]); + networkStatsBuffer[NETWORK_STATS_DELTA] = NetworkStats.subtract(stats, + networkStatsBuffer[NETWORK_STATS_LAST], null, null, + networkStatsBuffer[NETWORK_STATS_DELTA]); + networkStatsBuffer[NETWORK_STATS_NEXT] = networkStatsBuffer[NETWORK_STATS_LAST]; + networkStatsBuffer[NETWORK_STATS_LAST] = stats; + return networkStatsBuffer[NETWORK_STATS_DELTA]; + } + + /** + * Distribute WiFi energy info and network traffic to apps. + * @param info The energy information from the WiFi controller. + */ + public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) { + final NetworkStats delta; + try { + delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats); + } catch (IOException e) { + Slog.wtf(TAG, "Failed to get wifi network stats", e); + return; + } + + if (!mOnBatteryInternal) { + return; + } + + if (delta != null) { + final int size = delta.size(); + for (int i = 0; i < size; i++) { + final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); + + if (DEBUG) { + Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes + + " tx=" + entry.txBytes); + } + + if (entry.rxBytes == 0 || entry.txBytes == 0) { + continue; + } + + final Uid u = getUidStatsLocked(mapUid(entry.uid)); + u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, + entry.rxPackets); + u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, + entry.txPackets); + + mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked( + entry.rxBytes); + mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked( + entry.txBytes); + mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked( + entry.rxPackets); + mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked( + entry.txPackets); + } + } + + if (info != null) { + // Update WiFi controller stats. + mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked( + info.getControllerRxTimeMillis()); + mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked( + info.getControllerTxTimeMillis()); + mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( + info.getControllerIdleTimeMillis()); + mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked( + info.getControllerEnergyUsed()); + } + } + + /** + * Distribute Cell radio energy info and network traffic to apps. + */ + public void updateMobileRadioStateLocked(long elapsedRealtimeMs) { + final NetworkStats delta; + + try { + delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats); + } catch (IOException e) { + Slog.wtf(TAG, "Failed to get mobile network stats", e); + return; + } + + if (delta == null || !mOnBatteryInternal) { + return; + } + + long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(elapsedRealtimeMs); + long totalPackets = delta.getTotalPackets(); + + final int size = delta.size(); + for (int i = 0; i < size; i++) { + final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); + + if (entry.rxBytes == 0 || entry.txBytes == 0) continue; + + final Uid u = getUidStatsLocked(mapUid(entry.uid)); + u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, + entry.rxPackets); + u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, + entry.txPackets); + + if (radioTime > 0) { + // Distribute total radio active time in to this app. + long appPackets = entry.rxPackets + entry.txPackets; + long appRadioTime = (radioTime*appPackets)/totalPackets; + u.noteMobileRadioActiveTimeLocked(appRadioTime); + // Remove this app from the totals, so that we don't lose any time + // due to rounding. + radioTime -= appRadioTime; + totalPackets -= appPackets; + } + + mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( + entry.rxBytes); + mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( + entry.txBytes); + mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( + entry.rxPackets); + mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( + entry.txPackets); + } + + if (radioTime > 0) { + // Whoops, there is some radio time we can't blame on an app! + mMobileRadioActiveUnknownTime.addCountLocked(radioTime); + mMobileRadioActiveUnknownCount.addCountLocked(1); + } + } + + /** + * Distribute Bluetooth energy info and network traffic to apps. + * @param info The energy information from the bluetooth controller. + */ + public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) { + if (info != null && mOnBatteryInternal) { + mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked( + info.getControllerRxTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked( + info.getControllerTxTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( + info.getControllerIdleTimeMillis()); + mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked( + info.getControllerEnergyUsed()); + } + } + + /** + * Read and distribute kernel wake lock use across apps. + */ + public void updateKernelWakelocksLocked() { + final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats( + mTmpWakelockStats); + if (wakelockStats == null) { + // Not crashing might make board bringup easier. + Slog.w(TAG, "Couldn't get kernel wake lock stats"); + return; + } + + for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { + String name = ent.getKey(); + KernelWakelockStats.Entry kws = ent.getValue(); + + SamplingTimer kwlt = mKernelWakelockStats.get(name); + if (kwlt == null) { + kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, + true /* track reported val */); + mKernelWakelockStats.put(name, kwlt); + } + kwlt.updateCurrentReportedCount(kws.mCount); + kwlt.updateCurrentReportedTotalTime(kws.mTotalTime); + kwlt.setUpdateVersion(kws.mVersion); + } + + if (wakelockStats.size() != mKernelWakelockStats.size()) { + // Set timers to stale if they didn't appear in /proc/wakelocks this time. + for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) { + SamplingTimer st = ent.getValue(); + if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) { + st.setStale(); + } + } + } + } + void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level) { boolean doWrite = false; @@ -7669,340 +7691,132 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private void scheduleSyncExternalStatsLocked() { + if (mExternalSync != null) { + mExternalSync.scheduleSync(); + } + } + // This should probably be exposed in the API, though it's not critical - private static final int BATTERY_PLUGGED_NONE = 0; + public static final int BATTERY_PLUGGED_NONE = 0; - public void setBatteryState(int status, int health, int plugType, int level, + public void setBatteryStateLocked(int status, int health, int plugType, int level, int temp, int volt) { - synchronized(this) { - final boolean onBattery = plugType == BATTERY_PLUGGED_NONE; - final long uptime = SystemClock.uptimeMillis(); - final long elapsedRealtime = SystemClock.elapsedRealtime(); - if (!mHaveBatteryLevel) { - mHaveBatteryLevel = true; - // We start out assuming that the device is plugged in (not - // on battery). If our first report is now that we are indeed - // plugged in, then twiddle our state to correctly reflect that - // since we won't be going through the full setOnBattery(). - if (onBattery == mOnBattery) { - if (onBattery) { - mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } else { - mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; - } - } - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryLevel = (byte)level; - mMaxChargeStepLevel = mMinDischargeStepLevel = - mLastChargeStepLevel = mLastDischargeStepLevel = level; - } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { - recordDailyStatsIfNeededLocked(level >= 100 && onBattery); - } - int oldStatus = mHistoryCur.batteryStatus; - if (onBattery) { - mDischargeCurrentLevel = level; - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtime, uptime, true); - } - } else if (level < 96) { - if (!mRecordingHistory) { - mRecordingHistory = true; - startRecordingHistory(elapsedRealtime, uptime, true); - } - } - mCurrentBatteryLevel = level; - if (mDischargePlugLevel < 0) { - mDischargePlugLevel = level; - } - if (onBattery != mOnBattery) { - mHistoryCur.batteryLevel = (byte)level; - mHistoryCur.batteryStatus = (byte)status; - mHistoryCur.batteryHealth = (byte)health; - mHistoryCur.batteryPlugType = (byte)plugType; - mHistoryCur.batteryTemperature = (short)temp; - mHistoryCur.batteryVoltage = (char)volt; - setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level); - } else { - boolean changed = false; - if (mHistoryCur.batteryLevel != level) { - mHistoryCur.batteryLevel = (byte)level; - changed = true; - } - if (mHistoryCur.batteryStatus != status) { - mHistoryCur.batteryStatus = (byte)status; - changed = true; - } - if (mHistoryCur.batteryHealth != health) { - mHistoryCur.batteryHealth = (byte)health; - changed = true; - } - if (mHistoryCur.batteryPlugType != plugType) { - mHistoryCur.batteryPlugType = (byte)plugType; - changed = true; - } - if (temp >= (mHistoryCur.batteryTemperature+10) - || temp <= (mHistoryCur.batteryTemperature-10)) { - mHistoryCur.batteryTemperature = (short)temp; - changed = true; - } - if (volt > (mHistoryCur.batteryVoltage+20) - || volt < (mHistoryCur.batteryVoltage-20)) { - mHistoryCur.batteryVoltage = (char)volt; - changed = true; - } - if (changed) { - addHistoryRecordLocked(elapsedRealtime, uptime); - } - long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT) - | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT) - | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT); + final boolean onBattery = plugType == BATTERY_PLUGGED_NONE; + final long uptime = SystemClock.uptimeMillis(); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + if (!mHaveBatteryLevel) { + mHaveBatteryLevel = true; + // We start out assuming that the device is plugged in (not + // on battery). If our first report is now that we are indeed + // plugged in, then twiddle our state to correctly reflect that + // since we won't be going through the full setOnBattery(). + if (onBattery == mOnBattery) { if (onBattery) { - if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) { - mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level, - modeBits, elapsedRealtime); - mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level, - modeBits, elapsedRealtime); - mLastDischargeStepLevel = level; - mMinDischargeStepLevel = level; - mInitStepMode = mCurStepMode; - mModStepMode = 0; - } + mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; } else { - if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) { - mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel, - modeBits, elapsedRealtime); - mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel, - modeBits, elapsedRealtime); - mLastChargeStepLevel = level; - mMaxChargeStepLevel = level; - mInitStepMode = mCurStepMode; - mModStepMode = 0; - } + mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; } } - if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) { - // We don't record history while we are plugged in and fully charged. - // The next time we are unplugged, history will be cleared. - mRecordingHistory = DEBUG; + mHistoryCur.batteryStatus = (byte)status; + mHistoryCur.batteryLevel = (byte)level; + mMaxChargeStepLevel = mMinDischargeStepLevel = + mLastChargeStepLevel = mLastDischargeStepLevel = level; + } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) { + recordDailyStatsIfNeededLocked(level >= 100 && onBattery); + } + int oldStatus = mHistoryCur.batteryStatus; + if (onBattery) { + mDischargeCurrentLevel = level; + if (!mRecordingHistory) { + mRecordingHistory = true; + startRecordingHistory(elapsedRealtime, uptime, true); + } + } else if (level < 96) { + if (!mRecordingHistory) { + mRecordingHistory = true; + startRecordingHistory(elapsedRealtime, uptime, true); } } - } - - public void updateKernelWakelocksLocked() { - Map<String, KernelWakelockStats> m = readKernelWakelockStats(); - - if (m == null) { - // Not crashing might make board bringup easier. - Slog.w(TAG, "Couldn't get kernel wake lock stats"); - return; + mCurrentBatteryLevel = level; + if (mDischargePlugLevel < 0) { + mDischargePlugLevel = level; } + if (onBattery != mOnBattery) { + mHistoryCur.batteryLevel = (byte)level; + mHistoryCur.batteryStatus = (byte)status; + mHistoryCur.batteryHealth = (byte)health; + mHistoryCur.batteryPlugType = (byte)plugType; + mHistoryCur.batteryTemperature = (short)temp; + mHistoryCur.batteryVoltage = (char)volt; + setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level); + } else { + boolean changed = false; + if (mHistoryCur.batteryLevel != level) { + mHistoryCur.batteryLevel = (byte)level; + changed = true; - for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) { - String name = ent.getKey(); - KernelWakelockStats kws = ent.getValue(); - - SamplingTimer kwlt = mKernelWakelockStats.get(name); - if (kwlt == null) { - kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase, - true /* track reported val */); - mKernelWakelockStats.put(name, kwlt); + // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record + // which will pull external stats. + scheduleSyncExternalStatsLocked(); } - kwlt.updateCurrentReportedCount(kws.mCount); - kwlt.updateCurrentReportedTotalTime(kws.mTotalTime); - kwlt.setUpdateVersion(sKernelWakelockUpdateVersion); - } - - if (m.size() != mKernelWakelockStats.size()) { - // Set timers to stale if they didn't appear in /proc/wakelocks this time. - for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) { - SamplingTimer st = ent.getValue(); - if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) { - st.setStale(); - } + if (mHistoryCur.batteryStatus != status) { + mHistoryCur.batteryStatus = (byte)status; + changed = true; } - } - } - - static final int NET_UPDATE_MOBILE = 1<<0; - static final int NET_UPDATE_WIFI = 1<<1; - static final int NET_UPDATE_ALL = 0xffff; - - private void updateNetworkActivityLocked(int which, long elapsedRealtimeMs) { - if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return; - - if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) { - final NetworkStats snapshot; - final NetworkStats last = mCurMobileSnapshot; - try { - snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL, - mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot); - } catch (IOException e) { - Log.wtf(TAG, "Failed to read mobile network stats", e); - return; + if (mHistoryCur.batteryHealth != health) { + mHistoryCur.batteryHealth = (byte)health; + changed = true; } - - mCurMobileSnapshot = snapshot; - mLastMobileSnapshot = last; - - if (mOnBatteryInternal) { - final NetworkStats delta = NetworkStats.subtract(snapshot, last, - null, null, mTmpNetworkStats); - mTmpNetworkStats = delta; - - long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked( - elapsedRealtimeMs); - long totalPackets = delta.getTotalPackets(); - - final int size = delta.size(); - for (int i = 0; i < size; i++) { - final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); - - if (entry.rxBytes == 0 || entry.txBytes == 0) continue; - - final Uid u = getUidStatsLocked(mapUid(entry.uid)); - u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, - entry.rxPackets); - u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, - entry.txPackets); - - if (radioTime > 0) { - // Distribute total radio active time in to this app. - long appPackets = entry.rxPackets + entry.txPackets; - long appRadioTime = (radioTime*appPackets)/totalPackets; - u.noteMobileRadioActiveTimeLocked(appRadioTime); - // Remove this app from the totals, so that we don't lose any time - // due to rounding. - radioTime -= appRadioTime; - totalPackets -= appPackets; - } - - mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( - entry.rxBytes); - mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( - entry.txBytes); - mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked( - entry.rxPackets); - mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked( - entry.txPackets); - } - - if (radioTime > 0) { - // Whoops, there is some radio time we can't blame on an app! - mMobileRadioActiveUnknownTime.addCountLocked(radioTime); - mMobileRadioActiveUnknownCount.addCountLocked(1); - } + if (mHistoryCur.batteryPlugType != plugType) { + mHistoryCur.batteryPlugType = (byte)plugType; + changed = true; } - } - - if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) { - final NetworkStats snapshot; - final NetworkStats last = mCurWifiSnapshot; - try { - snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL, - mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot); - } catch (IOException e) { - Log.wtf(TAG, "Failed to read wifi network stats", e); - return; + if (temp >= (mHistoryCur.batteryTemperature+10) + || temp <= (mHistoryCur.batteryTemperature-10)) { + mHistoryCur.batteryTemperature = (short)temp; + changed = true; } - - mCurWifiSnapshot = snapshot; - mLastWifiSnapshot = last; - - if (mOnBatteryInternal) { - final NetworkStats delta = NetworkStats.subtract(snapshot, last, - null, null, mTmpNetworkStats); - mTmpNetworkStats = delta; - - final int size = delta.size(); - for (int i = 0; i < size; i++) { - final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry); - - if (DEBUG) { - final NetworkStats.Entry cur = snapshot.getValues(i, null); - Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes - + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes - + " tx=" + cur.txBytes); - } - - if (entry.rxBytes == 0 || entry.txBytes == 0) continue; - - final Uid u = getUidStatsLocked(mapUid(entry.uid)); - u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, - entry.rxPackets); - u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, - entry.txPackets); - - mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked( - entry.rxBytes); - mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked( - entry.txBytes); - mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked( - entry.rxPackets); - mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked( - entry.txPackets); + if (volt > (mHistoryCur.batteryVoltage+20) + || volt < (mHistoryCur.batteryVoltage-20)) { + mHistoryCur.batteryVoltage = (char)volt; + changed = true; + } + if (changed) { + addHistoryRecordLocked(elapsedRealtime, uptime); + } + long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT) + | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT) + | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT); + if (onBattery) { + if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) { + mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level, + modeBits, elapsedRealtime); + mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level, + modeBits, elapsedRealtime); + mLastDischargeStepLevel = level; + mMinDischargeStepLevel = level; + mInitStepMode = mCurStepMode; + mModStepMode = 0; + } + } else { + if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) { + mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel, + modeBits, elapsedRealtime); + mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel, + modeBits, elapsedRealtime); + mLastChargeStepLevel = level; + mMaxChargeStepLevel = level; + mInitStepMode = mCurStepMode; + mModStepMode = 0; } } } - } - - private void updateBluetoothControllerActivityLocked() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter == null) { - return; - } - - // We read the data even if we are not on battery. Each read clears - // the previous data, so we must always read to make sure the - // data is for the current interval. - BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo( - BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED); - if (info == null || !info.isValid() || !mOnBatteryInternal) { - // Bad info or we are not on battery. - return; - } - - mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked( - info.getControllerRxTimeMillis()); - mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked( - info.getControllerTxTimeMillis()); - mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( - info.getControllerIdleTimeMillis()); - mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked( - info.getControllerEnergyUsed()); - } - - private void updateWifiControllerActivityLocked() { - IWifiManager wifiManager = IWifiManager.Stub.asInterface( - ServiceManager.getService(Context.WIFI_SERVICE)); - if (wifiManager == null) { - return; - } - - WifiActivityEnergyInfo info; - try { - // We read the data even if we are not on battery. Each read clears - // the previous data, so we must always read to make sure the - // data is for the current interval. - info = wifiManager.reportActivityInfo(); - } catch (RemoteException e) { - // Nothing to report, WiFi is dead. - return; + if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) { + // We don't record history while we are plugged in and fully charged. + // The next time we are unplugged, history will be cleared. + mRecordingHistory = DEBUG; } - - if (info == null || !info.isValid() || !mOnBatteryInternal) { - // Bad info or we are not on battery. - return; - } - - mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked( - info.getControllerRxTimeMillis()); - mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked( - info.getControllerTxTimeMillis()); - mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( - info.getControllerIdleTimeMillis()); - mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked( - info.getControllerEnergyUsed()); } public long getAwakeTimeBattery() { @@ -8938,7 +8752,18 @@ public final class BatteryStatsImpl extends BatteryStats { for (int ip = 0; ip < NP; ip++) { String pkgName = in.readString(); Uid.Pkg p = u.getPackageStatsLocked(pkgName); - p.mWakeups = p.mLoadedWakeups = in.readInt(); + final int NWA = in.readInt(); + if (NWA > 1000) { + Slog.w(TAG, "File corrupt: too many wakeup alarms " + NWA); + return; + } + p.mWakeupAlarms.clear(); + for (int iwa=0; iwa<NWA; iwa++) { + String tag = in.readString(); + Counter c = new Counter(mOnBatteryTimeBase); + c.readSummaryFromParcelLocked(in); + p.mWakeupAlarms.put(tag, c); + } NS = in.readInt(); if (NS > 1000) { Slog.w(TAG, "File corrupt: too many services " + NS); @@ -9263,20 +9088,22 @@ public final class BatteryStatsImpl extends BatteryStats { : u.mPackageStats.entrySet()) { out.writeString(ent.getKey()); Uid.Pkg ps = ent.getValue(); - out.writeInt(ps.mWakeups); + final int NWA = ps.mWakeupAlarms.size(); + out.writeInt(NWA); + for (int iwa=0; iwa<NWA; iwa++) { + out.writeString(ps.mWakeupAlarms.keyAt(iwa)); + ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out); + } NS = ps.mServiceStats.size(); out.writeInt(NS); - if (NS > 0) { - for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent - : ps.mServiceStats.entrySet()) { - out.writeString(sent.getKey()); - BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue(); - long time = ss.getStartTimeToNowLocked( - mOnBatteryTimeBase.getUptime(NOW_SYS)); - out.writeLong(time); - out.writeInt(ss.mStarts); - out.writeInt(ss.mLaunches); - } + for (int is=0; is<NS; is++) { + out.writeString(ps.mServiceStats.keyAt(is)); + BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is); + long time = ss.getStartTimeToNowLocked( + mOnBatteryTimeBase.getUptime(NOW_SYS)); + out.writeLong(time); + out.writeInt(ss.mStarts); + out.writeInt(ss.mLaunches); } } } diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java new file mode 100644 index 0000000..768d586 --- /dev/null +++ b/core/java/com/android/internal/os/KernelWakelockReader.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.os.Process; +import android.util.Slog; + +import java.io.FileInputStream; +import java.util.Iterator; + +/** + * Reads and parses wakelock stats from the kernel (/proc/wakelocks). + */ +public class KernelWakelockReader { + private static final String TAG = "KernelWakelockReader"; + private static int sKernelWakelockUpdateVersion = 0; + private static final String sWakelockFile = "/proc/wakelocks"; + private static final String sWakeupSourceFile = "/d/wakeup_sources"; + + private static final int[] PROC_WAKELOCKS_FORMAT = new int[] { + Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name + Process.PROC_QUOTES, + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM, + Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime + }; + + private static final int[] WAKEUP_SOURCES_FORMAT = new int[] { + Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name + Process.PROC_TAB_TERM|Process.PROC_COMBINE| + Process.PROC_OUT_LONG, // 1: count + Process.PROC_TAB_TERM|Process.PROC_COMBINE, + Process.PROC_TAB_TERM|Process.PROC_COMBINE, + Process.PROC_TAB_TERM|Process.PROC_COMBINE, + Process.PROC_TAB_TERM|Process.PROC_COMBINE, + Process.PROC_TAB_TERM|Process.PROC_COMBINE + |Process.PROC_OUT_LONG, // 6: totalTime + }; + + private final String[] mProcWakelocksName = new String[3]; + private final long[] mProcWakelocksData = new long[3]; + + /** + * Reads kernel wakelock stats and updates the staleStats with the new information. + * @param staleStats Existing object to update. + * @return the updated data. + */ + public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) { + byte[] buffer = new byte[32*1024]; + int len; + boolean wakeup_sources; + + try { + FileInputStream is; + try { + is = new FileInputStream(sWakeupSourceFile); + wakeup_sources = true; + } catch (java.io.FileNotFoundException e) { + try { + is = new FileInputStream(sWakelockFile); + wakeup_sources = false; + } catch (java.io.FileNotFoundException e2) { + return null; + } + } + + len = is.read(buffer); + is.close(); + } catch (java.io.IOException e) { + return null; + } + + if (len > 0) { + if (len >= buffer.length) { + Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length); + } + int i; + for (i=0; i<len; i++) { + if (buffer[i] == '\0') { + len = i; + break; + } + } + } + return parseProcWakelocks(buffer, len, wakeup_sources, staleStats); + } + + /** + * Reads the wakelocks and updates the staleStats with the new information. + */ + private KernelWakelockStats parseProcWakelocks(byte[] wlBuffer, int len, boolean wakeup_sources, + final KernelWakelockStats staleStats) { + String name; + int count; + long totalTime; + int startIndex; + int endIndex; + int numUpdatedWlNames = 0; + + // Advance past the first line. + int i; + for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++); + startIndex = endIndex = i + 1; + + synchronized(this) { + sKernelWakelockUpdateVersion++; + while (endIndex < len) { + for (endIndex=startIndex; + endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; + endIndex++); + endIndex++; // endIndex is an exclusive upper bound. + // Don't go over the end of the buffer, Process.parseProcLine might + // write to wlBuffer[endIndex] + if (endIndex >= (len - 1) ) { + return staleStats; + } + + String[] nameStringArray = mProcWakelocksName; + long[] wlData = mProcWakelocksData; + // Stomp out any bad characters since this is from a circular buffer + // A corruption is seen sometimes that results in the vm crashing + // This should prevent crashes and the line will probably fail to parse + for (int j = startIndex; j < endIndex; j++) { + if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?'; + } + boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex, + wakeup_sources ? WAKEUP_SOURCES_FORMAT : + PROC_WAKELOCKS_FORMAT, + nameStringArray, wlData, null); + + name = nameStringArray[0]; + count = (int) wlData[1]; + + if (wakeup_sources) { + // convert milliseconds to microseconds + totalTime = wlData[2] * 1000; + } else { + // convert nanoseconds to microseconds with rounding. + totalTime = (wlData[2] + 500) / 1000; + } + + if (parsed && name.length() > 0) { + if (!staleStats.containsKey(name)) { + staleStats.put(name, new KernelWakelockStats.Entry(count, totalTime, + sKernelWakelockUpdateVersion)); + numUpdatedWlNames++; + } else { + KernelWakelockStats.Entry kwlStats = staleStats.get(name); + if (kwlStats.mVersion == sKernelWakelockUpdateVersion) { + kwlStats.mCount += count; + kwlStats.mTotalTime += totalTime; + } else { + kwlStats.mCount = count; + kwlStats.mTotalTime = totalTime; + kwlStats.mVersion = sKernelWakelockUpdateVersion; + numUpdatedWlNames++; + } + } + } + startIndex = endIndex; + } + + if (staleStats.size() != numUpdatedWlNames) { + // Don't report old data. + Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator(); + while (itr.hasNext()) { + if (itr.next().mVersion != sKernelWakelockUpdateVersion) { + itr.remove(); + } + } + } + + staleStats.kernelWakelockVersion = sKernelWakelockUpdateVersion; + return staleStats; + } + } +} diff --git a/core/java/com/android/internal/os/KernelWakelockStats.java b/core/java/com/android/internal/os/KernelWakelockStats.java new file mode 100644 index 0000000..144ea00 --- /dev/null +++ b/core/java/com/android/internal/os/KernelWakelockStats.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import java.util.HashMap; + +/** + * Kernel wakelock stats object. + */ +public class KernelWakelockStats extends HashMap<String, KernelWakelockStats.Entry> { + public static class Entry { + public int mCount; + public long mTotalTime; + public int mVersion; + + Entry(int count, long totalTime, int version) { + mCount = count; + mTotalTime = totalTime; + mVersion = version; + } + } + + int kernelWakelockVersion; +} diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java new file mode 100644 index 0000000..be9945d --- /dev/null +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -0,0 +1,596 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.PopupWindow; + +import com.android.internal.R; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * A floating toolbar for showing contextual menu items. + * This view shows as many menu item buttons as can fit in the horizontal toolbar and the + * the remaining menu items in a vertical overflow view when the overflow button is clicked. + * The horizontal toolbar morphs into the vertical overflow view. + */ +public final class FloatingToolbar { + + private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = + new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + return false; + } + }; + + private final Context mContext; + private final FloatingToolbarPopup mPopup; + private final ViewGroup mMenuItemButtonsContainer; + private final View.OnClickListener mMenuItemButtonOnClickListener = + new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getTag() instanceof MenuItem) { + mMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag()); + mPopup.dismiss(); + } + } + }; + + private final Rect mContentRect = new Rect(); + private final Point mCoordinates = new Point(); + + private Menu mMenu; + private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); + private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; + private View mOpenOverflowButton; + + private int mSuggestedWidth; + + /** + * Initializes a floating toolbar. + */ + public FloatingToolbar(Context context, Window window) { + mContext = Preconditions.checkNotNull(context); + mPopup = new FloatingToolbarPopup(Preconditions.checkNotNull(window.getDecorView())); + mMenuItemButtonsContainer = createMenuButtonsContainer(context); + } + + /** + * Sets the menu to be shown in this floating toolbar. + * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the + * toolbar. + */ + public FloatingToolbar setMenu(Menu menu) { + mMenu = Preconditions.checkNotNull(menu); + return this; + } + + /** + * Sets the custom listener for invocation of menu items in this floating + * toolbar. + */ + public FloatingToolbar setOnMenuItemClickListener( + MenuItem.OnMenuItemClickListener menuItemClickListener) { + if (menuItemClickListener != null) { + mMenuItemClickListener = menuItemClickListener; + } else { + mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; + } + return this; + } + + /** + * Sets the content rectangle. This is the area of the interesting content that this toolbar + * should avoid obstructing. + * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the + * toolbar. + */ + public FloatingToolbar setContentRect(Rect rect) { + mContentRect.set(Preconditions.checkNotNull(rect)); + return this; + } + + /** + * Sets the suggested width of this floating toolbar. + * The actual width will be about this size but there are no guarantees that it will be exactly + * the suggested width. + * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the + * toolbar. + */ + public FloatingToolbar setSuggestedWidth(int suggestedWidth) { + mSuggestedWidth = suggestedWidth; + return this; + } + + /** + * Shows this floating toolbar. + */ + public FloatingToolbar show() { + List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); + if (hasContentChanged(menuItems) || hasWidthChanged()) { + mPopup.dismiss(); + layoutMenuItemButtons(menuItems); + mShowingTitles = getMenuItemTitles(menuItems); + } + refreshCoordinates(); + mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y); + if (!mPopup.isShowing()) { + mPopup.show(mCoordinates.x, mCoordinates.y); + } + return this; + } + + /** + * Updates this floating toolbar to reflect recent position and view updates. + * NOTE: This method is a no-op if the toolbar isn't showing. + */ + public FloatingToolbar updateLayout() { + if (mPopup.isShowing()) { + // show() performs all the logic we need here. + show(); + } + return this; + } + + /** + * Dismisses this floating toolbar. + */ + public void dismiss() { + mPopup.dismiss(); + } + + /** + * Returns {@code true} if this popup is currently showing. {@code false} otherwise. + */ + public boolean isShowing() { + return mPopup.isShowing(); + } + + /** + * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}. + */ + private void refreshCoordinates() { + int popupWidth = mPopup.getWidth(); + int popupHeight = mPopup.getHeight(); + if (!mPopup.isShowing()) { + // Popup isn't yet shown, get estimated size from the menu item buttons container. + mMenuItemButtonsContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + popupWidth = mMenuItemButtonsContainer.getMeasuredWidth(); + popupHeight = mMenuItemButtonsContainer.getMeasuredHeight(); + } + int x = mContentRect.centerX() - popupWidth / 2; + int y; + if (shouldDisplayAtTopOfContent()) { + y = mContentRect.top - popupHeight; + } else { + y = mContentRect.bottom; + } + mCoordinates.set(x, y); + } + + /** + * Returns true if this floating toolbar's menu items have been reordered or changed. + */ + private boolean hasContentChanged(List<MenuItem> menuItems) { + return !mShowingTitles.equals(getMenuItemTitles(menuItems)); + } + + /** + * Returns true if there is a significant change in width of the toolbar. + */ + private boolean hasWidthChanged() { + int actualWidth = mPopup.getWidth(); + int difference = Math.abs(actualWidth - mSuggestedWidth); + return difference > (actualWidth * 0.2); + } + + /** + * Returns true if the preferred positioning of the toolbar is above the content rect. + */ + private boolean shouldDisplayAtTopOfContent() { + return mContentRect.top - getMinimumOverflowHeight(mContext) > 0; + } + + /** + * Returns the visible and enabled menu items in the specified menu. + * This method is recursive. + */ + private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) { + List<MenuItem> menuItems = new ArrayList<MenuItem>(); + for (int i = 0; (menu != null) && (i < menu.size()); i++) { + MenuItem menuItem = menu.getItem(i); + if (menuItem.isVisible() && menuItem.isEnabled()) { + Menu subMenu = menuItem.getSubMenu(); + if (subMenu != null) { + menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu)); + } else { + menuItems.add(menuItem); + } + } + } + return menuItems; + } + + private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) { + List<CharSequence> titles = new ArrayList<CharSequence>(); + for (MenuItem menuItem : menuItems) { + titles.add(menuItem.getTitle()); + } + return titles; + } + + private void layoutMenuItemButtons(List<MenuItem> menuItems) { + final int toolbarWidth = getAdjustedToolbarWidth(mContext, mSuggestedWidth) + // Reserve space for the "open overflow" button. + - getEstimatedOpenOverflowButtonWidth(mContext); + + int availableWidth = toolbarWidth; + LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems); + + mMenuItemButtonsContainer.removeAllViews(); + + boolean isFirstItem = true; + while (!remainingMenuItems.isEmpty()) { + final MenuItem menuItem = remainingMenuItems.peek(); + Button menuItemButton = createMenuItemButton(mContext, menuItem); + + // Adding additional left padding for the first button to even out button spacing. + if (isFirstItem) { + menuItemButton.setPadding( + 2 * menuItemButton.getPaddingLeft(), + menuItemButton.getPaddingTop(), + menuItemButton.getPaddingRight(), + menuItemButton.getPaddingBottom()); + isFirstItem = false; + } + + // Adding additional right padding for the last button to even out button spacing. + if (remainingMenuItems.size() == 1) { + menuItemButton.setPadding( + menuItemButton.getPaddingLeft(), + menuItemButton.getPaddingTop(), + 2 * menuItemButton.getPaddingRight(), + menuItemButton.getPaddingBottom()); + } + + menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth); + if (menuItemButtonWidth <= availableWidth) { + menuItemButton.setTag(menuItem); + menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener); + mMenuItemButtonsContainer.addView(menuItemButton); + menuItemButton.getLayoutParams().width = menuItemButtonWidth; + availableWidth -= menuItemButtonWidth; + remainingMenuItems.pop(); + } else { + // The "open overflow" button launches the vertical overflow from the + // floating toolbar. + createOpenOverflowButtonIfNotExists(); + mMenuItemButtonsContainer.addView(mOpenOverflowButton); + break; + } + } + mPopup.setContentView(mMenuItemButtonsContainer); + } + + /** + * Creates and returns the button that opens the vertical overflow. + */ + private void createOpenOverflowButtonIfNotExists() { + mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext) + .inflate(R.layout.floating_popup_open_overflow_button, null); + mOpenOverflowButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Open the overflow. + } + }); + } + + /** + * Creates and returns a floating toolbar menu buttons container. + */ + private static ViewGroup createMenuButtonsContainer(Context context) { + return (ViewGroup) LayoutInflater.from(context) + .inflate(R.layout.floating_popup_container, null); + } + + /** + * Creates and returns a menu button for the specified menu item. + */ + private static Button createMenuItemButton(Context context, MenuItem menuItem) { + Button menuItemButton = (Button) LayoutInflater.from(context) + .inflate(R.layout.floating_popup_menu_button, null); + menuItemButton.setText(menuItem.getTitle()); + menuItemButton.setContentDescription(menuItem.getTitle()); + return menuItemButton; + } + + private static int getMinimumOverflowHeight(Context context) { + return context.getResources(). + getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height); + } + + private static int getEstimatedOpenOverflowButtonWidth(Context context) { + return context.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width); + } + + private static int getAdjustedToolbarWidth(Context context, int width) { + if (width <= 0 || width > getScreenWidth(context)) { + width = context.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_default_width); + } + return width; + } + + /** + * Returns the device's screen width. + */ + public static int getScreenWidth(Context context) { + return context.getResources().getDisplayMetrics().widthPixels; + } + + /** + * Returns the device's screen height. + */ + public static int getScreenHeight(Context context) { + return context.getResources().getDisplayMetrics().heightPixels; + } + + + /** + * A popup window used by the floating toolbar. + */ + private static final class FloatingToolbarPopup { + + private final View mParent; + private final PopupWindow mPopupWindow; + private final ViewGroup mContentContainer; + private final Animator.AnimatorListener mOnDismissEnd = + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mPopupWindow.dismiss(); + mDismissAnimating = false; + } + }; + private final AnimatorSet mGrowFadeInFromBottomAnimation; + private final AnimatorSet mShrinkFadeOutFromBottomAnimation; + + private boolean mDismissAnimating; + + /** + * Initializes a new floating bar popup. + * + * @param parent A parent view to get the {@link View#getWindowToken()} token from. + */ + public FloatingToolbarPopup(View parent) { + mParent = Preconditions.checkNotNull(parent); + mContentContainer = createContentContainer(parent.getContext()); + mPopupWindow = createPopupWindow(mContentContainer); + mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer); + mShrinkFadeOutFromBottomAnimation = + createShrinkFadeOutFromBottomAnimation(mContentContainer, mOnDismissEnd); + } + + /** + * Shows this popup at the specified coordinates. + * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. + * If this popup is already showing, this will be a no-op. + */ + public void show(int x, int y) { + if (isShowing()) { + updateCoordinates(x, y); + return; + } + + mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, 0, 0); + positionOnScreen(x, y); + growFadeInFromBottom(); + + mDismissAnimating = false; + } + + /** + * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op. + */ + public void dismiss() { + if (!isShowing()) { + return; + } + + if (mDismissAnimating) { + // This window is already dismissing. Don't restart the animation. + return; + } + mDismissAnimating = true; + shrinkFadeOutFromBottom(); + } + + /** + * Returns {@code true} if this popup is currently showing. {@code false} otherwise. + */ + public boolean isShowing() { + return mPopupWindow.isShowing() && !mDismissAnimating; + } + + /** + * Updates the coordinates of this popup. + * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. + */ + public void updateCoordinates(int x, int y) { + if (isShowing()) { + positionOnScreen(x, y); + } + } + + /** + * Sets the content of this popup. + */ + public void setContentView(View view) { + Preconditions.checkNotNull(view); + mContentContainer.removeAllViews(); + mContentContainer.addView(view); + } + + /** + * Returns the width of this popup. + */ + public int getWidth() { + return mContentContainer.getWidth(); + } + + /** + * Returns the height of this popup. + */ + public int getHeight() { + return mContentContainer.getHeight(); + } + + /** + * Returns the context this popup is running in. + */ + public Context getContext() { + return mContentContainer.getContext(); + } + + private void positionOnScreen(int x, int y) { + if (getWidth() == 0) { + // content size is yet to be measured. + mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + } + x = clamp(x, 0, getScreenWidth(getContext()) - getWidth()); + y = clamp(y, 0, getScreenHeight(getContext()) - getHeight()); + + // Position the view w.r.t. the window. + mContentContainer.setX(x); + mContentContainer.setY(y); + } + + /** + * Performs the "grow and fade in from the bottom" animation on the floating popup. + */ + private void growFadeInFromBottom() { + setPivot(); + mGrowFadeInFromBottomAnimation.start(); + } + + /** + * Performs the "shrink and fade out from bottom" animation on the floating popup. + */ + private void shrinkFadeOutFromBottom() { + setPivot(); + mShrinkFadeOutFromBottomAnimation.start(); + } + + /** + * Sets the popup content container's pivot. + */ + private void setPivot() { + mContentContainer.setPivotX(mContentContainer.getMeasuredWidth() / 2); + mContentContainer.setPivotY(mContentContainer.getMeasuredHeight()); + } + + private static ViewGroup createContentContainer(Context context) { + return (ViewGroup) LayoutInflater.from(context) + .inflate(R.layout.floating_popup_container, null); + } + + private static PopupWindow createPopupWindow(View content) { + ViewGroup popupContentHolder = new LinearLayout(content.getContext()); + PopupWindow popupWindow = new PopupWindow(popupContentHolder); + popupWindow.setAnimationStyle(0); + popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + popupWindow.setWidth(getScreenWidth(content.getContext())); + popupWindow.setHeight(getScreenHeight(content.getContext())); + content.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + popupContentHolder.addView(content); + return popupWindow; + } + + /** + * Creates a "grow and fade in from the bottom" animation for the specified view. + * + * @param view The view to animate + */ + private static AnimatorSet createGrowFadeInFromBottom(View view) { + AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet(); + growFadeInFromBottomAnimation.playTogether( + ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125), + ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125), + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75)); + return growFadeInFromBottomAnimation; + } + + /** + * Creates a "shrink and fade out from bottom" animation for the specified view. + * + * @param view The view to animate + * @param listener The animation listener + */ + private static AnimatorSet createShrinkFadeOutFromBottomAnimation( + View view, Animator.AnimatorListener listener) { + AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet(); + shrinkFadeOutFromBottomAnimation.playTogether( + ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125), + ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75)); + shrinkFadeOutFromBottomAnimation.setStartDelay(150); + shrinkFadeOutFromBottomAnimation.addListener(listener); + return shrinkFadeOutFromBottomAnimation; + } + + /** + * Returns value, restricted to the range min->max (inclusive). + * If maximum is less than minimum, the result is undefined. + * + * @param value The value to clamp. + * @param minimum The minimum value in the range. + * @param maximum The maximum value in the range. Must not be less than minimum. + */ + private static int clamp(int value, int minimum, int maximum) { + return Math.max(minimum, Math.min(value, maximum)); + } + } +} diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java index b5f2f37..037fd66 100644 --- a/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/core/java/com/android/server/backup/SystemBackupAgent.java @@ -104,9 +104,9 @@ public class SystemBackupAgent extends BackupAgentHelper { // steps during restore; the restore will happen properly when the individual // files are restored piecemeal. FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null, - WALLPAPER_INFO_DIR, WALLPAPER_INFO, output.getData()); + WALLPAPER_INFO_DIR, WALLPAPER_INFO, output); FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null, - WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output.getData()); + WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output); } @Override |
