From fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 16 Jul 2014 17:31:10 -0700 Subject: [PATCH] Implement issue #16330060: Inform ActivityManager about WebView... ...state changes. Add a new API to tell the activity manager about a new dependency one process has on another package. Start using it already for when apps is Context.createPackageContext() to load code from another app. Also do some work on getting the monitoring of proc/uid states in shape so it can be used by unundled code, along with an AppImportanceMonitor class for doing so. Some small fixes and additions to VoiceInteractionService. Improve handling of unaccounted/overcounted battery use so that they aren't shown to the user unless they are significant. Change-Id: I22dd79a73f4e70103d3f8964494aebc8a31f971c --- api/current.txt | 4 + core/java/android/app/ActivityManager.java | 24 ++- .../android/app/ActivityManagerNative.java | 25 ++- core/java/android/app/ActivityThread.java | 13 +- .../android/app/AppImportanceMonitor.java | 150 ++++++++++++++++++ core/java/android/app/ContextImpl.java | 2 +- core/java/android/app/IActivityManager.java | 6 +- core/java/android/app/LoadedApk.java | 12 +- core/java/android/content/Context.java | 10 +- .../voice/IVoiceInteractionService.aidl | 1 + .../voice/VoiceInteractionService.java | 71 ++++++++- .../voice/VoiceInteractionServiceInfo.java | 7 + .../android/internal/os/BatterySipper.java | 9 ++ .../internal/os/BatteryStatsHelper.java | 8 +- core/res/res/values/attrs.xml | 3 + core/res/res/values/public.xml | 1 + .../server/am/ActivityManagerService.java | 72 +++++---- .../com/android/server/am/ProcessRecord.java | 11 +- .../VoiceInteractionManagerServiceImpl.java | 4 + .../MainInteractionService.java | 4 +- 20 files changed, 383 insertions(+), 54 deletions(-) create mode 100644 core/java/android/app/AppImportanceMonitor.java diff --git a/api/current.txt b/api/current.txt index 87c730066b5a0..97bd93cd05608 100644 --- a/api/current.txt +++ b/api/current.txt @@ -996,6 +996,7 @@ package android { field public static final int ratingBarStyleIndicator = 16843280; // 0x1010210 field public static final int ratingBarStyleSmall = 16842877; // 0x101007d field public static final int readPermission = 16842759; // 0x1010007 + field public static final int recognitionService = 16843935; // 0x101049f field public static final int relinquishTaskIdentity = 16843896; // 0x1010478 field public static final int repeatCount = 16843199; // 0x10101bf field public static final int repeatMode = 16843200; // 0x10101c0 @@ -3613,6 +3614,7 @@ package android.app { field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190 field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4 field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 + field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82 field public static final int IMPORTANCE_SERVICE = 300; // 0x12c field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8 @@ -26990,7 +26992,9 @@ package android.service.voice { public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public final android.service.voice.AlwaysOnHotwordDetector getAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback); + method public static boolean isActiveService(android.content.Context, android.content.ComponentName); method public android.os.IBinder onBind(android.content.Intent); + method public void onReady(); method public void startSession(android.os.Bundle); field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction"; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index c8cab6f11b039..d2540f19c2a9b 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1819,7 +1819,29 @@ public class ActivityManager { * actively running code. */ public static final int IMPORTANCE_EMPTY = 500; - + + /** + * Constant for {@link #importance}: this process does not exist. + */ + public static final int IMPORTANCE_GONE = 1000; + + /** @hide */ + public static int procStateToImportance(int procState) { + if (procState >= ActivityManager.PROCESS_STATE_HOME) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + } else if (procState >= ActivityManager.PROCESS_STATE_SERVICE) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; + } else if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; + } else if (procState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; + } else if (procState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; + } else { + return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } + } + /** * The relative importance level that the system places on this * process. May be one of {@link #IMPORTANCE_FOREGROUND}, diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index e2b5a841c532c..fb70098d69597 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1465,7 +1465,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + + case ADD_PACKAGE_DEPENDENCY_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String packageName = data.readString(); + addPackageDependency(packageName); + reply.writeNoException(); + return true; + } + case KILL_APPLICATION_WITH_APPID_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String pkg = data.readString(); @@ -1475,7 +1483,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case CLOSE_SYSTEM_DIALOGS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String reason = data.readString(); @@ -4050,7 +4058,18 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); data.recycle(); } - + + public void addPackageDependency(String packageName) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(packageName); + mRemote.transact(ADD_PACKAGE_DEPENDENCY_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public void killApplicationWithAppId(String pkg, int appid, String reason) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7c8c83aa15a1c..15f3a759e26c7 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1684,6 +1684,7 @@ public final class ActivityThread { && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null ? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid) : true); + boolean registerPackage = includeCode && (flags&Context.CONTEXT_REGISTER_PACKAGE) != 0; if ((flags&(Context.CONTEXT_INCLUDE_CODE |Context.CONTEXT_IGNORE_SECURITY)) == Context.CONTEXT_INCLUDE_CODE) { @@ -1698,12 +1699,13 @@ public final class ActivityThread { throw new SecurityException(msg); } } - return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode); + return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode, + registerPackage); } public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo) { - return getPackageInfo(ai, compatInfo, null, false, true); + return getPackageInfo(ai, compatInfo, null, false, true, false); } public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) { @@ -1719,7 +1721,8 @@ public final class ActivityThread { } private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, - ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { + ClassLoader baseLoader, boolean securityViolation, boolean includeCode, + boolean registerPackage) { synchronized (mResourcesManager) { WeakReference ref; if (includeCode) { @@ -1738,7 +1741,7 @@ public final class ActivityThread { packageInfo = new LoadedApk(this, aInfo, compatInfo, baseLoader, securityViolation, includeCode && - (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); + (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage); if (includeCode) { mPackages.put(aInfo.packageName, new WeakReference(packageInfo)); @@ -4394,7 +4397,7 @@ public final class ActivityThread { instrApp.dataDir = ii.dataDir; instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, - appContext.getClassLoader(), false, true); + appContext.getClassLoader(), false, true, false); ContextImpl instrContext = ContextImpl.createAppContext(this, pi); try { diff --git a/core/java/android/app/AppImportanceMonitor.java b/core/java/android/app/AppImportanceMonitor.java new file mode 100644 index 0000000000000..c760e1e34c53b --- /dev/null +++ b/core/java/android/app/AppImportanceMonitor.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2014 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.app; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.SparseArray; +import android.util.SparseIntArray; + +import java.util.List; + +/** + * Helper for monitoring the current importance of applications. + * @hide + */ +public class AppImportanceMonitor { + final Context mContext; + + final SparseArray mApps = new SparseArray<>(); + + static class AppEntry { + final int uid; + final SparseArray procs = new SparseArray<>(1); + int importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; + + AppEntry(int _uid) { + uid = _uid; + } + } + + final IProcessObserver mProcessObserver = new IProcessObserver.Stub() { + @Override + public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { + } + + @Override + public void onProcessStateChanged(int pid, int uid, int procState) { + synchronized (mApps) { + updateImportanceLocked(pid, uid, + ActivityManager.RunningAppProcessInfo.procStateToImportance(procState), + true); + } + } + + @Override + public void onProcessDied(int pid, int uid) { + synchronized (mApps) { + updateImportanceLocked(pid, uid, + ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, true); + } + } + }; + + static final int MSG_UPDATE = 1; + + final Handler mHandler; + + public AppImportanceMonitor(Context context, Looper looper) { + mContext = context; + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE: + onImportanceChanged(msg.arg1, msg.arg2&0xffff, msg.arg2>>16); + break; + default: + super.handleMessage(msg); + } + } + }; + ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); + try { + ActivityManagerNative.getDefault().registerProcessObserver(mProcessObserver); + } catch (RemoteException e) { + } + List apps = am.getRunningAppProcesses(); + if (apps != null) { + for (int i=0; i= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) { + ent.procs.remove(pid); + } else { + ent.procs.put(pid, importance); + } + updateImportanceLocked(ent, repChange); + } + + void updateImportanceLocked(AppEntry ent, boolean repChange) { + int appImp = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; + for (int i=0; i= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) { + mApps.remove(ent.uid); + } + if (repChange) { + mHandler.obtainMessage(MSG_UPDATE, ent.uid, impCode).sendToTarget(); + } + } + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d7c384aef6ace..cbfde14fa3616 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2097,7 +2097,7 @@ class ContextImpl extends Context { } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), - flags, user.getIdentifier()); + flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, user, restricted, mDisplay, mOverrideConfiguration); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index c6921a209e2c3..ac2916124ef3a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -294,7 +294,9 @@ public interface IActivityManager extends IInterface { public void stopAppSwitches() throws RemoteException; public void resumeAppSwitches() throws RemoteException; - + + public void addPackageDependency(String packageName) throws RemoteException; + public void killApplicationWithAppId(String pkg, int appid, String reason) throws RemoteException; @@ -640,7 +642,7 @@ public interface IActivityManager extends IInterface { int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91; int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92; int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93; - int ___AVAILABLE_2___ = IBinder.FIRST_CALL_TRANSACTION+94; + int ADD_PACKAGE_DEPENDENCY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94; int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95; int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96; int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 38614a06cfab4..24c283590188b 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -93,6 +93,7 @@ public final class LoadedApk { private final ClassLoader mBaseClassLoader; private final boolean mSecurityViolation; private final boolean mIncludeCode; + private final boolean mRegisterPackage; private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); Resources mResources; private ClassLoader mClassLoader; @@ -121,7 +122,7 @@ public final class LoadedApk { */ public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, CompatibilityInfo compatInfo, ClassLoader baseLoader, - boolean securityViolation, boolean includeCode) { + boolean securityViolation, boolean includeCode, boolean registerPackage) { final int myUid = Process.myUid(); aInfo = adjustNativeLibraryPaths(aInfo); @@ -144,6 +145,7 @@ public final class LoadedApk { mBaseClassLoader = baseLoader; mSecurityViolation = securityViolation; mIncludeCode = includeCode; + mRegisterPackage = registerPackage; mDisplayAdjustments.setCompatibilityInfo(compatInfo); } @@ -189,6 +191,7 @@ public final class LoadedApk { mBaseClassLoader = null; mSecurityViolation = false; mIncludeCode = true; + mRegisterPackage = false; mClassLoader = ClassLoader.getSystemClassLoader(); mResources = Resources.getSystem(); } @@ -272,6 +275,13 @@ public final class LoadedApk { final ArrayList zipPaths = new ArrayList<>(); final ArrayList libPaths = new ArrayList<>(); + if (mRegisterPackage) { + try { + ActivityManagerNative.getDefault().addPackageDependency(mPackageName); + } catch (RemoteException e) { + } + } + zipPaths.add(mAppDir); if (mSplitAppDirs != null) { Collections.addAll(zipPaths, mSplitAppDirs); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7d152332205c0..1dd018f3d1df2 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2475,11 +2475,11 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a {@link - * android.net.ethernet.EthernetManager} for handling management of + * android.net.EthernetManager} for handling management of * Ethernet access. * * @see #getSystemService - * @see android.net.ethernet.EthernetManager + * @see android.net.EthernetManager * * @hide */ @@ -3250,6 +3250,12 @@ public abstract class Context { */ public static final int CONTEXT_RESTRICTED = 0x00000004; + /** + * @hide Used to indicate we should tell the activity manager about the process + * loading this code. + */ + public static final int CONTEXT_REGISTER_PACKAGE = 0x40000000; + /** * Return a new Context object for the given application name. This * Context is the same as what the named application gets when it is diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl index e9e2f4c81aa7c..c9915a27634d0 100644 --- a/core/java/android/service/voice/IVoiceInteractionService.aidl +++ b/core/java/android/service/voice/IVoiceInteractionService.aidl @@ -20,4 +20,5 @@ package android.service.voice; * @hide */ oneway interface IVoiceInteractionService { + void ready(); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index a9b19599bb460..1f5d3276d1819 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -18,15 +18,19 @@ package android.service.voice; import android.annotation.SdkConstant; import android.app.Service; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; import android.hardware.soundtrigger.SoundTriggerHelper; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; +import android.provider.Settings; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractionManagerService; @@ -64,14 +68,58 @@ public class VoiceInteractionService extends Service { public static final String SERVICE_META_DATA = "android.voice_interaction"; IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { + @Override public void ready() { + mHandler.sendEmptyMessage(MSG_READY); + } }; + MyHandler mHandler; + IVoiceInteractionManagerService mSystemService; private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo; private SoundTriggerHelper mSoundTriggerHelper; + static final int MSG_READY = 1; + + class MyHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_READY: + onReady(); + break; + default: + super.handleMessage(msg); + } + } + } + + /** + * Check whether the given service component is the currently active + * VoiceInteractionService. + */ + public static boolean isActiveService(Context context, ComponentName service) { + String cur = Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE); + if (cur == null || cur.isEmpty()) { + return false; + } + ComponentName curComp = ComponentName.unflattenFromString(cur); + if (curComp == null) { + return false; + } + return curComp.equals(cur); + } + + /** + * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}. + * @param args Arbitrary arguments that will be propagated to the session. + */ public void startSession(Bundle args) { + if (mSystemService == null) { + throw new IllegalStateException("Not available until onReady() is called"); + } try { mSystemService.startSession(mInterface, args); } catch (RemoteException e) { @@ -81,10 +129,7 @@ public class VoiceInteractionService extends Service { @Override public void onCreate() { super.onCreate(); - mSystemService = IVoiceInteractionManagerService.Stub.asInterface( - ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); - mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager()); - mSoundTriggerHelper = new SoundTriggerHelper(); + mHandler = new MyHandler(); } @Override @@ -95,6 +140,19 @@ public class VoiceInteractionService extends Service { return null; } + /** + * Called during service initialization to tell you when the system is ready + * to receive interaction from it. You should generally do initialization here + * rather than in {@link #onCreate()}. Methods such as {@link #startSession} + * and {@link #getAlwaysOnHotwordDetector} will not be operational until this point. + */ + public void onReady() { + mSystemService = IVoiceInteractionManagerService.Stub.asInterface( + ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); + mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager()); + mSoundTriggerHelper = new SoundTriggerHelper(); + } + /** * @param keyphrase The keyphrase that's being used, for example "Hello Android". * @param locale The locale for which the enrollment needs to be performed. @@ -104,6 +162,11 @@ public class VoiceInteractionService extends Service { */ public final AlwaysOnHotwordDetector getAlwaysOnHotwordDetector( String keyphrase, String locale, AlwaysOnHotwordDetector.Callback callback) { + if (mSystemService == null) { + throw new IllegalStateException("Not available until onReady() is called"); + } + // TODO: Cache instances and return the same one instead of creating a new interactor + // for the same keyphrase/locale combination. return new AlwaysOnHotwordDetector(keyphrase, locale, callback, mKeyphraseEnrollmentInfo, mSoundTriggerHelper, mInterface, mSystemService); } diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java index a909ead8e95cd..d27e2cd91061f 100644 --- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java +++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java @@ -40,6 +40,7 @@ public class VoiceInteractionServiceInfo { private ServiceInfo mServiceInfo; private String mSessionService; + private String mRecognitionService; private String mSettingsActivity; public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp) @@ -82,6 +83,8 @@ public class VoiceInteractionServiceInfo { com.android.internal.R.styleable.VoiceInteractionService); mSessionService = array.getString( com.android.internal.R.styleable.VoiceInteractionService_sessionService); + mRecognitionService = array.getString( + com.android.internal.R.styleable.VoiceInteractionService_recognitionService); mSettingsActivity = array.getString( com.android.internal.R.styleable.VoiceInteractionService_settingsActivity); array.recycle(); @@ -119,6 +122,10 @@ public class VoiceInteractionServiceInfo { return mSessionService; } + public String getRecognitionService() { + return mRecognitionService; + } + public String getSettingsActivity() { return mSettingsActivity; } diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 247c8feab80d9..cfeca086b2b43 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -80,6 +80,15 @@ public class BatterySipper implements Comparable { @Override public int compareTo(BatterySipper other) { + // Over-counted always goes to the bottom. + if (drainType != other.drainType) { + if (drainType == DrainType.OVERCOUNTED) { + // This is "larger" + return 1; + } else if (other.drainType == DrainType.OVERCOUNTED) { + return -1; + } + } // Return the flipped value because we want the items in descending order return Double.compare(other.value, value); } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index 023ba032b1e8a..6c9b4b838152c 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -48,7 +48,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Arrays; /** * A helper class for retrieving the power usage information for all applications and services. @@ -95,6 +94,7 @@ public class BatteryStatsHelper { private long mStatsPeriod = 0; private double mMaxPower = 1; + private double mMaxRealPower = 1; private double mComputedPower; private double mTotalPower; private double mWifiPower; @@ -208,6 +208,7 @@ public class BatteryStatsHelper { getStats(); mMaxPower = 0; + mMaxRealPower = 0; mComputedPower = 0; mTotalPower = 0; mWifiPower = 0; @@ -542,6 +543,7 @@ public class BatteryStatsHelper { } else { mUsageList.add(app); if (power > mMaxPower) mMaxPower = power; + if (power > mMaxRealPower) mMaxRealPower = power; mComputedPower += power; } if (u.getUid() == 0) { @@ -567,6 +569,7 @@ public class BatteryStatsHelper { osApp.value += power; osApp.values[0] += power; if (osApp.value > mMaxPower) mMaxPower = osApp.value; + if (osApp.value > mMaxRealPower) mMaxRealPower = osApp.value; mComputedPower += power; } } @@ -806,6 +809,7 @@ public class BatteryStatsHelper { private BatterySipper addEntry(DrainType drainType, long time, double power) { mComputedPower += power; + if (power > mMaxRealPower) mMaxRealPower = power; return addEntryNoTotal(drainType, time, power); } @@ -831,6 +835,8 @@ public class BatteryStatsHelper { public double getMaxPower() { return mMaxPower; } + public double getMaxRealPower() { return mMaxRealPower; } + public double getTotalPower() { return mTotalPower; } public double getComputedPower() { return mComputedPower; } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 5b55a24de02c6..ab19ad4c5f385 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6772,7 +6772,10 @@ its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry. Described here are the attributes that can be included in that tag. --> + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 1b6ea951fd397..e4484ada04ebd 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2250,6 +2250,7 @@ + diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0f55b0f981bcb..8b7e0d6b55de7 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4715,6 +4715,28 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public void addPackageDependency(String packageName) { + synchronized (this) { + int callingPid = Binder.getCallingPid(); + if (callingPid == Process.myPid()) { + // Yeah, um, no. + Slog.w(TAG, "Can't addPackageDependency on system process"); + return; + } + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(Binder.getCallingPid()); + } + if (proc != null) { + if (proc.pkgDeps == null) { + proc.pkgDeps = new ArraySet(1); + } + proc.pkgDeps.add(packageName); + } + } + } + /* * The pkg name and app id have to be specified. */ @@ -4911,7 +4933,6 @@ public final class ActivityManagerService extends ActivityManagerNative // Remove all processes this package may have touched: all with the // same UID (except for the system or root user), and all whose name // matches the package name. - final String procNamePrefix = packageName != null ? (packageName + ":") : null; final int NP = mProcessNames.getMap().size(); for (int ip=0; ip apps = mProcessNames.getMap().valueAt(ip); @@ -4947,13 +4968,15 @@ public final class ActivityManagerService extends ActivityManagerNative // that match it. We need to qualify this by the processes // that are running under the specified app and user ID. } else { - if (UserHandle.getAppId(app.uid) != appId) { + final boolean isDep = app.pkgDeps != null + && app.pkgDeps.contains(packageName); + if (!isDep && UserHandle.getAppId(app.uid) != appId) { continue; } if (userId != UserHandle.USER_ALL && app.userId != userId) { continue; } - if (!app.pkgList.containsKey(packageName)) { + if (!app.pkgList.containsKey(packageName) && !isDep) { continue; } } @@ -11030,30 +11053,15 @@ public final class ActivityManagerService extends ActivityManagerNative return errList; } - static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) { - if (adj >= ProcessList.CACHED_APP_MIN_ADJ) { - if (currApp != null) { - currApp.lru = adj - ProcessList.CACHED_APP_MIN_ADJ + 1; - } - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.SERVICE_B_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; - } else if (adj >= ProcessList.HOME_APP_ADJ) { - if (currApp != null) { - currApp.lru = 0; - } - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.SERVICE_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; - } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; - } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; - } else if (adj >= ProcessList.VISIBLE_APP_ADJ) { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; + static int procStateToImportance(int procState, int memAdj, + ActivityManager.RunningAppProcessInfo currApp) { + int imp = ActivityManager.RunningAppProcessInfo.procStateToImportance(procState); + if (imp == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) { + currApp.lru = memAdj; } else { - return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + currApp.lru = 0; } + return imp; } private void fillInProcMemInfo(ProcessRecord app, @@ -11071,7 +11079,8 @@ public final class ActivityManagerService extends ActivityManagerNative } outInfo.lastTrimLevel = app.trimMemoryLevel; int adj = app.curAdj; - outInfo.importance = oomAdjToImportance(adj, outInfo); + int procState = app.curProcState; + outInfo.importance = procStateToImportance(procState, adj, outInfo); outInfo.importanceReasonCode = app.adjTypeCode; outInfo.processState = app.curProcState; } @@ -11098,8 +11107,9 @@ public final class ActivityManagerService extends ActivityManagerNative fillInProcMemInfo(app, currApp); if (app.adjSource instanceof ProcessRecord) { currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid; - currApp.importanceReasonImportance = oomAdjToImportance( - app.adjSourceOom, null); + currApp.importanceReasonImportance = + ActivityManager.RunningAppProcessInfo.procStateToImportance( + app.adjSourceProcState); } else if (app.adjSource instanceof ActivityRecord) { ActivityRecord r = (ActivityRecord)app.adjSource; if (r.app != null) currApp.importanceReasonPid = r.app.pid; @@ -15615,7 +15625,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; app.adjSource = cr.binding.client; - app.adjSourceOom = clientAdj; + app.adjSourceProcState = clientProcState; app.adjTarget = s.name; } } @@ -15636,7 +15646,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; app.adjSource = a; - app.adjSourceOom = adj; + app.adjSourceProcState = procState; app.adjTarget = s.name; } } @@ -15681,7 +15691,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_PROVIDER_IN_USE; app.adjSource = client; - app.adjSourceOom = clientAdj; + app.adjSourceProcState = clientProcState; app.adjTarget = cpr.name; } if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index a20be73f2722d..b33f7b70f9ac8 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -55,6 +55,7 @@ final class ProcessRecord { // List of packages running in the process final ArrayMap pkgList = new ArrayMap(); + ArraySet pkgDeps; // additional packages we have a dependency on IApplicationThread thread; // the actual proc... may be null only if // 'persistent' is true (in which case we // are in the process of launching the app) @@ -124,7 +125,7 @@ final class ProcessRecord { String adjType; // Debugging: primary thing impacting oom_adj. int adjTypeCode; // Debugging: adj code to report to app. Object adjSource; // Debugging: option dependent object. - int adjSourceOom; // Debugging: oom_adj of adjSource's process. + int adjSourceProcState; // Debugging: proc state of adjSource's process. Object adjTarget; // Debugging: target component impacting oom_adj. // contains HistoryRecord objects @@ -195,6 +196,14 @@ final class ProcessRecord { pw.print(pkgList.keyAt(i)); } pw.println("}"); + if (pkgDeps != null) { + pw.print(prefix); pw.print("packageDependencies={"); + for (int i=0; i 0) pw.print(", "); + pw.print(pkgDeps.valueAt(i)); + } + pw.println("}"); + } pw.print(prefix); pw.print("compat="); pw.println(compat); if (instrumentationClass != null || instrumentationProfileFile != null || instrumentationArguments != null) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 1f40c262687a4..54af5d462edf1 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -87,6 +87,10 @@ class VoiceInteractionManagerServiceImpl { public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mLock) { mService = IVoiceInteractionService.Stub.asInterface(service); + try { + mService.ready(); + } catch (RemoteException e) { + } } } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index db43be3696eaf..ab2e8ac6ded4a 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -27,8 +27,8 @@ public class MainInteractionService extends VoiceInteractionService { static final String TAG = "MainInteractionService"; @Override - public void onCreate() { - super.onCreate(); + public void onReady() { + super.onReady(); Log.i(TAG, "Creating " + this); Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError()); Log.i(TAG, "Keyphrase enrollment meta-data: "