diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-02-19 17:02:21 -0800 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2010-02-22 11:27:52 -0800 |
commit | 21f1bd17b2dfe361acbb28453b3f3b1a110932fa (patch) | |
tree | 531c362903a1c327db99630996948da85cdedaf7 /core/java/android | |
parent | 9a56aaf12b462a064e81e02386eca8a1e77fe737 (diff) | |
download | frameworks_base-21f1bd17b2dfe361acbb28453b3f3b1a110932fa.zip frameworks_base-21f1bd17b2dfe361acbb28453b3f3b1a110932fa.tar.gz frameworks_base-21f1bd17b2dfe361acbb28453b3f3b1a110932fa.tar.bz2 |
Fix issue #2438980: Implement package watcher for voice recognizer service setting
I am getting tired of writing package monitor code, realized this is missing in
a number of places, and at this point it has gotten complicated enough that I
don't think anyone actually does it 100% right so:
Introducing PackageMonitor.
Yes there are no Java docs. I am still playing around with just what this
thing is to figure out what makes sense and how people will use it. It is
being used to fix this bug for monitoring voice recognizers (integrating the
code from the settings provider for setting an initial value), to replace
the existing code for monitoring input methods (and fix the bug where we
wouldn't remove an input method from the enabled list when it got
uninstalled), to now monitor live wallpaper package changes (now allowing
us to avoid reverting back to the default live wallpaper when the current
one is updated!), and to monitor device admin changes.
Also includes a fix so you can't uninstall an .apk that is currently enabled
as a device admin.
Also includes a fix where the default time zone was not initialized early
enough which should fix issue #2455507 (Observed Google services frame work crash).
In addition, this finally introduces a mechanism to determine if the
"force stop" button should be enabled, with convenience in PackageMonitor
for system services to handle it. All services have been updated to support
this. There is also new infrastructure for reporting battery usage as an
applicatin error report.
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/ApplicationErrorReport.java | 102 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 2 | ||||
-rw-r--r-- | core/java/android/app/DeviceAdminInfo.java | 14 | ||||
-rw-r--r-- | core/java/android/app/DevicePolicyManager.java | 21 | ||||
-rw-r--r-- | core/java/android/app/IDevicePolicyManager.aidl | 1 | ||||
-rw-r--r-- | core/java/android/content/ComponentName.java | 2 | ||||
-rw-r--r-- | core/java/android/content/Intent.java | 21 | ||||
-rw-r--r-- | core/java/android/os/BatteryStats.java | 85 |
8 files changed, 206 insertions, 42 deletions
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index 832f599..fe81056 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -16,8 +16,16 @@ package android.app; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemProperties; +import android.provider.Settings; import android.util.Printer; import java.io.PrintWriter; import java.io.StringWriter; @@ -38,6 +46,13 @@ import java.io.StringWriter; */ public class ApplicationErrorReport implements Parcelable { + // System property defining error report receiver for system apps + static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps"; + + // System property defining default error report receiver + static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; + + /** * Uninitialized error report. */ @@ -54,8 +69,13 @@ public class ApplicationErrorReport implements Parcelable { public static final int TYPE_ANR = 2; /** + * An error report about an application that's consuming too much battery. + */ + public static final int TYPE_BATTERY = 3; + + /** * Type of this report. Can be one of {@link #TYPE_NONE}, - * {@link #TYPE_CRASH} or {@link #TYPE_ANR}. + * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}. */ public int type; @@ -99,6 +119,11 @@ public class ApplicationErrorReport implements Parcelable { public AnrInfo anrInfo; /** + * Text containing battery usage data. + */ + public String batteryText; + + /** * Create an uninitialized instance of {@link ApplicationErrorReport}. */ public ApplicationErrorReport() { @@ -112,6 +137,68 @@ public class ApplicationErrorReport implements Parcelable { readFromParcel(in); } + public static ComponentName getErrorReportReceiver(Context context, + String packageName, int appFlags) { + // check if error reporting is enabled in secure settings + int enabled = Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.SEND_ACTION_APP_ERROR, 0); + if (enabled == 0) { + return null; + } + + PackageManager pm = context.getPackageManager(); + + // look for receiver in the installer package + String candidate = pm.getInstallerPackageName(packageName); + ComponentName result = getErrorReportReceiver(pm, packageName, candidate); + if (result != null) { + return result; + } + + // if the error app is on the system image, look for system apps + // error receiver + if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { + candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); + result = getErrorReportReceiver(pm, packageName, candidate); + if (result != null) { + return result; + } + } + + // if there is a default receiver, try that + candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY); + return getErrorReportReceiver(pm, packageName, candidate); + } + + /** + * Return activity in receiverPackage that handles ACTION_APP_ERROR. + * + * @param pm PackageManager isntance + * @param errorPackage package which caused the error + * @param receiverPackage candidate package to receive the error + * @return activity component within receiverPackage which handles + * ACTION_APP_ERROR, or null if not found + */ + static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage, + String receiverPackage) { + if (receiverPackage == null || receiverPackage.length() == 0) { + return null; + } + + // break the loop if it's the error report receiver package that crashed + if (receiverPackage.equals(errorPackage)) { + return null; + } + + Intent intent = new Intent(Intent.ACTION_APP_ERROR); + intent.setPackage(receiverPackage); + ResolveInfo info = pm.resolveActivity(intent, 0); + if (info == null || info.activityInfo == null) { + return null; + } + return new ComponentName(receiverPackage, info.activityInfo.name); + } + public void writeToParcel(Parcel dest, int flags) { dest.writeInt(type); dest.writeString(packageName); @@ -127,6 +214,9 @@ public class ApplicationErrorReport implements Parcelable { case TYPE_ANR: anrInfo.writeToParcel(dest, flags); break; + case TYPE_BATTERY: + dest.writeString(batteryText); + break; } } @@ -142,10 +232,17 @@ public class ApplicationErrorReport implements Parcelable { case TYPE_CRASH: crashInfo = new CrashInfo(in); anrInfo = null; + batteryText = null; break; case TYPE_ANR: anrInfo = new AnrInfo(in); crashInfo = null; + batteryText = null; + break; + case TYPE_BATTERY: + batteryText = in.readString(); + anrInfo = null; + crashInfo = null; break; } } @@ -347,6 +444,9 @@ public class ApplicationErrorReport implements Parcelable { case TYPE_ANR: anrInfo.dump(pw, prefix); break; + case TYPE_BATTERY: + pw.println(batteryText); + break; } } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1d004ee..c7c9429 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1146,7 +1146,7 @@ class ContextImpl extends Context { private DevicePolicyManager getDevicePolicyManager() { synchronized (mSync) { if (mDevicePolicyManager == null) { - mDevicePolicyManager = new DevicePolicyManager(this, + mDevicePolicyManager = DevicePolicyManager.create(this, mMainThread.getHandler()); } } diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java index bedf4b4..61e1bb3 100644 --- a/core/java/android/app/DeviceAdminInfo.java +++ b/core/java/android/app/DeviceAdminInfo.java @@ -18,6 +18,7 @@ package android.app; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; import android.content.ComponentName; import android.content.Context; @@ -331,6 +332,19 @@ public final class DeviceAdminInfo implements Parcelable { return res; } + /** @hide */ + public void writePoliciesToXml(XmlSerializer out) + throws IllegalArgumentException, IllegalStateException, IOException { + out.attribute(null, "flags", Integer.toString(mUsesPolicies)); + } + + /** @hide */ + public void readPoliciesFromXml(XmlPullParser parser) + throws XmlPullParserException, IOException { + mUsesPolicies = Integer.parseInt( + parser.getAttributeValue(null, "flags")); + } + public void dump(Printer pw, String prefix) { pw.println(prefix + "Receiver:"); mReceiver.dump(pw, prefix + " "); diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java index d611807..0e8c1ab 100644 --- a/core/java/android/app/DevicePolicyManager.java +++ b/core/java/android/app/DevicePolicyManager.java @@ -49,13 +49,18 @@ public class DevicePolicyManager { private final Handler mHandler; - /*package*/ DevicePolicyManager(Context context, Handler handler) { + private DevicePolicyManager(Context context, Handler handler) { mContext = context; mHandler = handler; mService = IDevicePolicyManager.Stub.asInterface( ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); } + /*package*/ static DevicePolicyManager create(Context context, Handler handler) { + DevicePolicyManager me = new DevicePolicyManager(context, handler); + return me.mService != null ? me : null; + } + /** * Activity action: ask the user to add a new device administrator to the system. * The desired policy is the ComponentName of the policy in the @@ -133,6 +138,20 @@ public class DevicePolicyManager { } /** + * @hide + */ + public boolean packageHasActiveAdmins(String packageName) { + if (mService != null) { + try { + return mService.packageHasActiveAdmins(packageName); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } + + /** * Remove a current administration component. This can only be called * by the application that owns the administration component; if you * try to remove someone else's component, a security exception will be diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl index ae5c4bf..b138720 100644 --- a/core/java/android/app/IDevicePolicyManager.aidl +++ b/core/java/android/app/IDevicePolicyManager.aidl @@ -49,6 +49,7 @@ interface IDevicePolicyManager { void setActiveAdmin(in ComponentName policyReceiver); boolean isAdminActive(in ComponentName policyReceiver); List<ComponentName> getActiveAdmins(); + boolean packageHasActiveAdmins(String packageName); void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result); void removeActiveAdmin(in ComponentName policyReceiver); diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java index c4ba05d..7ca0f01 100644 --- a/core/java/android/content/ComponentName.java +++ b/core/java/android/content/ComponentName.java @@ -126,7 +126,7 @@ public final class ComponentName implements Parcelable, Cloneable, Comparable<Co } /** - * The samee as {@link #flattenToString()}, but abbreviates the class + * The same as {@link #flattenToString()}, but abbreviates the class * name if it is a suffix of the package. The result can still be used * with {@link #unflattenFromString(String)}. * diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1b0437c..607605d 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1316,6 +1316,21 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"; /** + * @hide + * Broadcast Action: Ask system services if there is any reason to + * restart the given package. The data contains the name of the + * package. + * <ul> + * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. + * <li> {@link #EXTRA_PACKAGES} String array of all packages to check. + * </ul> + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART"; + /** * Broadcast Action: The user has restarted a package, and all of its * processes have been killed. All runtime state * associated with it (processes, alarms, notifications, etc) should @@ -2098,6 +2113,7 @@ public class Intent implements Parcelable, Cloneable { * number to call in a {@link android.content.Intent#ACTION_CALL}. */ public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"; + /** * Used as an int extra field in {@link android.content.Intent#ACTION_UID_REMOVED} * intents to supply the uid the package had been assigned. Also an optional @@ -2108,6 +2124,11 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_UID = "android.intent.extra.UID"; /** + * @hide String array of package names. + */ + public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES"; + + /** * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} * intents to indicate whether this represents a full uninstall (removing * both the code and its data) or a partial uninstall (leaving its data, diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index b706c5c..56a05ee 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -750,11 +750,8 @@ public abstract class BatteryStats implements Parcelable { * Checkin server version of dump to produce more compact, computer-readable log. * * NOTE: all times are expressed in 'ms'. - * @param fd - * @param pw - * @param which */ - private final void dumpCheckinLocked(PrintWriter pw, int which) { + public final void dumpCheckinLocked(PrintWriter pw, int which, int reqUid) { final long rawUptime = SystemClock.uptimeMillis() * 1000; final long rawRealtime = SystemClock.elapsedRealtime() * 1000; final long batteryUptime = getBatteryUptime(rawUptime); @@ -856,19 +853,24 @@ public abstract class BatteryStats implements Parcelable { getDischargeCurrentLevel()); } - Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); - if (kernelWakelocks.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { - sb.setLength(0); - printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, ""); - - dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), - sb.toString()); + if (reqUid < 0) { + Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { + sb.setLength(0); + printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, ""); + + dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(), + sb.toString()); + } } } for (int iu = 0; iu < NU; iu++) { final int uid = uidStats.keyAt(iu); + if (reqUid >= 0 && uid != reqUid) { + continue; + } Uid u = uidStats.valueAt(iu); // Dump Network stats per uid, if any long rx = u.getTcpBytesReceived(which); @@ -987,7 +989,7 @@ public abstract class BatteryStats implements Parcelable { } @SuppressWarnings("unused") - private final void dumpLocked(PrintWriter pw, String prefix, int which) { + public final void dumpLocked(PrintWriter pw, String prefix, int which, int reqUid) { final long rawUptime = SystemClock.uptimeMillis() * 1000; final long rawRealtime = SystemClock.elapsedRealtime() * 1000; final long batteryUptime = getBatteryUptime(rawUptime); @@ -1063,23 +1065,25 @@ public abstract class BatteryStats implements Parcelable { long fullWakeLockTimeTotalMicros = 0; long partialWakeLockTimeTotalMicros = 0; - Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); - if (kernelWakelocks.size() > 0) { - for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { - - String linePrefix = ": "; - sb.setLength(0); - sb.append(prefix); - sb.append(" Kernel Wake lock "); - sb.append(ent.getKey()); - linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, - linePrefix); - if (!linePrefix.equals(": ")) { - sb.append(" realtime"); - } else { - sb.append(": (nothing executed)"); + if (reqUid < 0) { + Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats(); + if (kernelWakelocks.size() > 0) { + for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) { + + String linePrefix = ": "; + sb.setLength(0); + sb.append(prefix); + sb.append(" Kernel Wake lock "); + sb.append(ent.getKey()); + linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which, + linePrefix); + if (!linePrefix.equals(": ")) { + sb.append(" realtime"); + } else { + sb.append(": (nothing executed)"); + } + pw.println(sb.toString()); } - pw.println(sb.toString()); } } @@ -1212,7 +1216,12 @@ public abstract class BatteryStats implements Parcelable { for (int iu=0; iu<NU; iu++) { final int uid = uidStats.keyAt(iu); + if (reqUid >= 0 && uid != reqUid) { + continue; + } + Uid u = uidStats.valueAt(iu); + pw.println(prefix + " #" + uid + ":"); boolean uidActivity = false; @@ -1421,16 +1430,16 @@ public abstract class BatteryStats implements Parcelable { pw.println("Total Statistics (Current and Historic):"); pw.println(" System starts: " + getStartCount() + ", currently on battery: " + getIsOnBattery()); - dumpLocked(pw, "", STATS_TOTAL); + dumpLocked(pw, "", STATS_TOTAL, -1); pw.println(""); pw.println("Last Run Statistics (Previous run of system):"); - dumpLocked(pw, "", STATS_LAST); + dumpLocked(pw, "", STATS_LAST, -1); pw.println(""); pw.println("Current Battery Statistics (Currently running system):"); - dumpLocked(pw, "", STATS_CURRENT); + dumpLocked(pw, "", STATS_CURRENT, -1); pw.println(""); pw.println("Unplugged Statistics (Since last unplugged from power):"); - dumpLocked(pw, "", STATS_UNPLUGGED); + dumpLocked(pw, "", STATS_UNPLUGGED, -1); } @SuppressWarnings("unused") @@ -1445,13 +1454,13 @@ public abstract class BatteryStats implements Parcelable { } if (isUnpluggedOnly) { - dumpCheckinLocked(pw, STATS_UNPLUGGED); + dumpCheckinLocked(pw, STATS_UNPLUGGED, -1); } else { - dumpCheckinLocked(pw, STATS_TOTAL); - dumpCheckinLocked(pw, STATS_LAST); - dumpCheckinLocked(pw, STATS_UNPLUGGED); - dumpCheckinLocked(pw, STATS_CURRENT); + dumpCheckinLocked(pw, STATS_TOTAL, -1); + dumpCheckinLocked(pw, STATS_LAST, -1); + dumpCheckinLocked(pw, STATS_UNPLUGGED, -1); + dumpCheckinLocked(pw, STATS_CURRENT, -1); } } |