diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-02-22 12:18:01 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-02-22 12:18:01 -0800 |
commit | 7e31e0c351a3b2bb70ee5507b34f1c72d62b56d7 (patch) | |
tree | 5b177c59b9ab317e3951b6369a5676080afd9788 | |
parent | ec2c88d835dac156be0d14bd2b73cf3825e2e164 (diff) | |
parent | 21f1bd17b2dfe361acbb28453b3f3b1a110932fa (diff) | |
download | frameworks_base-7e31e0c351a3b2bb70ee5507b34f1c72d62b56d7.zip frameworks_base-7e31e0c351a3b2bb70ee5507b34f1c72d62b56d7.tar.gz frameworks_base-7e31e0c351a3b2bb70ee5507b34f1c72d62b56d7.tar.bz2 |
Merge "Fix issue #2438980: Implement package watcher for voice recognizer service setting"
23 files changed, 1161 insertions, 375 deletions
diff --git a/api/current.xml b/api/current.xml index 33a8020..a753165 100644 --- a/api/current.xml +++ b/api/current.xml @@ -23748,7 +23748,7 @@ > <parameter name="parcel" type="android.os.Parcel"> </parameter> -<parameter name="flags" type="int"> +<parameter name="flagz" type="int"> </parameter> </method> <field name="CREATOR" 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); } } diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java new file mode 100644 index 0000000..343041f --- /dev/null +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -0,0 +1,287 @@ +package com.android.internal.content; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; + +import java.util.HashSet; + +/** + * Helper class for monitoring the state of packages: adding, removing, + * updating, and disappearing and reappearing on the SD card. + */ +public abstract class PackageMonitor extends android.content.BroadcastReceiver { + static final IntentFilter sPackageFilt = new IntentFilter(); + static final IntentFilter sNonDataFilt = new IntentFilter(); + static final IntentFilter sExternalFilt = new IntentFilter(); + + static { + sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); + sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); + sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); + sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); + sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); + sPackageFilt.addAction(Intent.ACTION_UID_REMOVED); + sPackageFilt.addDataScheme("package"); + sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); + sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + } + + final HashSet<String> mUpdatingPackages = new HashSet<String>(); + + Context mRegisteredContext; + String[] mDisappearingPackages; + String[] mAppearingPackages; + String[] mModifiedPackages; + int mChangeType; + boolean mSomePackagesChanged; + + String[] mTempArray = new String[1]; + + public void register(Context context, boolean externalStorage) { + if (mRegisteredContext != null) { + throw new IllegalStateException("Already registered"); + } + mRegisteredContext = context; + context.registerReceiver(this, sPackageFilt); + context.registerReceiver(this, sNonDataFilt); + if (externalStorage) { + context.registerReceiver(this, sExternalFilt); + } + } + + public void unregister() { + if (mRegisteredContext == null) { + throw new IllegalStateException("Not registered"); + } + mRegisteredContext.unregisterReceiver(this); + mRegisteredContext = null; + } + + //not yet implemented + boolean isPackageUpdating(String packageName) { + synchronized (mUpdatingPackages) { + return mUpdatingPackages.contains(packageName); + } + } + + public void onBeginPackageChanges() { + } + + public void onPackageAdded(String packageName, int uid) { + } + + public void onPackageRemoved(String packageName, int uid) { + } + + public void onPackageUpdateStarted(String packageName, int uid) { + } + + public void onPackageUpdateFinished(String packageName, int uid) { + } + + public void onPackageChanged(String packageName, int uid, String[] components) { + } + + public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { + return false; + } + + public void onUidRemoved(int uid) { + } + + public void onPackagesAvailable(String[] packages) { + } + + public void onPackagesUnavailable(String[] packages) { + } + + public static final int PACKAGE_UNCHANGED = 0; + public static final int PACKAGE_UPDATING = 1; + public static final int PACKAGE_TEMPORARY_CHANGE = 2; + public static final int PACKAGE_PERMANENT_CHANGE = 3; + + public void onPackageDisappeared(String packageName, int reason) { + } + + public void onPackageAppeared(String packageName, int reason) { + } + + public void onPackageModified(String packageName) { + } + + public boolean didSomePackagesChange() { + return mSomePackagesChanged; + } + + public int isPackageAppearing(String packageName) { + if (mAppearingPackages != null) { + for (int i=mAppearingPackages.length-1; i>=0; i--) { + if (packageName.equals(mAppearingPackages[i])) { + return mChangeType; + } + } + } + return PACKAGE_UNCHANGED; + } + + public boolean anyPackagesAppearing() { + return mAppearingPackages != null; + } + + public int isPackageDisappearing(String packageName) { + if (mDisappearingPackages != null) { + for (int i=mDisappearingPackages.length-1; i>=0; i--) { + if (packageName.equals(mDisappearingPackages[i])) { + return mChangeType; + } + } + } + return PACKAGE_UNCHANGED; + } + + public boolean anyPackagesDisappearing() { + return mDisappearingPackages != null; + } + + public boolean isPackageModified(String packageName) { + if (mModifiedPackages != null) { + for (int i=mModifiedPackages.length-1; i>=0; i--) { + if (packageName.equals(mModifiedPackages[i])) { + return true; + } + } + } + return false; + } + + public void onSomePackagesChanged() { + } + + public void onFinishPackageChanges() { + } + + String getPackageName(Intent intent) { + Uri uri = intent.getData(); + String pkg = uri != null ? uri.getSchemeSpecificPart() : null; + return pkg; + } + + @Override + public void onReceive(Context context, Intent intent) { + onBeginPackageChanges(); + + mDisappearingPackages = mAppearingPackages = null; + mSomePackagesChanged = false; + + String action = intent.getAction(); + if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + String pkg = getPackageName(intent); + int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); + // We consider something to have changed regardless of whether + // this is just an update, because the update is now finished + // and the contents of the package may have changed. + mSomePackagesChanged = true; + if (pkg != null) { + mAppearingPackages = mTempArray; + mTempArray[0] = pkg; + if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + mModifiedPackages = mTempArray; + mChangeType = PACKAGE_UPDATING; + onPackageUpdateFinished(pkg, uid); + onPackageModified(pkg); + } else { + mChangeType = PACKAGE_PERMANENT_CHANGE; + onPackageAdded(pkg, uid); + } + onPackageAppeared(pkg, mChangeType); + if (mChangeType == PACKAGE_UPDATING) { + synchronized (mUpdatingPackages) { + mUpdatingPackages.remove(pkg); + } + } + } + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + String pkg = getPackageName(intent); + int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); + if (pkg != null) { + mDisappearingPackages = mTempArray; + mTempArray[0] = pkg; + if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + mChangeType = PACKAGE_UPDATING; + synchronized (mUpdatingPackages) { + //not used for now + //mUpdatingPackages.add(pkg); + } + onPackageUpdateStarted(pkg, uid); + } else { + mChangeType = PACKAGE_PERMANENT_CHANGE; + // We only consider something to have changed if this is + // not a replace; for a replace, we just need to consider + // it when it is re-added. + mSomePackagesChanged = true; + onPackageRemoved(pkg, uid); + } + onPackageDisappeared(pkg, mChangeType); + } + } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { + String pkg = getPackageName(intent); + int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); + String[] components = intent.getStringArrayExtra( + Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); + if (pkg != null) { + mModifiedPackages = mTempArray; + mTempArray[0] = pkg; + onPackageChanged(pkg, uid, components); + // XXX Don't want this to always cause mSomePackagesChanged, + // since it can happen a fair amount. + onPackageModified(pkg); + } + } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { + mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); + mChangeType = PACKAGE_TEMPORARY_CHANGE; + boolean canRestart = onHandleForceStop(intent, + mDisappearingPackages, + intent.getIntExtra(Intent.EXTRA_UID, 0), false); + if (canRestart) setResultCode(Activity.RESULT_OK); + } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) { + mDisappearingPackages = new String[] {getPackageName(intent)}; + mChangeType = PACKAGE_TEMPORARY_CHANGE; + onHandleForceStop(intent, mDisappearingPackages, + intent.getIntExtra(Intent.EXTRA_UID, 0), true); + } else if (Intent.ACTION_UID_REMOVED.equals(action)) { + onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0)); + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { + String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + mAppearingPackages = pkgList; + mChangeType = PACKAGE_TEMPORARY_CHANGE; + mSomePackagesChanged = true; + if (pkgList != null) { + onPackagesAvailable(pkgList); + for (int i=0; i<pkgList.length; i++) { + onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); + } + } + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + mDisappearingPackages = pkgList; + mChangeType = PACKAGE_TEMPORARY_CHANGE; + mSomePackagesChanged = true; + if (pkgList != null) { + onPackagesUnavailable(pkgList); + for (int i=0; i<pkgList.length; i++) { + onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); + } + } + } + + if (mSomePackagesChanged) { + onSomePackagesChanged(); + } + + onFinishPackageChanges(); + } +} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index cf34d4e..5b616b3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -618,18 +618,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { if (upgradeVersion == 48) { /* - * Adding a new setting for which voice recognition service to use. + * Default recognition service no longer initialized here, + * moved to RecognitionManagerService. */ - db.beginTransaction(); - try { - SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)" - + " VALUES(?,?);"); - loadVoiceRecognitionServiceSetting(stmt); - stmt.close(); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } upgradeVersion = 49; } @@ -1028,8 +1019,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, R.bool.def_mount_ums_notify_enabled); - loadVoiceRecognitionServiceSetting(stmt); - stmt.close(); } @@ -1041,32 +1030,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { R.string.def_backup_transport); } - /** - * Introduced in database version 49. - */ - private void loadVoiceRecognitionServiceSetting(SQLiteStatement stmt) { - String selectedService = null; - List<ResolveInfo> availableRecognitionServices = - mContext.getPackageManager().queryIntentServices( - new Intent(RecognitionService.SERVICE_INTERFACE), 0); - int numAvailable = availableRecognitionServices.size(); - - if (numAvailable == 0) { - Log.w(TAG, "no available voice recognition services found"); - } else { - if (numAvailable > 1) { - Log.w(TAG, "more than one voice recognition service found, picking first"); - } - - ServiceInfo serviceInfo = availableRecognitionServices.get(0).serviceInfo; - selectedService = - new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToString(); - } - - loadSetting(stmt, Settings.Secure.VOICE_RECOGNITION_SERVICE, - selectedService == null ? "" : selectedService); - } - private void loadSetting(SQLiteStatement stmt, String key, Object value) { stmt.bindString(1, key); stmt.bindString(2, value.toString()); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 4080a6a..db802d3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -20,7 +20,6 @@ import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import java.util.Random; import android.backup.BackupManager; import android.content.ContentProvider; @@ -30,14 +29,11 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; -import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.ParcelFileDescriptor; -import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.DrmStore; import android.provider.MediaStore; diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index 477ea0c..c55dcb3 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import com.android.internal.content.PackageMonitor; import com.android.internal.os.HandlerCaller; import com.android.internal.os.HandlerCaller.SomeArgs; @@ -56,6 +57,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -145,13 +147,58 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void registerPackageChangeAndBootCompletedBroadcastReceiver() { Context context = mContext; - BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + PackageMonitor monitor = new PackageMonitor() { @Override - public void onReceive(Context context, Intent intent) { + public void onSomePackagesChanged() { synchronized (mLock) { populateAccessibilityServiceListLocked(); + manageServicesLocked(); + } + } + + @Override + public boolean onHandleForceStop(Intent intent, String[] packages, + int uid, boolean doit) { + synchronized (mLock) { + boolean changed = false; + Iterator<ComponentName> it = mEnabledServices.iterator(); + while (it.hasNext()) { + ComponentName comp = it.next(); + String compPkg = comp.getPackageName(); + for (String pkg : packages) { + if (compPkg.equals(pkg)) { + if (!doit) { + return true; + } + it.remove(); + changed = true; + } + } + } + if (changed) { + it = mEnabledServices.iterator(); + StringBuilder str = new StringBuilder(); + while (it.hasNext()) { + if (str.length() > 0) { + str.append(':'); + } + str.append(it.next().flattenToShortString()); + } + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + str.toString()); + manageServicesLocked(); + } + return false; + } + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) { + synchronized (mLock) { + populateAccessibilityServiceListLocked(); - if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) { // get the accessibility enabled setting on boot mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; @@ -160,29 +207,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mIsEnabled) { updateClientsLocked(); } - } - manageServicesLocked(); + manageServicesLocked(); + } + + return; } + + super.onReceive(context, intent); } }; // package changes - IntentFilter packageFilter = new IntentFilter(); - packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); - packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - packageFilter.addDataScheme("package"); - context.registerReceiver(broadcastReceiver, packageFilter); - // Register for events related to sdcard installation. - IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(broadcastReceiver, sdFilter); + monitor.register(context, true); // boot completed IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - mContext.registerReceiver(broadcastReceiver, bootFiler); + mContext.registerReceiver(monitor, bootFiler); } /** @@ -529,8 +570,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; splitter.setString(servicesValue); while (splitter.hasNext()) { - ComponentName enabledService = ComponentName.unflattenFromString(splitter.next()); - enabledServices.add(enabledService); + String str = splitter.next(); + if (str == null || str.length() <= 0) { + continue; + } + ComponentName enabledService = ComponentName.unflattenFromString(str); + if (enabledService != null) { + enabledServices.add(enabledService); + } } } } diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 44cc0bb..f480209 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.app.Activity; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.IAlarmManager; @@ -344,6 +345,22 @@ class AlarmManagerService extends IAlarmManager.Stub { } } + public boolean lookForPackageLocked(String packageName) { + return lookForPackageLocked(mRtcWakeupAlarms, packageName) + || lookForPackageLocked(mRtcAlarms, packageName) + || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName) + || lookForPackageLocked(mElapsedRealtimeAlarms, packageName); + } + + private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) { + for (int i=alarmList.size()-1; i>=0; i--) { + if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) { + return true; + } + } + return false; + } + private ArrayList<Alarm> getAlarmList(int type) { switch (type) { case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; @@ -778,6 +795,7 @@ class AlarmManagerService extends IAlarmManager.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); + filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); filter.addDataScheme("package"); mContext.registerReceiver(this, filter); // Register for events related to sdcard installation. @@ -791,7 +809,16 @@ class AlarmManagerService extends IAlarmManager.Stub { synchronized (mLock) { String action = intent.getAction(); String pkgList[] = null; - if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); + for (String packageName : pkgList) { + if (lookForPackageLocked(packageName)) { + setResultCode(Activity.RESULT_OK); + return; + } + } + return; + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri data = intent.getData(); diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index a267e0f..ac65aa9 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -17,6 +17,8 @@ package com.android.server; import com.android.common.FastXmlSerializer; +import com.android.common.XmlUtils; +import com.android.internal.content.PackageMonitor; import com.android.internal.widget.LockPatternUtils; import org.xmlpull.v1.XmlPullParser; @@ -34,6 +36,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.PackageManager.NameNotFoundException; import android.os.Binder; import android.os.IBinder; import android.os.IPowerManager; @@ -58,9 +61,10 @@ import java.util.List; * Implementation of the device policy APIs. */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { - private static final String TAG = "DevicePolicyManagerService"; + static final String TAG = "DevicePolicyManagerService"; - private final Context mContext; + final Context mContext; + final MyPackageMonitor mMonitor; IPowerManager mIPowerManager; @@ -89,6 +93,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { void writeToXml(XmlSerializer out) throws IllegalArgumentException, IllegalStateException, IOException { + out.startTag(null, "policies"); + info.writePoliciesToXml(out); + out.endTag(null, "policies"); if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { out.startTag(null, "password-quality"); out.attribute(null, "value", Integer.toString(passwordQuality)); @@ -121,7 +128,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { continue; } String tag = parser.getName(); - if ("password-quality".equals(tag)) { + if ("policies".equals(tag)) { + info.readPoliciesFromXml(parser); + } else if ("password-quality".equals(tag)) { passwordQuality = Integer.parseInt( parser.getAttributeValue(null, "value")); } else if ("min-password-length".equals(tag)) { @@ -133,6 +142,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("max-failed-password-wipe".equals(tag)) { maximumFailedPasswordsForWipe = Integer.parseInt( parser.getAttributeValue(null, "value")); + } else { + Log.w(TAG, "Unknown admin tag: " + tag); + } + XmlUtils.skipCurrentTag(parser); + } + } + } + + class MyPackageMonitor extends PackageMonitor { + public void onSomePackagesChanged() { + synchronized (DevicePolicyManagerService.this) { + for (int i=mAdminList.size()-1; i>=0; i--) { + ActiveAdmin aa = mAdminList.get(i); + int change = isPackageDisappearing(aa.info.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + Log.w(TAG, "Admin unexpectedly uninstalled: " + + aa.info.getComponent()); + mAdminList.remove(i); + } else if (isPackageModified(aa.info.getPackageName())) { + try { + mContext.getPackageManager().getReceiverInfo( + aa.info.getComponent(), 0); + } catch (NameNotFoundException e) { + Log.w(TAG, "Admin package change removed component: " + + aa.info.getComponent()); + mAdminList.remove(i); + } + } } } } @@ -143,6 +181,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ public DevicePolicyManagerService(Context context) { mContext = context; + mMonitor = new MyPackageMonitor(); + mMonitor.register(context, true); } private IPowerManager getIPowerManager() { @@ -336,6 +376,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if ("failed-password-attempts".equals(tag)) { mFailedPasswordAttempts = Integer.parseInt( parser.getAttributeValue(null, "value")); + XmlUtils.skipCurrentTag(parser); + } else { + Log.w(TAG, "Unknown tag: " + tag); + XmlUtils.skipCurrentTag(parser); } } } catch (NullPointerException e) { @@ -420,6 +464,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + public boolean packageHasActiveAdmins(String packageName) { + synchronized (this) { + final int N = mAdminList.size(); + for (int i=0; i<N; i++) { + if (mAdminList.get(i).info.getPackageName().equals(packageName)) { + return true; + } + } + return false; + } + } + public void removeActiveAdmin(ComponentName adminReceiver) { synchronized (this) { ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 5e96a2f..59d4c9b 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import com.android.internal.content.PackageMonitor; import com.android.internal.os.HandlerCaller; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethod; @@ -48,7 +49,6 @@ import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; -import android.net.Uri; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -332,51 +332,68 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - class PackageReceiver extends android.content.BroadcastReceiver { + class MyPackageMonitor extends PackageMonitor { + @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - String pkgList[] = null; - if (Intent.ACTION_PACKAGE_ADDED.equals(action) || - Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - Uri uri = intent.getData(); - String pkg = uri != null ? uri.getSchemeSpecificPart() : null; - if (pkg != null) { - pkgList = new String[] { pkg }; + public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { + synchronized (mMethodMap) { + String curInputMethodId = Settings.Secure.getString(mContext + .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); + final int N = mMethodList.size(); + if (curInputMethodId != null) { + for (int i=0; i<N; i++) { + InputMethodInfo imi = mMethodList.get(i); + if (imi.getId().equals(curInputMethodId)) { + for (String pkg : packages) { + if (imi.getPackageName().equals(pkg)) { + if (!doit) { + return true; + } + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, ""); + chooseNewDefaultIMELocked(); + return true; + } + } + } + } } - } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) || - Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { - pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } - if (pkgList == null || pkgList.length == 0) { - return; - } - synchronized (mMethodMap) { - buildInputMethodListLocked(mMethodList, mMethodMap); + return false; + } + @Override + public void onSomePackagesChanged() { + synchronized (mMethodMap) { InputMethodInfo curIm = null; - String curInputMethodId = Settings.Secure.getString(context + String curInputMethodId = Settings.Secure.getString(mContext .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); final int N = mMethodList.size(); if (curInputMethodId != null) { for (int i=0; i<N; i++) { - if (mMethodList.get(i).getId().equals(curInputMethodId)) { - curIm = mMethodList.get(i); + InputMethodInfo imi = mMethodList.get(i); + if (imi.getId().equals(curInputMethodId)) { + curIm = imi; + } + int change = isPackageDisappearing(imi.getPackageName()); + if (change == PACKAGE_TEMPORARY_CHANGE + || change == PACKAGE_PERMANENT_CHANGE) { + Log.i(TAG, "Input method uninstalled, disabling: " + + imi.getComponent()); + setInputMethodEnabledLocked(imi.getId(), false); } } } + buildInputMethodListLocked(mMethodList, mMethodMap); + boolean changed = false; if (curIm != null) { - boolean foundPkg = false; - for (String pkg : pkgList) { - if (curIm.getPackageName().equals(pkg)) { - foundPkg = true; - break; - } - } - if (foundPkg) { + int change = isPackageDisappearing(curIm.getPackageName()); + if (change == PACKAGE_TEMPORARY_CHANGE + || change == PACKAGE_PERMANENT_CHANGE) { ServiceInfo si = null; try { si = mContext.getPackageManager().getServiceInfo( @@ -387,7 +404,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Uh oh, current input method is no longer around! // Pick another one... Log.i(TAG, "Current input method removed: " + curInputMethodId); - if (!chooseNewDefaultIME()) { + if (!chooseNewDefaultIMELocked()) { changed = true; curIm = null; curInputMethodId = ""; @@ -397,16 +414,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub curInputMethodId); } } - - } else if (curIm == null) { - // We currently don't have a default input method... is - // one now available? - changed = chooseNewDefaultIME(); } + } + + if (curIm == null) { + // We currently don't have a default input method... is + // one now available? + changed = chooseNewDefaultIMELocked(); + } - if (changed) { - updateFromSettingsLocked(); - } + if (changed) { + updateFromSettingsLocked(); } } } @@ -438,19 +456,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } }); - PackageReceiver mBroadcastReceiver = new PackageReceiver(); - IntentFilter packageFilt = new IntentFilter(); - packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); - packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); - packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); - packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); - packageFilt.addDataScheme("package"); - mContext.registerReceiver(mBroadcastReceiver, packageFilt); - // Register for events related to sdcard installation. - IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(mBroadcastReceiver, sdFilter); + (new MyPackageMonitor()).register(mContext, true); IntentFilter screenOnOffFilt = new IntentFilter(); screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON); @@ -1385,7 +1391,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub & ApplicationInfo.FLAG_SYSTEM) != 0; } - private boolean chooseNewDefaultIME() { + private boolean chooseNewDefaultIMELocked() { List<InputMethodInfo> enabled = getEnabledInputMethodListLocked(); if (enabled != null && enabled.size() > 0) { Settings.Secure.putString(mContext.getContentResolver(), @@ -1446,7 +1452,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub String defaultIme = Settings.Secure.getString(mContext .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); if (!map.containsKey(defaultIme)) { - if (chooseNewDefaultIME()) { + if (chooseNewDefaultIMELocked()) { updateFromSettingsLocked(); } } @@ -1557,90 +1563,94 @@ public class InputMethodManagerService extends IInputMethodManager.Stub "Requires permission " + android.Manifest.permission.WRITE_SECURE_SETTINGS); } - + long ident = Binder.clearCallingIdentity(); try { - // Make sure this is a valid input method. - InputMethodInfo imm = mMethodMap.get(id); - if (imm == null) { - if (imm == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); - } - } + return setInputMethodEnabledLocked(id, enabled); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + boolean setInputMethodEnabledLocked(String id, boolean enabled) { + // Make sure this is a valid input method. + InputMethodInfo imm = mMethodMap.get(id); + if (imm == null) { + if (imm == null) { + throw new IllegalArgumentException("Unknown id: " + mCurMethodId); + } + } - StringBuilder builder = new StringBuilder(256); - - boolean removed = false; - String firstId = null; - - // Look through the currently enabled input methods. - String enabledStr = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS); - if (enabledStr != null) { - final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(enabledStr); - while (splitter.hasNext()) { - String curId = splitter.next(); - if (curId.equals(id)) { - if (enabled) { - // We are enabling this input method, but it is - // already enabled. Nothing to do. The previous - // state was enabled. - return true; - } - // We are disabling this input method, and it is - // currently enabled. Skip it to remove from the - // new list. - removed = true; - } else if (!enabled) { - // We are building a new list of input methods that - // doesn't contain the given one. - if (firstId == null) firstId = curId; - if (builder.length() > 0) builder.append(':'); - builder.append(curId); - } - } - } + StringBuilder builder = new StringBuilder(256); - if (!enabled) { - if (!removed) { - // We are disabling the input method but it is already - // disabled. Nothing to do. The previous state was - // disabled. - return false; - } - // Update the setting with the new list of input methods. - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); - // We the disabled input method is currently selected, switch - // to another one. - String selId = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); - if (id.equals(selId)) { - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - firstId != null ? firstId : ""); - } - // Previous state was enabled. - return true; - } + boolean removed = false; + String firstId = null; - // Add in the newly enabled input method. - if (enabledStr == null || enabledStr.length() == 0) { - enabledStr = id; - } else { - enabledStr = enabledStr + ':' + id; + // Look through the currently enabled input methods. + String enabledStr = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS); + if (enabledStr != null) { + final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(enabledStr); + while (splitter.hasNext()) { + String curId = splitter.next(); + if (curId.equals(id)) { + if (enabled) { + // We are enabling this input method, but it is + // already enabled. Nothing to do. The previous + // state was enabled. + return true; + } + // We are disabling this input method, and it is + // currently enabled. Skip it to remove from the + // new list. + removed = true; + } else if (!enabled) { + // We are building a new list of input methods that + // doesn't contain the given one. + if (firstId == null) firstId = curId; + if (builder.length() > 0) builder.append(':'); + builder.append(curId); } + } + } - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, enabledStr); - - // Previous state was disabled. + if (!enabled) { + if (!removed) { + // We are disabling the input method but it is already + // disabled. Nothing to do. The previous state was + // disabled. return false; - } finally { - Binder.restoreCallingIdentity(ident); } + // Update the setting with the new list of input methods. + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); + // We the disabled input method is currently selected, switch + // to another one. + String selId = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD); + if (id.equals(selId)) { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + firstId != null ? firstId : ""); + } + // Previous state was enabled. + return true; + } + + // Add in the newly enabled input method. + if (enabledStr == null || enabledStr.length() == 0) { + enabledStr = id; + } else { + enabledStr = enabledStr + ':' + id; } + + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ENABLED_INPUT_METHODS, enabledStr); + + // Previous state was disabled. + return false; } // ---------------------------------------------------------------------- diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 004fcf1..dd351be 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -27,6 +27,7 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; +import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -506,6 +507,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Register for Package Manager updates intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); + intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); mContext.registerReceiver(mBroadcastReceiver, intentFilter); IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); @@ -1539,8 +1541,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - - if (action.equals(Intent.ACTION_PACKAGE_REMOVED) + boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART); + if (queryRestart + || action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { synchronized (mLock) { @@ -1560,6 +1563,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run for (int j=i.size()-1; j>=0; j--) { UpdateRecord ur = i.get(j); if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { + if (queryRestart) { + setResultCode(Activity.RESULT_OK); + return; + } if (removedRecs == null) { removedRecs = new ArrayList<Receiver>(); } @@ -1572,6 +1579,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run ArrayList<ProximityAlert> removedAlerts = null; for (ProximityAlert i : mProximityAlerts.values()) { if (i.mUid == uid) { + if (queryRestart) { + setResultCode(Activity.RESULT_OK); + return; + } if (removedAlerts == null) { removedAlerts = new ArrayList<ProximityAlert>(); } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 3657133..3c43352 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -307,6 +307,8 @@ class NotificationManagerService extends INotificationManager.Stub public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + boolean queryRestart = false; + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0); int level = intent.getIntExtra("level", -1); @@ -330,10 +332,13 @@ class NotificationManagerService extends INotificationManager.Stub updateAdbNotification(); } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) + || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { String pkgList[] = null; if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } else if (queryRestart) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); } else { Uri uri = intent.getData(); if (uri == null) { @@ -347,7 +352,7 @@ class NotificationManagerService extends INotificationManager.Stub } if (pkgList != null && (pkgList.length > 0)) { for (String pkgName : pkgList) { - cancelAllNotificationsInt(pkgName, 0, 0); + cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart); } } } else if (action.equals(Intent.ACTION_SCREEN_ON)) { @@ -436,11 +441,15 @@ class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_UMS_CONNECTED); filter.addAction(Intent.ACTION_UMS_DISCONNECTED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); mContext.registerReceiver(mIntentReceiver, filter); + IntentFilter pkgFilter = new IntentFilter(); + pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); + pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); + pkgFilter.addDataScheme("package"); + mContext.registerReceiver(mIntentReceiver, pkgFilter); IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mIntentReceiver, sdFilter); @@ -920,8 +929,8 @@ class NotificationManagerService extends INotificationManager.Stub * Cancels all notifications from a given package that have all of the * {@code mustHaveFlags}. */ - void cancelAllNotificationsInt(String pkg, int mustHaveFlags, - int mustNotHaveFlags) { + boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags, + int mustNotHaveFlags, boolean doit) { EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags); synchronized (mNotificationList) { @@ -938,13 +947,17 @@ class NotificationManagerService extends INotificationManager.Stub if (!r.pkg.equals(pkg)) { continue; } + canceledSomething = true; + if (!doit) { + return true; + } mNotificationList.remove(i); cancelNotificationLocked(r); - canceledSomething = true; } if (canceledSomething) { updateLightsLocked(); } + return canceledSomething; } } @@ -966,7 +979,7 @@ class NotificationManagerService extends INotificationManager.Stub // Calling from user space, don't allow the canceling of actively // running foreground services. - cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE); + cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true); } void checkIncomingCall(String pkg) { diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 38d8615..4fdcd59 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -28,7 +28,9 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.app.ActivityManagerNative; +import android.app.DevicePolicyManager; import android.app.IActivityManager; +import android.app.IDevicePolicyManager; import android.backup.IBackupManager; import android.content.ComponentName; import android.content.Context; @@ -5594,6 +5596,16 @@ class PackageManagerService extends IPackageManager.Stub { PackageRemovedInfo info = new PackageRemovedInfo(); boolean res; + IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); + try { + if (dpm != null && dpm.packageHasActiveAdmins(packageName)) { + Log.w(TAG, "Not removing package " + packageName + ": has active device admin"); + return false; + } + } catch (RemoteException e) { + } + synchronized (mInstallLock) { res = deletePackageLI(packageName, deleteCodeAndResources, flags, info); } diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java new file mode 100644 index 0000000..7305b07 --- /dev/null +++ b/services/java/com/android/server/RecognitionManagerService.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2010 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.server; + +import com.android.internal.content.PackageMonitor; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Binder; +import android.provider.Settings; +import android.speech.RecognitionService; +import android.text.TextUtils; +import android.util.Log; + +import java.util.List; + +public class RecognitionManagerService extends Binder { + final static String TAG = "RecognitionManagerService"; + + final Context mContext; + final MyPackageMonitor mMonitor; + + class MyPackageMonitor extends PackageMonitor { + public void onSomePackagesChanged() { + ComponentName comp = getCurRecognizer(); + if (comp == null) { + if (anyPackagesAppearing()) { + comp = findAvailRecognizer(null); + if (comp != null) { + setCurRecognizer(comp); + } + } + return; + } + + int change = isPackageDisappearing(comp.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + setCurRecognizer(findAvailRecognizer(null)); + + } else if (isPackageModified(comp.getPackageName())) { + setCurRecognizer(findAvailRecognizer(comp.getPackageName())); + } + } + } + + RecognitionManagerService(Context context) { + mContext = context; + mMonitor = new MyPackageMonitor(); + mMonitor.register(context, true); + } + + public void systemReady() { + ComponentName comp = getCurRecognizer(); + if (comp != null) { + // See if the current recognizer is no longer available. + try { + mContext.getPackageManager().getServiceInfo(comp, 0); + } catch (NameNotFoundException e) { + setCurRecognizer(null); + } + } else { + comp = findAvailRecognizer(null); + if (comp != null) { + setCurRecognizer(comp); + } + } + } + + ComponentName findAvailRecognizer(String prefPackage) { + List<ResolveInfo> available = + mContext.getPackageManager().queryIntentServices( + new Intent(RecognitionService.SERVICE_INTERFACE), 0); + int numAvailable = available.size(); + + if (numAvailable == 0) { + Log.w(TAG, "no available voice recognition services found"); + return null; + } else { + if (prefPackage != null) { + for (int i=0; i<numAvailable; i++) { + ServiceInfo serviceInfo = available.get(i).serviceInfo; + if (prefPackage.equals(serviceInfo.packageName)) { + return new ComponentName(serviceInfo.packageName, serviceInfo.name); + } + } + } + if (numAvailable > 1) { + Log.w(TAG, "more than one voice recognition service found, picking first"); + } + + ServiceInfo serviceInfo = available.get(0).serviceInfo; + return new ComponentName(serviceInfo.packageName, serviceInfo.name); + } + } + + ComponentName getCurRecognizer() { + String curRecognizer = Settings.Secure.getString( + mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE); + if (TextUtils.isEmpty(curRecognizer)) { + return null; + } + return ComponentName.unflattenFromString(curRecognizer); + } + + void setCurRecognizer(ComponentName comp) { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + comp != null ? comp.flattenToShortString() : ""); + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a09896a..38df02f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -97,6 +97,7 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; + RecognitionManagerService recognition = null; // Critical services... try { @@ -377,6 +378,13 @@ class ServerThread extends Thread { } try { + Log.i(TAG, "Recognition Service"); + recognition = new RecognitionManagerService(context); + } catch (Throwable e) { + Log.e(TAG, "Failure starting Recognition Service", e); + } + + try { com.android.server.status.StatusBarPolicy.installIcons(context, statusBar); } catch (Throwable e) { Log.e(TAG, "Failure installing status bar icons", e); @@ -435,6 +443,7 @@ class ServerThread extends Thread { final AppWidgetService appWidgetF = appWidget; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; + final RecognitionManagerService recognitionF = recognition; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -449,6 +458,7 @@ class ServerThread extends Thread { if (batteryF != null) batteryF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); if (dockF != null) dockF.systemReady(); + if (recognitionF != null) recognitionF.systemReady(); Watchdog.getInstance().start(); // It is now okay to let the various system services start their diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 81255ee..481e6a4 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -65,7 +65,10 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import com.android.internal.content.PackageMonitor; import com.android.internal.service.wallpaper.ImageWallpaper; +import com.android.server.DevicePolicyManagerService.ActiveAdmin; +import com.android.server.DevicePolicyManagerService.MyPackageMonitor; import com.android.common.FastXmlSerializer; class WallpaperManagerService extends IWallpaperManager.Stub { @@ -122,6 +125,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { final Context mContext; final IWindowManager mIWindowManager; + final MyPackageMonitor mMonitor; int mWidth = -1; int mHeight = -1; @@ -150,6 +154,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { WallpaperConnection mWallpaperConnection; long mLastDiedTime; + boolean mWallpaperUpdating; class WallpaperConnection extends IWallpaperConnection.Stub implements ServiceConnection { @@ -165,6 +170,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mLock) { if (mWallpaperConnection == this) { + mLastDiedTime = SystemClock.uptimeMillis(); mService = IWallpaperService.Stub.asInterface(service); attachServiceLocked(this); // XXX should probably do saveSettingsLocked() later @@ -182,8 +188,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub { mEngine = null; if (mWallpaperConnection == this) { Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent); - if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME) - < SystemClock.uptimeMillis()) { + if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME) + > SystemClock.uptimeMillis()) { Log.w(TAG, "Reverting to built-in wallpaper!"); bindWallpaperComponentLocked(null); } @@ -205,11 +211,92 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } + class MyPackageMonitor extends PackageMonitor { + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + synchronized (mLock) { + if (mWallpaperComponent != null && + mWallpaperComponent.getPackageName().equals(packageName)) { + mWallpaperUpdating = false; + ComponentName comp = mWallpaperComponent; + clearWallpaperComponentLocked(); + bindWallpaperComponentLocked(comp); + } + } + } + + @Override + public void onPackageUpdateStarted(String packageName, int uid) { + synchronized (mLock) { + if (mWallpaperComponent != null && + mWallpaperComponent.getPackageName().equals(packageName)) { + mWallpaperUpdating = true; + } + } + } + + @Override + public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { + return doPackagesChanged(doit); + } + + @Override + public void onSomePackagesChanged() { + doPackagesChanged(true); + } + + boolean doPackagesChanged(boolean doit) { + boolean changed = false; + synchronized (mLock) { + if (mWallpaperComponent != null) { + int change = isPackageDisappearing(mWallpaperComponent.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + changed = true; + if (doit) { + Log.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent); + clearWallpaperLocked(); + } + } + } + if (mNextWallpaperComponent != null) { + int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + mNextWallpaperComponent = null; + } + } + if (mWallpaperComponent != null + && isPackageModified(mWallpaperComponent.getPackageName())) { + try { + mContext.getPackageManager().getServiceInfo( + mWallpaperComponent, 0); + } catch (NameNotFoundException e) { + Log.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent); + clearWallpaperLocked(); + } + } + if (mNextWallpaperComponent != null + && isPackageModified(mNextWallpaperComponent.getPackageName())) { + try { + mContext.getPackageManager().getServiceInfo( + mNextWallpaperComponent, 0); + } catch (NameNotFoundException e) { + mNextWallpaperComponent = null; + } + } + } + return changed; + } + } + public WallpaperManagerService(Context context) { if (DEBUG) Log.v(TAG, "WallpaperService startup"); mContext = context; mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); + mMonitor = new MyPackageMonitor(); + mMonitor.register(context, true); WALLPAPER_DIR.mkdirs(); loadSettingsLocked(); mWallpaperObserver.startWatching(); @@ -241,16 +328,20 @@ class WallpaperManagerService extends IWallpaperManager.Stub { public void clearWallpaper() { if (DEBUG) Log.v(TAG, "clearWallpaper"); synchronized (mLock) { - File f = WALLPAPER_FILE; - if (f.exists()) { - f.delete(); - } - final long ident = Binder.clearCallingIdentity(); - try { - bindWallpaperComponentLocked(null); - } finally { - Binder.restoreCallingIdentity(ident); - } + clearWallpaperLocked(); + } + } + + public void clearWallpaperLocked() { + File f = WALLPAPER_FILE; + if (f.exists()) { + f.delete(); + } + final long ident = Binder.clearCallingIdentity(); + try { + bindWallpaperComponentLocked(null); + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -499,7 +590,9 @@ class WallpaperManagerService extends IWallpaperManager.Stub { mWidth, mHeight); } catch (RemoteException e) { Log.w(TAG, "Failed attaching wallpaper; clearing", e); - bindWallpaperComponentLocked(null); + if (!mWallpaperUpdating) { + bindWallpaperComponentLocked(null); + } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 45c3f00..5b37f47 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -47,6 +47,7 @@ import android.app.ResultInfo; import android.app.Service; import android.backup.IBackupManager; import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -93,7 +94,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; -import android.text.TextUtils; import android.util.Config; import android.util.EventLog; import android.util.Log; @@ -107,7 +107,6 @@ import android.view.WindowManagerPolicy; import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; @@ -296,12 +295,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Memory pages are 4K. static final int PAGE_SIZE = 4*1024; - // 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"; - // Corresponding memory levels for above adjustments. static final int EMPTY_APP_MEM; static final int HIDDEN_APP_MEM; @@ -1193,7 +1186,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int uid = msg.arg1; boolean restart = (msg.arg2 == 1); String pkg = (String) msg.obj; - forceStopPackageLocked(pkg, uid, restart, false); + forceStopPackageLocked(pkg, uid, restart, false, true); } } break; } @@ -1396,7 +1389,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); - mConfiguration.makeDefault(); + mConfiguration.setToDefaults(); + mConfiguration.locale = Locale.getDefault(); mProcessStats.init(); // Add ourself to the Watchdog monitors. @@ -4846,7 +4840,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return; } killPackageProcessesLocked(packageName, pkgUid, - SECONDARY_SERVER_ADJ, false); + SECONDARY_SERVER_ADJ, false, true); } } finally { Binder.restoreCallingIdentity(callingId); @@ -4988,7 +4982,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } private void forceStopPackageLocked(final String packageName, int uid) { - forceStopPackageLocked(packageName, uid, false, false); + forceStopPackageLocked(packageName, uid, false, false, true); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, uid); @@ -4997,8 +4991,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen false, false, MY_PID, Process.SYSTEM_UID); } - private final void killPackageProcessesLocked(String packageName, int uid, - int minOomAdj, boolean callerWillRestart) { + private final boolean killPackageProcessesLocked(String packageName, int uid, + int minOomAdj, boolean callerWillRestart, boolean doit) { ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); // Remove all processes this package may have touched: all with the @@ -5010,11 +5004,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen for (int ia=0; ia<NA; ia++) { ProcessRecord app = apps.valueAt(ia); if (app.removed) { - procs.add(app); + if (doit) { + procs.add(app); + } } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) || app.processName.equals(packageName) || app.processName.startsWith(procNamePrefix)) { if (app.setAdj >= minOomAdj) { + if (!doit) { + return true; + } app.removed = true; procs.add(app); } @@ -5026,10 +5025,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen for (int i=0; i<N; i++) { removeProcessLocked(procs.get(i), callerWillRestart); } + return N > 0; } - private final void forceStopPackageLocked(String name, int uid, - boolean callerWillRestart, boolean purgeCache) { + private final boolean forceStopPackageLocked(String name, int uid, + boolean callerWillRestart, boolean purgeCache, boolean doit) { int i, N; if (uid < 0) { @@ -5039,21 +5039,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - Log.i(TAG, "Force stopping package " + name + " uid=" + uid); + if (doit) { + Log.i(TAG, "Force stopping package " + name + " uid=" + uid); - Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator(); - while (badApps.hasNext()) { - SparseArray<Long> ba = badApps.next(); - if (ba.get(uid) != null) { - badApps.remove(); + Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator(); + while (badApps.hasNext()) { + SparseArray<Long> ba = badApps.next(); + if (ba.get(uid) != null) { + badApps.remove(); + } } } - - killPackageProcessesLocked(name, uid, -100, callerWillRestart); + + boolean didSomething = killPackageProcessesLocked(name, uid, -100, + callerWillRestart, doit); for (i=mHistory.size()-1; i>=0; i--) { HistoryRecord r = (HistoryRecord)mHistory.get(i); if (r.packageName.equals(name)) { + if (!doit) { + return true; + } + didSomething = true; Log.i(TAG, " Force finishing activity " + r); if (r.app != null) { r.app.removed = true; @@ -5066,6 +5073,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); for (ServiceRecord service : mServices.values()) { if (service.packageName.equals(name)) { + if (!doit) { + return true; + } + didSomething = true; Log.i(TAG, " Force stopping service " + service); if (service.app != null) { service.app.removed = true; @@ -5080,13 +5091,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen bringDownServiceLocked(services.get(i), true); } - resumeTopActivityLocked(null); - if (purgeCache) { - AttributeCache ac = AttributeCache.instance(); - if (ac != null) { - ac.removePackage(name); + if (doit) { + if (purgeCache) { + AttributeCache ac = AttributeCache.instance(); + if (ac != null) { + ac.removePackage(name); + } } + resumeTopActivityLocked(null); } + + return didSomething; } private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) { @@ -5583,19 +5598,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } final void finishBooting() { - // Ensure that any processes we had put on hold are now started - // up. - final int NP = mProcessesOnHold.size(); - if (NP > 0) { - ArrayList<ProcessRecord> procs = - new ArrayList<ProcessRecord>(mProcessesOnHold); - for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); + IntentFilter pkgFilter = new IntentFilter(); + pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); + pkgFilter.addDataScheme("package"); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); + if (pkgs != null) { + for (String pkg : pkgs) { + if (forceStopPackageLocked(pkg, -1, false, false, false)) { + setResultCode(Activity.RESULT_OK); + return; + } + } + } } - } - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - // Tell anyone interested that we are done booting! - synchronized (this) { + }, pkgFilter); + + synchronized (this) { + // Ensure that any processes we had put on hold are now started + // up. + final int NP = mProcessesOnHold.size(); + if (NP > 0) { + ArrayList<ProcessRecord> procs = + new ArrayList<ProcessRecord>(mProcessesOnHold); + for (int ip=0; ip<NP; ip++) { + this.startProcessLocked(procs.get(ip), "on-hold", null); + } + } + + if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + // Tell anyone interested that we are done booting! broadcastIntentLocked(null, null, new Intent(Intent.ACTION_BOOT_COMPLETED, null), null, null, 0, null, null, @@ -8050,7 +8084,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mDebugTransient = !persistent; if (packageName != null) { final long origId = Binder.clearCallingIdentity(); - forceStopPackageLocked(packageName, -1, false, false); + forceStopPackageLocked(packageName, -1, false, false, true); Binder.restoreCallingIdentity(origId); } } @@ -8339,7 +8373,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mAlwaysFinishActivities = alwaysFinishActivities; // This happens before any activities are started, so we can // change mConfiguration in-place. - mConfiguration.locale = Locale.getDefault(); mConfiguration.updateFrom(configuration); mConfigurationSeq = mConfiguration.seq = 1; if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration); @@ -8537,73 +8570,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return handleAppCrashLocked(app); } - private ComponentName getErrorReportReceiver(ProcessRecord app) { - // check if error reporting is enabled in secure settings - int enabled = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.SEND_ACTION_APP_ERROR, 0); - if (enabled == 0) { - return null; - } - - IPackageManager pm = ActivityThread.getPackageManager(); - - try { - // look for receiver in the installer package - String candidate = pm.getInstallerPackageName(app.info.packageName); - ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate); - if (result != null) { - return result; - } - - // if the error app is on the system image, look for system apps - // error receiver - if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); - result = getErrorReportReceiver(pm, app.info.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, app.info.packageName, candidate); - } catch (RemoteException e) { - // should not happen - Log.e(TAG, "error talking to PackageManager", e); - return null; - } - } - - /** - * 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 - */ - private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage, - String receiverPackage) throws RemoteException { - 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.resolveIntent(intent, null, 0); - if (info == null || info.activityInfo == null) { - return null; - } - return new ComponentName(receiverPackage, info.activityInfo.name); - } - private void makeAppNotRespondingLocked(ProcessRecord app, String activity, String shortMsg, String longMsg) { app.notResponding = true; @@ -8717,7 +8683,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } void startAppProblemLocked(ProcessRecord app) { - app.errorReportReceiver = getErrorReportReceiver(app); + app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver( + mContext, app.info.packageName, app.info.flags); skipCurrentReceiverLocked(app); } @@ -11951,7 +11918,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { - forceStopPackageLocked(pkg, -1, false, true); + forceStopPackageLocked(pkg, -1, false, true, true); } } } else { @@ -11960,7 +11927,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { forceStopPackageLocked(ssp, - intent.getIntExtra(Intent.EXTRA_UID, -1), false, true); + intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true); } } } @@ -12931,7 +12898,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } final long origId = Binder.clearCallingIdentity(); - forceStopPackageLocked(ii.targetPackage, -1, true, false); + forceStopPackageLocked(ii.targetPackage, -1, true, false, true); ProcessRecord app = addAppLocked(ai); app.instrumentationClass = className; app.instrumentationInfo = ai; @@ -12986,7 +12953,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.instrumentationProfileFile = null; app.instrumentationArguments = null; - forceStopPackageLocked(app.processName, -1, false, false); + forceStopPackageLocked(app.processName, -1, false, false, true); } public void finishInstrumentation(IApplicationThread target, |