From d24b8183b93e781080b2c16c487e60d51c12da31 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:44:00 -0800 Subject: auto import from //branches/cupcake/...@130745 --- .../com/android/server/AlarmManagerService.java | 2 +- .../java/com/android/server/BatteryService.java | 35 +- .../com/android/server/ConnectivityService.java | 29 +- .../com/android/server/FallbackCheckinService.java | 75 ++ .../java/com/android/server/GadgetService.java | 913 +++++++++++++++++++-- .../java/com/android/server/HardwareService.java | 80 +- .../java/com/android/server/HeadsetObserver.java | 48 +- .../android/server/InputMethodManagerService.java | 166 ++-- .../java/com/android/server/KeyInputQueue.java | 1 + .../com/android/server/LocationManagerService.java | 182 ++-- .../java/com/android/server/MountListener.java | 108 +-- services/java/com/android/server/MountService.java | 399 +++++++-- .../java/com/android/server/NetStatService.java | 31 +- .../android/server/NotificationManagerService.java | 2 +- .../com/android/server/PackageManagerService.java | 182 ++-- .../com/android/server/PowerManagerService.java | 43 +- .../java/com/android/server/SensorService.java | 8 +- services/java/com/android/server/SystemServer.java | 82 +- .../java/com/android/server/TelephonyRegistry.java | 2 +- services/java/com/android/server/WifiService.java | 105 +-- .../com/android/server/WindowManagerService.java | 358 ++++++-- .../android/server/am/ActivityManagerService.java | 267 +++++- .../com/android/server/am/BatteryStatsService.java | 58 +- .../java/com/android/server/am/HistoryRecord.java | 6 + .../com/android/server/am/UsageStatsService.java | 192 +++++ .../com/android/server/status/StatusBarPolicy.java | 33 +- .../android/server/status/StatusBarService.java | 6 +- 27 files changed, 2719 insertions(+), 694 deletions(-) create mode 100644 services/java/com/android/server/FallbackCheckinService.java create mode 100755 services/java/com/android/server/am/UsageStatsService.java (limited to 'services/java/com') diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 1625853..d8012b2 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -382,7 +382,7 @@ class AlarmManagerService extends IAlarmManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission("android.permission.DUMP") + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump AlarmManager from from pid=" + Binder.getCallingPid() diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index dba8fca..e4fdd0c 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager; import android.os.BatteryManager; import android.os.Binder; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UEventObserver; import android.util.EventLog; import android.util.Log; @@ -61,9 +62,13 @@ class BatteryService extends Binder { static final int LOG_BATTERY_LEVEL = 2722; static final int LOG_BATTERY_STATUS = 2723; + static final int LOG_BATTERY_DISCHARGE_STATUS = 2730; static final int BATTERY_SCALE = 100; // battery capacity is a percentage + // This should probably be exposed in the API, though it's not critical + private static final int BATTERY_PLUGGED_NONE = 0; + private final Context mContext; private final IBatteryStats mBatteryStats; @@ -85,7 +90,10 @@ class BatteryService extends Binder { private int mLastBatteryTemperature; private int mPlugType; - private int mLastPlugType; + private int mLastPlugType = -1; // Extra state so we can detect first run + + private long mDischargeStartTime; + private int mDischargeStartLevel; public BatteryService(Context context) { mContext = context; @@ -145,7 +153,7 @@ class BatteryService extends Binder { } else if (mUsbOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_USB; } else { - mPlugType = 0; + mPlugType = BATTERY_PLUGGED_NONE; } if (mBatteryStatus != mLastBatteryStatus || mBatteryHealth != mLastBatteryHealth || @@ -155,6 +163,25 @@ class BatteryService extends Binder { mBatteryVoltage != mLastBatteryVoltage || mBatteryTemperature != mLastBatteryTemperature) { + if (mPlugType != mLastPlugType) { + if (mLastPlugType == BATTERY_PLUGGED_NONE) { + // discharging -> charging + + // There's no value in this data unless we've discharged at least once and the + // battery level has changed; so don't log until it does. + if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) { + long duration = SystemClock.elapsedRealtime() - mDischargeStartTime; + EventLog.writeEvent(LOG_BATTERY_DISCHARGE_STATUS, duration, + mDischargeStartLevel, mBatteryLevel); + // make sure we see a discharge event before logging again + mDischargeStartTime = 0; + } + } else if (mPlugType == BATTERY_PLUGGED_NONE) { + // charging -> discharging or we just powered up + mDischargeStartTime = SystemClock.elapsedRealtime(); + mDischargeStartLevel = mBatteryLevel; + } + } if (mBatteryStatus != mLastBatteryStatus || mBatteryHealth != mLastBatteryHealth || mBatteryPresent != mLastBatteryPresent || @@ -187,7 +214,7 @@ class BatteryService extends Binder { Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); try { - mBatteryStats.setOnBattery(mPlugType == 0); + mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE); } catch (RemoteException e) { // Should never happen. } @@ -233,7 +260,7 @@ class BatteryService extends Binder { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission("android.permission.DUMP") + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump Battery service from from pid=" diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 65e3650..760988d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; +import android.provider.Sync; import android.util.EventLog; import android.util.Log; @@ -333,6 +334,32 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * @see ConnectivityManager#getBackgroundDataSetting() + */ + public boolean getBackgroundDataSetting() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.BACKGROUND_DATA, 1) == 1; + } + + /** + * @see ConnectivityManager#setBackgroundDataSetting(boolean) + */ + public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING, + "ConnectivityService"); + + if (getBackgroundDataSetting() == allowBackgroundDataUsage) return; + + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0); + + Intent broadcast = new Intent( + ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); + mContext.sendBroadcast(broadcast); + } + private int getNumConnectedNetworks() { int numConnectedNets = 0; @@ -632,7 +659,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump ConnectivityService from from pid=" + Binder.getCallingPid() diff --git a/services/java/com/android/server/FallbackCheckinService.java b/services/java/com/android/server/FallbackCheckinService.java new file mode 100644 index 0000000..cf22446 --- /dev/null +++ b/services/java/com/android/server/FallbackCheckinService.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 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 android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.ICheckinService; +import android.os.IParentalControlCallback; +import android.util.Log; + +import java.io.IOException; + +import com.android.internal.os.RecoverySystem; +import com.google.android.net.ParentalControlState; + +/** + * @hide + */ +public final class FallbackCheckinService extends ICheckinService.Stub { + static final String TAG = "FallbackCheckinService"; + final Context mContext; + + public FallbackCheckinService(Context context) { + mContext = context; + } + + public boolean checkin() { + return false; // failure, because not implemented + } + + public void reportCrashSync(byte[] crashData) { + } + + public void reportCrashAsync(byte[] crashData) { + } + + public void masterClear() { + if (mContext.checkCallingOrSelfPermission("android.permission.MASTER_CLEAR") != + PackageManager.PERMISSION_GRANTED) { + Log.e(TAG, "Permission Denial: can't invoke masterClear from " + + "pid=" + Binder.getCallingPid() + ", " + + "uid=" + Binder.getCallingUid()); + return; + } + + // Save the android ID so the new system can get it erased. + try { + RecoverySystem.rebootAndWipe(); + } catch (IOException e) { + Log.e(TAG, "Reboot for masterClear() failed", e); + } + } + + public void getParentalControlState(IParentalControlCallback p, String requestingApp) + throws android.os.RemoteException { + ParentalControlState state = new ParentalControlState(); + state.isEnabled = false; + p.onResult(state); + } +} diff --git a/services/java/com/android/server/GadgetService.java b/services/java/com/android/server/GadgetService.java index 4be9ed5..5ef0fb9 100644 --- a/services/java/com/android/server/GadgetService.java +++ b/services/java/com/android/server/GadgetService.java @@ -16,57 +16,127 @@ package com.android.server; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.content.pm.PackageItemInfo; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.gadget.GadgetManager; import android.gadget.GadgetInfo; +import android.net.Uri; import android.os.Binder; +import android.os.RemoteException; +import android.os.SystemClock; import android.util.AttributeSet; +import android.util.Config; import android.util.Log; import android.util.Xml; +import android.widget.RemoteViews; +import java.io.IOException; +import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.HashMap; +import java.util.HashSet; import com.android.internal.gadget.IGadgetService; +import com.android.internal.gadget.IGadgetHost; +import com.android.internal.util.XmlUtils; +import com.android.internal.util.FastXmlSerializer; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; class GadgetService extends IGadgetService.Stub { private static final String TAG = "GadgetService"; + private static final boolean LOGD = Config.LOGD || false; + + private static final String SETTINGS_FILENAME = "gadgets.xml"; + private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp"; + + /* + * When identifying a Host or Provider based on the calling process, use the uid field. + * When identifying a Host or Provider based on a package manager broadcast, use the + * package given. + */ + + static class Provider { + int uid; + GadgetInfo info; + ArrayList instances = new ArrayList(); + PendingIntent broadcast; + + int tag; // for use while saving state (the index) + } + + static class Host { + int uid; + int hostId; + String packageName; + ArrayList instances = new ArrayList(); + IGadgetHost callbacks; + + int tag; // for use while saving state (the index) + } static class GadgetId { int gadgetId; - String hostPackage; - GadgetInfo info; + Provider provider; + RemoteViews views; + Host host; } Context mContext; PackageManager mPackageManager; - ArrayList mInstalledProviders; + AlarmManager mAlarmManager; + ArrayList mInstalledProviders = new ArrayList(); int mNextGadgetId = 1; ArrayList mGadgetIds = new ArrayList(); + ArrayList mHosts = new ArrayList(); GadgetService(Context context) { mContext = context; mPackageManager = context.getPackageManager(); - mInstalledProviders = getGadgetList(); + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + + getGadgetList(); + loadStateLocked(); + + // Register for the boot completed broadcast, so we can send the + // ENABLE broacasts. If we try to send them now, they time out, + // because the system isn't ready to handle them yet. + mContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + + // Register for broadcasts about package install, etc., so we can + // update the provider list. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + mContext.registerReceiver(mBroadcastReceiver, filter); } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump from from pid=" + Binder.getCallingPid() @@ -78,7 +148,7 @@ class GadgetService extends IGadgetService.Stub int N = mInstalledProviders.size(); pw.println("Providers: (size=" + N + ")"); for (int i=0; i getInstalledProviders() { synchronized (mGadgetIds) { - return new ArrayList(mInstalledProviders); + final int N = mInstalledProviders.size(); + ArrayList result = new ArrayList(N); + for (int i=0; i instances = p.instances; + final int N = instances.size(); + for (int i=0; i updatedViews) { + int callingUid = enforceCallingUid(packageName); + synchronized (mGadgetIds) { + Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); + host.callbacks = callbacks; + + updatedViews.clear(); + + ArrayList instances = host.instances; + int N = instances.size(); + int[] updatedIds = new int[N]; + for (int i=0; i getGadgetList() { + Host lookupHostLocked(int uid, int hostId) { + final int N = mHosts.size(); + for (int i=0; i broadcastReceivers = pm.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA); - ArrayList result = new ArrayList(); - final int N = broadcastReceivers.size(); for (int i=0; i 0) { + // if this is the first instance, set the alarm. otherwise, + // rely on the fact that we've already set it and that + // PendingIntent.getBroadcast will update the extras. + boolean alreadyRegistered = p.broadcast != null; + int instancesSize = p.instances.size(); + Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION); + intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds); + intent.setComponent(p.info.provider); + long token = Binder.clearCallingIdentity(); + try { + p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + } finally { + Binder.restoreCallingIdentity(token); + } + if (!alreadyRegistered) { + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + p.info.updatePeriodMillis, + p.info.updatePeriodMillis, p.broadcast); + } + } + } + + static int[] getGadgetIds(Provider p) { + int instancesSize = p.instances.size(); + int gadgetIds[] = new int[instancesSize]; + for (int i=0; i 0) { + out.startTag(null, "p"); + out.attribute(null, "pkg", p.info.provider.getPackageName()); + out.attribute(null, "cl", p.info.provider.getClassName()); + out.endTag(null, "h"); + p.tag = providerIndex; + providerIndex++; + } + } + + N = mHosts.size(); + for (int i=0; i loadedProviders = new HashMap(); + do { + type = parser.next(); + if (type == XmlPullParser.START_TAG) { + String tag = parser.getName(); + if ("p".equals(tag)) { + // TODO: do we need to check that this package has the same signature + // as before? + String pkg = parser.getAttributeValue(null, "pkg"); + String cl = parser.getAttributeValue(null, "cl"); + Provider p = lookupProviderLocked(new ComponentName(pkg, cl)); + // if it wasn't uninstalled or something + if (p != null) { + loadedProviders.put(providerIndex, p); + } + providerIndex++; + } + else if ("h".equals(tag)) { + Host host = new Host(); + + // TODO: do we need to check that this package has the same signature + // as before? + host.packageName = parser.getAttributeValue(null, "pkg"); + try { + host.uid = getUidForPackage(host.packageName); + host.hostId = Integer.parseInt( + parser.getAttributeValue(null, "id"), 16); + mHosts.add(host); + } catch (PackageManager.NameNotFoundException ex) { + // Just ignore drop this entry, as if it has been uninstalled. + // We need to deal with this case because of safe mode, but there's + // a bug filed about it. + } + } + else if ("g".equals(tag)) { + GadgetId id = new GadgetId(); + id.gadgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16); + if (id.gadgetId >= mNextGadgetId) { + mNextGadgetId = id.gadgetId + 1; + } + + String providerString = parser.getAttributeValue(null, "p"); + if (providerString != null) { + // there's no provider if it hasn't been bound yet. + // maybe we don't have to save this, but it brings the system + // to the state it was in. + int pIndex = Integer.parseInt(providerString, 16); + id.provider = loadedProviders.get(pIndex); + if (false) { + Log.d(TAG, "bound gadgetId=" + id.gadgetId + " to provider " + + pIndex + " which is " + id.provider); + } + if (id.provider == null) { + // This provider is gone. We just let the host figure out + // that this happened when it fails to load it. + continue; + } + } + + int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16); + id.host = mHosts.get(hIndex); + if (id.host == null) { + // This host is gone. + continue; + } + + if (id.provider != null) { + id.provider.instances.add(id); + } + id.host.instances.add(id); + mGadgetIds.add(id); + } + } + } while (type != XmlPullParser.END_DOCUMENT); + success = true; + } catch (NullPointerException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (NumberFormatException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (XmlPullParserException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (IOException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (IndexOutOfBoundsException e) { + Log.w(TAG, "failed parsing " + file, e); + } + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + + if (success) { + // delete any hosts that didn't manage to get connected (should happen) + // if it matters, they'll be reconnected. + final int N = mHosts.size(); + for (int i=0; i broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, + PackageManager.GET_META_DATA); + + final int N = broadcastReceivers.size(); + for (int i=0; i keep = new HashSet(); + Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION); + List broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, + PackageManager.GET_META_DATA); + + // add the missing ones and collect which ones to keep + int N = broadcastReceivers.size(); + for (int i=0; i 0) { + long bedtime = SystemClock.uptimeMillis(); + do { + try { + this.wait(duration); + } + catch (InterruptedException e) { + } + if (mDone) { + break; + } + duration = duration + - SystemClock.uptimeMillis() - bedtime; + } while (duration > 0); + } + } + public void run() { synchronized (this) { int index = 0; - boolean nextState = false; long[] pattern = mPattern; - if (pattern[0] == 0) { - index++; - nextState = true; - } int len = pattern.length; - long start = SystemClock.uptimeMillis(); + long duration = 0; while (!mDone) { - if (nextState) { - HardwareService.this.on(); - } else { - HardwareService.this.off(); + // add off-time duration to any accumulated on-time duration + if (index < len) { + duration += pattern[index++]; } - nextState = !nextState; - long bedtime = SystemClock.uptimeMillis(); - long duration = pattern[index]; - do { - try { - this.wait(duration); - } - catch (InterruptedException e) { - } - if (mDone) { - break; + + // sleep until it is time to start the vibrator + delay(duration); + if (mDone) { + break; + } + + if (index < len) { + // read on-time duration and start the vibrator + // duration is saved for delay() at top of loop + duration = pattern[index++]; + if (duration > 0) { + HardwareService.this.vibratorOn(duration); } - duration = duration - - SystemClock.uptimeMillis() - bedtime; - } while (duration > 0); - index++; - if (index >= len) { + } else { if (mRepeat < 0) { - HardwareService.this.off(); break; } else { index = mRepeat; + duration = 0; } } } + if (mDone) { + // make sure vibrator is off if we were cancelled. + // otherwise, it will turn off automatically + // when the last timeout expires. + HardwareService.this.vibratorOff(); + } mWakeLock.release(); } synchronized (HardwareService.this) { @@ -301,6 +321,6 @@ public class HardwareService extends IHardwareService.Stub { volatile Death mDeath; volatile IBinder mToken; - native static void on(); - native static void off(); + native static void vibratorOn(long milliseconds); + native static void vibratorOff(); } diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java index 2bea731..855734d 100644 --- a/services/java/com/android/server/HeadsetObserver.java +++ b/services/java/com/android/server/HeadsetObserver.java @@ -19,6 +19,8 @@ package com.android.server; import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; +import android.os.Handler; +import android.os.Message; import android.os.UEventObserver; import android.util.Log; import android.media.AudioManager; @@ -40,6 +42,8 @@ class HeadsetObserver extends UEventObserver { private int mHeadsetState; private String mHeadsetName; + private boolean mAudioRouteNeedsUpdate; + private AudioManager mAudioManager; public HeadsetObserver(Context context) { mContext = context; @@ -60,7 +64,7 @@ class HeadsetObserver extends UEventObserver { } } - private final void init() { + private synchronized final void init() { char[] buffer = new char[1024]; String newName = mHeadsetName; @@ -80,21 +84,33 @@ class HeadsetObserver extends UEventObserver { Log.e(TAG, "" , e); } + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); update(newName, newState); } private synchronized final void update(String newName, int newState) { if (newName != mHeadsetName || newState != mHeadsetState) { + boolean isUnplug = (newState == 0 && mHeadsetState == 1); mHeadsetName = newName; mHeadsetState = newState; - AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - - audioManager.setWiredHeadsetOn(mHeadsetState == 1); - sendIntent(); + mAudioRouteNeedsUpdate = true; + + sendIntent(isUnplug); + + if (isUnplug) { + // It often takes >200ms to flush the audio pipeline after apps + // pause audio playback, but audio route changes are immediate, + // so delay the route change by 400ms. + // This could be improved once the audio sub-system provides an + // interface to clear the audio pipeline. + mHandler.sendEmptyMessageDelayed(0, 400); + } else { + updateAudioRoute(); + } } } - private synchronized final void sendIntent() { + private synchronized final void sendIntent(boolean isUnplug) { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -104,5 +120,25 @@ class HeadsetObserver extends UEventObserver { // TODO: Should we require a permission? ActivityManagerNative.broadcastStickyIntent(intent, null); + + if (isUnplug) { + intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + mContext.sendBroadcast(intent); + } } + + private synchronized final void updateAudioRoute() { + if (mAudioRouteNeedsUpdate) { + mAudioManager.setWiredHeadsetOn(mHeadsetState == 1); + mAudioRouteNeedsUpdate = false; + } + } + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + updateAudioRoute(); + } + }; + } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 139aaa3..ee49365 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -30,6 +30,7 @@ import com.android.server.status.StatusBarService; import org.xmlpull.v1.XmlPullParserException; +import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.content.ComponentName; import android.content.ContentResolver; @@ -61,7 +62,6 @@ import android.util.PrintWriterPrinter; import android.util.Printer; import android.view.IWindowManager; import android.view.WindowManager; -import android.view.inputmethod.DefaultInputMethod; import android.view.inputmethod.InputBinding; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; @@ -189,6 +189,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ClientState mCurClient; /** + * The input context last provided by the current client. + */ + IInputContext mCurInputContext; + + /** * The attributes last provided by the current client. */ EditorInfo mCurAttribute; @@ -216,6 +221,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean mShowExplicitlyRequested; /** + * Set if we were forced to be shown. + */ + boolean mShowForced; + + /** * Set if we last told the input method to show itself. */ boolean mInputShown; @@ -281,7 +291,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { mScreenOn = false; } else { - Log.e(TAG, "Unexpected intent " + intent); + Log.w(TAG, "Unexpected intent " + intent); } // Inform the current client of the change in active status @@ -290,7 +300,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurClient.client.setActive(mScreenOn); } } catch (RemoteException e) { - Log.e(TAG, "Got RemoteException sending 'screen on/off' notification", e); + Log.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid " + + mCurClient.pid + " uid " + mCurClient.uid); } } } @@ -553,12 +564,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { mCurClient.client.setActive(false); } catch (RemoteException e) { - Log.e(TAG, "Got RemoteException sending setActive(false) notification", e); + Log.w(TAG, "Got RemoteException sending setActive(false) notification to pid " + + mCurClient.pid + " uid " + mCurClient.uid); } mCurClient = null; } } + private int getShowFlags() { + int flags = 0; + if (mShowForced) { + flags |= InputMethod.SHOW_FORCED + | InputMethod.SHOW_EXPLICIT; + } else if (mShowExplicitlyRequested) { + flags |= InputMethod.SHOW_EXPLICIT; + } + return flags; + } + InputBindResult attachNewInputLocked(boolean initial, boolean needResult) { if (!mBoundToMethod) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( @@ -567,16 +590,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final SessionState session = mCurClient.curSession; if (initial) { - executeOrSendMessage(session.method, mCaller.obtainMessageOO( - MSG_START_INPUT, session, mCurAttribute)); + executeOrSendMessage(session.method, mCaller.obtainMessageOOO( + MSG_START_INPUT, session, mCurInputContext, mCurAttribute)); } else { - executeOrSendMessage(session.method, mCaller.obtainMessageOO( - MSG_RESTART_INPUT, session, mCurAttribute)); + executeOrSendMessage(session.method, mCaller.obtainMessageOOO( + MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute)); } if (mShowRequested) { if (DEBUG) Log.v(TAG, "Attach new input asks to show input"); - showCurrentInputLocked(mShowExplicitlyRequested - ? 0 : InputMethodManager.SHOW_IMPLICIT); + showCurrentInputLocked(getShowFlags()); } return needResult ? new InputBindResult(session.session, mCurId, mCurSeq) @@ -584,7 +606,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } InputBindResult startInputLocked(IInputMethodClient client, - EditorInfo attribute, boolean initial, boolean needResult) { + IInputContext inputContext, EditorInfo attribute, + boolean initial, boolean needResult) { // If no method is currently selected, do nothing. if (mCurMethodId == null) { return mNoBinding; @@ -622,7 +645,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { cs.client.setActive(mScreenOn); } catch (RemoteException e) { - Log.e(TAG, "Got RemoteException sending setActive notification", e); + Log.w(TAG, "Got RemoteException sending setActive notification to pid " + + cs.pid + " uid " + cs.uid); } } } @@ -631,6 +655,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurSeq++; if (mCurSeq <= 0) mCurSeq = 1; mCurClient = cs; + mCurInputContext = inputContext; mCurAttribute = attribute; // Check if the input method is changing. @@ -659,6 +684,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (mCurToken != null) { try { + if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken); mIWindowManager.removeWindowToken(mCurToken); } catch (RemoteException e) { } @@ -679,6 +705,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurId = info.getId(); mCurToken = new Binder(); try { + if (DEBUG) Log.v(TAG, "Adding window token: " + mCurToken); mIWindowManager.addWindowToken(mCurToken, WindowManager.LayoutParams.TYPE_INPUT_METHOD); } catch (RemoteException e) { @@ -686,18 +713,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return new InputBindResult(null, mCurId, mCurSeq); } else { mCurIntent = null; - Log.e(TAG, "Failure connecting to input method service: " + Log.w(TAG, "Failure connecting to input method service: " + mCurIntent); } return null; } public InputBindResult startInput(IInputMethodClient client, - EditorInfo attribute, boolean initial, boolean needResult) { + IInputContext inputContext, EditorInfo attribute, + boolean initial, boolean needResult) { synchronized (mMethodMap) { final long ident = Binder.clearCallingIdentity(); try { - return startInputLocked(client, attribute, initial, needResult); + return startInputLocked(client, inputContext, attribute, + initial, needResult); } finally { Binder.restoreCallingIdentity(ident); } @@ -712,6 +741,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { mCurMethod = IInputMethod.Stub.asInterface(service); if (mCurClient != null) { + if (DEBUG) Log.v(TAG, "Initiating attach with token: " + mCurToken); executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_ATTACH_TOKEN, mCurMethod, mCurToken)); if (mCurClient != null) { @@ -817,10 +847,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurMethodId = id; Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD, id); - - Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); - intent.putExtra("input_method_id", id); - mContext.sendBroadcast(intent); + + if (ActivityManagerNative.isSystemReady()) { + Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); + intent.putExtra("input_method_id", id); + mContext.sendBroadcast(intent); + } unbindCurrentInputLocked(); } finally { Binder.restoreCallingIdentity(ident); @@ -853,10 +885,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) { mShowExplicitlyRequested = true; } + if ((flags&InputMethodManager.SHOW_FORCED) != 0) { + mShowExplicitlyRequested = true; + mShowForced = true; + } if (mCurMethod != null) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageIO( - MSG_SHOW_SOFT_INPUT, mShowExplicitlyRequested ? 1 : 0, - mCurMethod)); + MSG_SHOW_SOFT_INPUT, getShowFlags(), mCurMethod)); mInputShown = true; } } @@ -884,11 +919,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub void hideCurrentInputLocked(int flags) { if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 - && mShowExplicitlyRequested) { + && (mShowExplicitlyRequested || mShowForced)) { if (DEBUG) Log.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide"); return; } + if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) { + if (DEBUG) Log.v(TAG, + "Not hiding: forced show not cancelled by not-always hide"); + return; + } if (mInputShown && mCurMethod != null) { executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( MSG_HIDE_SOFT_INPUT, mCurMethod)); @@ -896,6 +936,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mInputShown = false; mShowRequested = false; mShowExplicitlyRequested = false; + mShowForced = false; } public void windowGainedFocus(IInputMethodClient client, @@ -933,7 +974,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // be behind any soft input window, so hide the // soft input window if it is shown. if (DEBUG) Log.v(TAG, "Unspecified window will hide input"); - hideCurrentInputLocked(0); + hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS); } } else if (isTextEditor && (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) @@ -1052,7 +1093,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return true; case MSG_SHOW_SOFT_INPUT: try { - ((IInputMethod)msg.obj).showSoftInput(msg.arg1 != 0); + ((IInputMethod)msg.obj).showSoftInput(msg.arg1); } catch (RemoteException e) { } return true; @@ -1065,6 +1106,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case MSG_ATTACH_TOKEN: args = (HandlerCaller.SomeArgs)msg.obj; try { + if (DEBUG) Log.v(TAG, "Sending attach of token: " + args.arg2); ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2); } catch (RemoteException e) { } @@ -1085,7 +1127,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { SessionState session = (SessionState)args.arg1; setEnabledSessionInMainThread(session); - session.method.startInput((EditorInfo)args.arg2); + session.method.startInput((IInputContext)args.arg2, + (EditorInfo)args.arg3); } catch (RemoteException e) { } return true; @@ -1094,7 +1137,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { SessionState session = (SessionState)args.arg1; setEnabledSessionInMainThread(session); - session.method.restartInput((EditorInfo)args.arg2); + session.method.restartInput((IInputContext)args.arg2, + (EditorInfo)args.arg3); } catch (RemoteException e) { } return true; @@ -1128,10 +1172,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub PackageManager pm = mContext.getPackageManager(); - Object[][] buildin = {{ - DefaultInputMethod.class.getName(), - DefaultInputMethod.getMetaInfo()}}; - List services = pm.queryIntentServices( new Intent(InputMethod.SERVICE_INTERFACE), PackageManager.GET_META_DATA); @@ -1150,39 +1190,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Log.d(TAG, "Checking " + compName); - /* Built-in input methods are not currently supported... this will - * need to be reworked to bring them back (all input methods must - * now be published in a manifest). - */ - /* - if (compName.getPackageName().equals( - InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) { - // System build-in input methods; - String inputMethodName = null; - int kbType = 0; - String skbName = null; - - for (int j = 0; j < buildin.length; ++j) { - Object[] obj = buildin[j]; - if (compName.getClassName().equals(obj[0])) { - InputMethodMetaInfo imp = (InputMethodMetaInfo) obj[1]; - inputMethodName = imp.inputMethodName; - } - } - - InputMethodMetaInfo p = new InputMethodMetaInfo(compName, - inputMethodName, ""); - - list.add(p); - - if (DEBUG) { - Log.d(TAG, "Found a build-in input method " + p); - } - - continue; - } - */ - try { InputMethodInfo p = new InputMethodInfo(mContext, ri); list.add(p); @@ -1386,7 +1393,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission("android.permission.DUMP") + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump InputMethodManager from from pid=" @@ -1395,8 +1402,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } + IInputMethod method; + ClientState client; + + final Printer p = new PrintWriterPrinter(pw); + synchronized (mMethodMap) { - final Printer p = new PrintWriterPrinter(pw); p.println("Current Input Method Manager state:"); int N = mMethodList.size(); p.println(" Input Methods:"); @@ -1416,17 +1427,40 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mInputMethodIcon=" + mInputMethodIcon); p.println(" mInputMethodData=" + mInputMethodData); p.println(" mCurrentMethod=" + mCurMethodId); - p.println(" mCurSeq=" + mCurSeq + " mCurClient=" + mCurClient); + client = mCurClient; + p.println(" mCurSeq=" + mCurSeq + " mCurClient=" + client); p.println(" mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection + " mBoundToMethod=" + mBoundToMethod); p.println(" mCurToken=" + mCurToken); p.println(" mCurIntent=" + mCurIntent); + method = mCurMethod; p.println(" mCurMethod=" + mCurMethod); p.println(" mEnabledSession=" + mEnabledSession); p.println(" mShowRequested=" + mShowRequested + " mShowExplicitlyRequested=" + mShowExplicitlyRequested + + " mShowForced=" + mShowForced + " mInputShown=" + mInputShown); p.println(" mScreenOn=" + mScreenOn); } + + if (client != null) { + p.println(" "); + pw.flush(); + try { + client.client.asBinder().dump(fd, args); + } catch (RemoteException e) { + p.println("Input method client dead: " + e); + } + } + + if (method != null) { + p.println(" "); + pw.flush(); + try { + method.asBinder().dump(fd, args); + } catch (RemoteException e) { + p.println("Input method service dead: " + e); + } + } } } diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 9874042..63b486c 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -165,6 +165,7 @@ public abstract class KeyInputQueue { public static native int getScancodeState(int deviceId, int sw); public static native int getKeycodeState(int sw); public static native int getKeycodeState(int deviceId, int sw); + public static native boolean hasKeys(int[] keycodes, boolean[] keyExists); public static KeyEvent newKeyEvent(InputDevice device, long downTime, long eventTime, boolean down, int keycode, int repeatCount, diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index ed9ee79..bc6fd71 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -64,12 +64,14 @@ import android.telephony.TelephonyManager; import android.util.Config; import android.util.Log; +import com.android.internal.app.IBatteryStats; import com.android.internal.location.CellState; import com.android.internal.location.GpsLocationProvider; -import com.android.internal.location.LocationCollector; -import com.android.internal.location.LocationMasfClient; -import com.android.internal.location.NetworkLocationProvider; +import com.android.internal.location.ILocationCollector; +import com.android.internal.location.INetworkLocationManager; +import com.android.internal.location.INetworkLocationProvider; import com.android.internal.location.TrackProvider; +import com.android.server.am.BatteryStatsService; /** * The service class that manages LocationProviders and issues location @@ -77,7 +79,8 @@ import com.android.internal.location.TrackProvider; * * {@hide} */ -public class LocationManagerService extends ILocationManager.Stub { +public class LocationManagerService extends ILocationManager.Stub + implements INetworkLocationManager { private static final String TAG = "LocationManagerService"; // Minimum time interval between last known location writes, in milliseconds. @@ -121,13 +124,15 @@ public class LocationManagerService extends ILocationManager.Stub { private final Context mContext; private GpsLocationProvider mGpsLocationProvider; - private NetworkLocationProvider mNetworkLocationProvider; + private LocationProviderImpl mNetworkLocationProvider; + private INetworkLocationProvider mNetworkLocationInterface; private LocationWorkerHandler mLocationHandler; // Handler messages private static final int MESSAGE_HEARTBEAT = 1; private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2; private static final int MESSAGE_RELEASE_WAKE_LOCK = 3; + private static final int MESSAGE_SET_NETWORK_LOCATION_PROVIDER = 4; // Alarm manager and wakelock variables private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; @@ -143,6 +148,11 @@ public class LocationManagerService extends ILocationManager.Stub { private boolean mWakeLockNetworkReceived = true; private boolean mWifiWakeLockAcquired = false; private boolean mCellWakeLockAcquired = false; + + private final IBatteryStats mBatteryStats; + + // The calling UID when we are in a clearCallingIdentity/restoreCallingIdentity block, or -1 + private int mCallingUid = -1; /** * Mapping from listener IBinder/PendingIntent to local Listener wrappers. @@ -199,10 +209,7 @@ public class LocationManagerService extends ILocationManager.Stub { private int mSignalStrength = -1; // Location collector - private LocationCollector mCollector; - - // Location MASF service - private LocationMasfClient mMasfClient; + private ILocationCollector mCollector; // Wifi Manager private WifiManager mWifiManager; @@ -417,15 +424,9 @@ public class LocationManagerService extends ILocationManager.Stub { private void _loadProvidersNoSync() { // Attempt to load "real" providers first - if (NetworkLocationProvider.isSupported()) { - // Create a network location provider - mNetworkLocationProvider = new NetworkLocationProvider(mContext, mMasfClient); - LocationProviderImpl.addProvider(mNetworkLocationProvider); - } - if (GpsLocationProvider.isSupported()) { // Create a gps location provider - mGpsLocationProvider = new GpsLocationProvider(mContext, mCollector); + mGpsLocationProvider = new GpsLocationProvider(mContext); LocationProviderImpl.addProvider(mGpsLocationProvider); } @@ -509,18 +510,15 @@ public class LocationManagerService extends ILocationManager.Stub { Log.d(TAG, "Constructed LocationManager Service"); } - // Initialize the LocationMasfClient - mMasfClient = new LocationMasfClient(mContext); - - // Create location collector - mCollector = new LocationCollector(mMasfClient); - // Alarm manager, needs to be done before calling loadProviders() below mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); // Create a wake lock, needs to be done before calling loadProviders() below PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + + // Battery statistics service to be notified when GPS turns on or off + mBatteryStats = BatteryStatsService.getService(); // Load providers loadProviders(); @@ -560,13 +558,27 @@ public class LocationManagerService extends ILocationManager.Stub { if (mWifiManager != null) { List wifiScanResults = mWifiManager.getScanResults(); if (wifiScanResults != null && wifiScanResults.size() != 0) { - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.updateWifiScanResults(wifiScanResults); + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); } } } } + public void setNetworkLocationProvider(INetworkLocationProvider provider) { + mLocationHandler.removeMessages(MESSAGE_SET_NETWORK_LOCATION_PROVIDER); + Message m = Message.obtain(mLocationHandler, + MESSAGE_SET_NETWORK_LOCATION_PROVIDER, provider); + mLocationHandler.sendMessageAtFrontOfQueue(m); + } + + public void setLocationCollector(ILocationCollector collector) { + mCollector = collector; + if (mGpsLocationProvider != null) { + mGpsLocationProvider.setLocationCollector(mCollector); + } + } + private WifiManager.WifiLock getWifiWakelock() { if (mWifiLock == null && mWifiManager != null) { mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY); @@ -690,7 +702,8 @@ public class LocationManagerService extends ILocationManager.Stub { boolean shouldBeEnabled = isAllowedBySettings(name); // Collection is only allowed when network provider is being used - if (p.getName().equals(LocationManager.NETWORK_PROVIDER)) { + if (mCollector != null && + p.getName().equals(LocationManager.NETWORK_PROVIDER)) { mCollector.updateNetworkProviderStatus(shouldBeEnabled); } @@ -847,7 +860,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void _requestLocationUpdates(String provider, + private synchronized void _requestLocationUpdates(String provider, long minTime, float minDistance, Receiver receiver) { Object key = receiver.getKey(); if (Config.LOGD) { @@ -864,6 +877,7 @@ public class LocationManagerService extends ILocationManager.Stub { String[] packages = getPackageNames(); // so wakelock calls will succeed + mCallingUid = getCallingUid(); long identity = Binder.clearCallingIdentity(); try { UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, packages); @@ -889,12 +903,16 @@ public class LocationManagerService extends ILocationManager.Stub { oldRecord.dispose(); } - if (impl instanceof NetworkLocationProvider) { - ((NetworkLocationProvider) impl).addListener(packages); - } - boolean isProviderEnabled = isAllowedBySettings(provider); if (isProviderEnabled) { + if (provider.equals(LocationManager.GPS_PROVIDER)) { + try { + mBatteryStats.noteRequestGpsOn(mCallingUid); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling noteRequestGpsOff", e); + } + } + long minTimeForProvider = getMinTime(provider); impl.setMinTime(minTimeForProvider); impl.enableLocationTracking(true); @@ -904,7 +922,6 @@ public class LocationManagerService extends ILocationManager.Stub { mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); - } else { try { // Notify the listener that updates are currently disabled @@ -919,6 +936,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } finally { Binder.restoreCallingIdentity(identity); + mCallingUid = -1; } } @@ -942,13 +960,14 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void _removeUpdates(Receiver receiver) { + private synchronized void _removeUpdates(Receiver receiver) { Object key = receiver.getKey(); if (Config.LOGD) { Log.d(TAG, "_removeUpdates: listener = " + key); } // so wakelock calls will succeed + mCallingUid = getCallingUid(); long identity = Binder.clearCallingIdentity(); try { synchronized (mLocationListeners) { @@ -964,8 +983,8 @@ public class LocationManagerService extends ILocationManager.Stub { // Call dispose() on the obsolete update records. for (UpdateRecord record : oldRecords.values()) { if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) { - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.removeListener(record.mPackages); + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.removeListener(record.mPackages); } } record.dispose(); @@ -973,6 +992,14 @@ public class LocationManagerService extends ILocationManager.Stub { // Accumulate providers providers.addAll(oldRecords.keySet()); } + + if (providers.contains("gps")) { + try { + mBatteryStats.noteRequestGpsOff(mCallingUid); + } catch (RemoteException e) { + Log.w(TAG, "Got RemoteException calling noteRequestGpsOff", e); + } + } mLocationListeners.remove(key); mLastFixBroadcast.remove(key); @@ -1010,6 +1037,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } finally { Binder.restoreCallingIdentity(identity); + mCallingUid = -1; } } @@ -1426,7 +1454,7 @@ public class LocationManagerService extends ILocationManager.Stub { } writeLastKnownLocation(provider, loc); - if (p instanceof NetworkLocationProvider) { + if (p instanceof INetworkLocationProvider) { mWakeLockNetworkReceived = true; } else if (p instanceof GpsLocationProvider) { // Gps location received signal is in NetworkStateBroadcastReceiver @@ -1570,6 +1598,17 @@ public class LocationManagerService extends ILocationManager.Stub { // Update wakelock status so the next alarm is set before releasing wakelock updateWakelockStatus(mScreenOn); releaseWakeLock(); + } else if (msg.what == MESSAGE_SET_NETWORK_LOCATION_PROVIDER) { + synchronized (LocationManagerService.class) { + Log.d(TAG, "adding network location provider"); + mNetworkLocationInterface = + (INetworkLocationProvider)msg.obj; + mNetworkLocationInterface.addListener(getPackageNames()); + mNetworkLocationProvider = + (LocationProviderImpl)mNetworkLocationInterface; + LocationProviderImpl.addProvider(mNetworkLocationProvider); + updateProviders(); + } } } catch (Exception e) { // Log, don't crash! @@ -1590,7 +1629,9 @@ public class LocationManagerService extends ILocationManager.Stub { mLastCellState = new CellState(mTelephonyManager, cellLocation, asu); // Notify collector - mCollector.updateCellState(mLastCellState); + if (mCollector != null) { + mCollector.updateCellState(mLastCellState); + } // Updates providers List providers = LocationProviderImpl.getProviders(); @@ -1648,7 +1689,9 @@ public class LocationManagerService extends ILocationManager.Stub { boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0; // Notify collector battery state - mCollector.updateBatteryState(scale, level, plugged); + if (mCollector != null) { + mCollector.updateBatteryState(scale, level, plugged); + } } } } @@ -1666,9 +1709,11 @@ public class LocationManagerService extends ILocationManager.Stub { } // Notify provider and collector of Wifi scan results - mCollector.updateWifiScanResults(wifiScanResults); - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.updateWifiScanResults(wifiScanResults); + if (mCollector != null) { + mCollector.updateWifiScanResults(wifiScanResults); + } + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); } } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { @@ -1702,8 +1747,8 @@ public class LocationManagerService extends ILocationManager.Stub { } // Notify network provider of current wifi enabled state - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.updateWifiEnabledState(enabled); + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.updateWifiEnabledState(enabled); } } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { @@ -1821,8 +1866,8 @@ public class LocationManagerService extends ILocationManager.Stub { } // Notify NetworkLocationProvider - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired); + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); } // Acquire wifi lock @@ -1845,6 +1890,14 @@ public class LocationManagerService extends ILocationManager.Stub { && mGpsLocationProvider.isLocationTracking(); if (gpsActive) { mGpsLocationProvider.startNavigating(); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteStartGps(mCallingUid == -1 ? getCallingUid() : mCallingUid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling noteStartGps on BatteryStatsService", e); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1853,6 +1906,14 @@ public class LocationManagerService extends ILocationManager.Stub { && mGpsLocationProvider.isLocationTracking(); if (gpsActive) { mGpsLocationProvider.stopNavigating(); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteStopGps(mCallingUid == -1 ? getCallingUid() : mCallingUid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling noteStopGps on BatteryStatsService", e); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -1877,7 +1938,6 @@ public class LocationManagerService extends ILocationManager.Stub { } if (!mScreenOn) { - // Stop the gps stopGps(); } @@ -1889,8 +1949,8 @@ public class LocationManagerService extends ILocationManager.Stub { } // Notify NetworkLocationProvider - if (mNetworkLocationProvider != null) { - mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired); + if (mNetworkLocationInterface != null) { + mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); } // Release wake lock @@ -1907,14 +1967,10 @@ public class LocationManagerService extends ILocationManager.Stub { public String getFromLocation(double latitude, double longitude, int maxResults, String language, String country, String variant, String appName, List
addrs) { - try { - Locale locale = new Locale(language, country, variant); - mMasfClient.reverseGeocode(locale, appName, latitude, longitude, maxResults, addrs); - return null; - } catch(IOException e) { - return e.getMessage(); - } catch(Exception e) { - Log.e(TAG, "getFromLocation got exception:", e); + if (mNetworkLocationInterface != null) { + return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults, + language, country, variant, appName, addrs); + } else { return null; } } @@ -1923,17 +1979,11 @@ public class LocationManagerService extends ILocationManager.Stub { double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude, int maxResults, String language, String country, String variant, String appName, List
addrs) { - - try { - Locale locale = new Locale(language, country, variant); - mMasfClient.forwardGeocode(locale, appName, locationName, - lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude, - maxResults, addrs); - return null; - } catch(IOException e) { - return e.getMessage(); - } catch(Exception e) { - Log.e(TAG, "getFromLocationName got exception:", e); + if (mNetworkLocationInterface != null) { + return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, + lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults, + language, country, variant, appName, addrs); + } else { return null; } } diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java index 40d1b72..2e430c8 100644 --- a/services/java/com/android/server/MountListener.java +++ b/services/java/com/android/server/MountListener.java @@ -30,7 +30,7 @@ import java.io.OutputStream; import java.net.Socket; /** - * Thread for communicating with the mount service daemon via a local socket. + * Thread for communicating with the vol service daemon via a local socket. * Events received from the daemon are passed to the MountService instance, * and the MountService instance calls MountListener to send commands to the daemon. */ @@ -38,39 +38,43 @@ final class MountListener implements Runnable { private static final String TAG = "MountListener"; - // ** THE FOLLOWING STRING CONSTANTS MUST MATCH VALUES IN system/mountd/mountd.h + // ** THE FOLLOWING STRING CONSTANTS MUST MATCH VALUES IN system/vold/ - // socket name for connecting to mountd - private static final String MOUNTD_SOCKET = "mountd"; + // socket name for connecting to vold + private static final String VOLD_SOCKET = "vold"; - // mountd commands - private static final String MOUNTD_ENABLE_UMS = "enable_ums"; - private static final String MOUNTD_DISABLE_UMS = "disable_ums"; - private static final String MOUNTD_SEND_STATUS = "send_status"; - private static final String MOUNTD_MOUNT_MEDIA = "mount_media:"; - private static final String MOUNTD_EJECT_MEDIA = "eject_media:"; + // vold commands + private static final String VOLD_CMD_ENABLE_UMS = "enable_ums"; + private static final String VOLD_CMD_DISABLE_UMS = "disable_ums"; + private static final String VOLD_CMD_SEND_UMS_STATUS = "send_ums_status"; + private static final String VOLD_CMD_MOUNT_VOLUME = "mount_volume:"; + private static final String VOLD_CMD_EJECT_MEDIA = "eject_media:"; + private static final String VOLD_CMD_FORMAT_MEDIA = "format_media:"; - // mountd events - private static final String MOUNTD_UMS_ENABLED = "ums_enabled"; - private static final String MOUNTD_UMS_DISABLED = "ums_disabled"; - private static final String MOUNTD_UMS_CONNECTED = "ums_connected"; - private static final String MOUNTD_UMS_DISCONNECTED = "ums_disconnected"; - private static final String MOUNTD_MEDIA_REMOVED = "media_removed:"; - private static final String MOUNTD_MEDIA_UNMOUNTED = "media_unmounted:"; - private static final String MOUNTD_MEDIA_MOUNTED = "media_mounted:"; - private static final String MOUNTD_MEDIA_MOUNTED_READ_ONLY = "media_mounted_ro:"; - private static final String MOUNTD_MEDIA_SHARED = "media_shared:"; - private static final String MOUNTD_MEDIA_BAD_REMOVAL = "media_bad_removal:"; - private static final String MOUNTD_MEDIA_UNMOUNTABLE = "media_unmountable:"; - private static final String MOUNTD_REQUEST_EJECT = "request_eject:"; + // vold events + private static final String VOLD_EVT_UMS_ENABLED = "ums_enabled"; + private static final String VOLD_EVT_UMS_DISABLED = "ums_disabled"; + private static final String VOLD_EVT_UMS_CONNECTED = "ums_connected"; + private static final String VOLD_EVT_UMS_DISCONNECTED = "ums_disconnected"; + + private static final String VOLD_EVT_NOMEDIA = "volume_nomedia:"; + private static final String VOLD_EVT_UNMOUNTED = "volume_unmounted:"; + private static final String VOLD_EVT_MOUNTED = "volume_mounted:"; + private static final String VOLD_EVT_MOUNTED_RO = "volume_mounted_ro:"; + private static final String VOLD_EVT_UMS = "volume_ums"; + private static final String VOLD_EVT_BAD_REMOVAL = "volume_badremoval:"; + private static final String VOLD_EVT_DAMAGED = "volume_damaged:"; + private static final String VOLD_EVT_CHECKING = "volume_checking:"; + private static final String VOLD_EVT_NOFS = "volume_nofs:"; + private static final String VOLD_EVT_EJECTING = "volume_ejecting:"; /** - * MountService that handles events received from the mount service daemon + * MountService that handles events received from the vol service daemon */ private MountService mService; /** - * Stream for sending commands to the mount service daemon. + * Stream for sending commands to the vol service daemon. */ private OutputStream mOutputStream; @@ -95,9 +99,9 @@ final class MountListener implements Runnable { } /** - * Process and dispatches events received from the mount service daemon + * Process and dispatches events received from the vol service daemon * - * @param event An event received from the mount service daemon + * @param event An event received from the vol service daemon */ private void handleEvent(String event) { if (Config.LOGD) Log.d(TAG, "handleEvent " + event); @@ -105,34 +109,38 @@ final class MountListener implements Runnable { int colonIndex = event.indexOf(':'); String path = (colonIndex > 0 ? event.substring(colonIndex + 1) : null); - if (event.equals(MOUNTD_UMS_ENABLED)) { + if (event.equals(VOLD_EVT_UMS_ENABLED)) { mUmsEnabled = true; - } else if (event.equals(MOUNTD_UMS_DISABLED)) { + } else if (event.equals(VOLD_EVT_UMS_DISABLED)) { mUmsEnabled = false; - } else if (event.equals(MOUNTD_UMS_CONNECTED)) { + } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) { mUmsConnected = true; mService.notifyUmsConnected(); - } else if (event.equals(MOUNTD_UMS_DISCONNECTED)) { + } else if (event.equals(VOLD_EVT_UMS_DISCONNECTED)) { mUmsConnected = false; mService.notifyUmsDisconnected(); - } else if (event.startsWith(MOUNTD_MEDIA_REMOVED)) { + } else if (event.startsWith(VOLD_EVT_NOMEDIA)) { mService.notifyMediaRemoved(path); - } else if (event.startsWith(MOUNTD_MEDIA_UNMOUNTED)) { + } else if (event.startsWith(VOLD_EVT_UNMOUNTED)) { mService.notifyMediaUnmounted(path); - } else if (event.startsWith(MOUNTD_MEDIA_MOUNTED)) { + } else if (event.startsWith(VOLD_EVT_CHECKING)) { + mService.notifyMediaChecking(path); + } else if (event.startsWith(VOLD_EVT_NOFS)) { + mService.notifyMediaNoFs(path); + } else if (event.startsWith(VOLD_EVT_MOUNTED)) { mService.notifyMediaMounted(path, false); - } else if (event.startsWith(MOUNTD_MEDIA_MOUNTED_READ_ONLY)) { + } else if (event.startsWith(VOLD_EVT_MOUNTED_RO)) { mService.notifyMediaMounted(path, true); - } else if (event.startsWith(MOUNTD_MEDIA_SHARED)) { + } else if (event.startsWith(VOLD_EVT_UMS)) { mService.notifyMediaShared(path); - } else if (event.startsWith(MOUNTD_MEDIA_BAD_REMOVAL)) { + } else if (event.startsWith(VOLD_EVT_BAD_REMOVAL)) { mService.notifyMediaBadRemoval(path); // also send media eject intent, to notify apps to close any open // files on the media. mService.notifyMediaEject(path); - } else if (event.startsWith(MOUNTD_MEDIA_UNMOUNTABLE)) { + } else if (event.startsWith(VOLD_EVT_DAMAGED)) { mService.notifyMediaUnmountable(path); - } else if (event.startsWith(MOUNTD_REQUEST_EJECT)) { + } else if (event.startsWith(VOLD_EVT_EJECTING)) { mService.notifyMediaEject(path); } } @@ -156,7 +164,7 @@ final class MountListener implements Runnable { private void writeCommand2(String command, String argument) { synchronized (this) { if (mOutputStream == null) { - Log.e(TAG, "No connection to mountd", new IllegalStateException()); + Log.e(TAG, "No connection to vold", new IllegalStateException()); } else { StringBuilder builder = new StringBuilder(command); if (argument != null) { @@ -183,7 +191,7 @@ final class MountListener implements Runnable { try { socket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress(MOUNTD_SOCKET, + LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET, LocalSocketAddress.Namespace.RESERVED); socket.connect(address); @@ -193,7 +201,7 @@ final class MountListener implements Runnable { byte[] buffer = new byte[100]; - writeCommand(MOUNTD_SEND_STATUS); + writeCommand(VOLD_CMD_SEND_UMS_STATUS); while (true) { int count = inputStream.read(buffer); @@ -242,7 +250,7 @@ final class MountListener implements Runnable { * create tons of throwaway LocalSockets, making * system_server GC constantly. */ - Log.e(TAG, "Failed to connect to mountd", new IllegalStateException()); + Log.e(TAG, "Failed to connect to vold", new IllegalStateException()); SystemClock.sleep(2000); } @@ -283,7 +291,7 @@ final class MountListener implements Runnable { * @param enable true to enable USB mass storage support */ void setMassStorageEnabled(boolean enable) { - writeCommand(enable ? MOUNTD_ENABLE_UMS : MOUNTD_DISABLE_UMS); + writeCommand(enable ? VOLD_CMD_ENABLE_UMS : VOLD_CMD_DISABLE_UMS); } /** @@ -297,14 +305,20 @@ final class MountListener implements Runnable { * Mount media at given mount point. */ public void mountMedia(String mountPoint) { - writeCommand2(MOUNTD_MOUNT_MEDIA, mountPoint); + writeCommand2(VOLD_CMD_MOUNT_VOLUME, mountPoint); } /** * Unmount media at given mount point. */ public void ejectMedia(String mountPoint) { - writeCommand2(MOUNTD_EJECT_MEDIA, mountPoint); + writeCommand2(VOLD_CMD_EJECT_MEDIA, mountPoint); } -} + /** + * Format media at given mount point. + */ + public void formatMedia(String mountPoint) { + writeCommand2(VOLD_CMD_FORMAT_MEDIA, mountPoint); + } +} diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 002ebed..0feb1da 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -19,15 +19,19 @@ package com.android.server; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.os.IMountService; import android.os.Environment; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UEventObserver; +import android.text.TextUtils; import android.util.Log; import java.io.File; @@ -52,24 +56,32 @@ class MountService extends IMountService.Stub { private MountListener mListener; /** - * The notification that is shown when USB is connected. It leads the user - * to a dialog to enable mass storage mode. + * The notification that is shown when a USB mass storage host + * is connected. *

- * This is lazily created, so use {@link #getUsbStorageNotification()}. + * This is lazily created, so use {@link #setUsbStorageNotification()}. */ private Notification mUsbStorageNotification; - private class SdDoorListener extends UEventObserver { - static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/sd-door"; - static final String SD_DOOR_SWITCH_NAME = "sd-door"; - public void onUEvent(UEvent event) { - if (SD_DOOR_SWITCH_NAME.equals(event.get("SWITCH_NAME"))) { - sdDoorStateChanged(event.get("SWITCH_STATE")); - } - } - }; + /** + * The notification that is shown when the following media events occur: + * - Media is being checked + * - Media is blank (or unknown filesystem) + * - Media is corrupt + * - Media is safe to unmount + * - Media is missing + *

+ * This is lazily created, so use {@link #setMediaStorageNotification()}. + */ + private Notification mMediaStorageNotification; + private boolean mShowSafeUnmountNotificationWhenUnmounted; + + private boolean mPlaySounds; + + private boolean mMounted; + /** * Constructs a new MountService instance * @@ -77,13 +89,28 @@ class MountService extends IMountService.Stub { */ public MountService(Context context) { mContext = context; + + // Register a BOOT_COMPLETED handler so that we can start + // MountListener. We defer the startup so that we don't + // start processing events before we ought-to + mContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + mListener = new MountListener(this); - Thread thread = new Thread(mListener, MountListener.class.getName()); - thread.start(); - SdDoorListener sdDoorListener = new SdDoorListener(); - sdDoorListener.startObserving(SdDoorListener.SD_DOOR_UEVENT_MATCH); + mShowSafeUnmountNotificationWhenUnmounted = false; + + mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1"); } + BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { + Thread thread = new Thread(mListener, MountListener.class.getName()); + thread.start(); + } + } + }; + /** * @return true if USB mass storage support is enabled. */ @@ -129,19 +156,92 @@ class MountService extends IMountService.Stub { throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission"); } + // Set a flag so that when we get the unmounted event, we know + // to display the notification + mShowSafeUnmountNotificationWhenUnmounted = true; + // tell mountd to unmount the media mListener.ejectMedia(mountPath); } /** + * Attempt to format external media + */ + public void formatMedia(String formatPath) throws RemoteException { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission"); + } + + mListener.formatMedia(formatPath); + } + + /** + * Returns true if we're playing media notification sounds. + */ + public boolean getPlayNotificationSounds() { + return mPlaySounds; + } + + /** + * Set whether or not we're playing media notification sounds. + */ + public void setPlayNotificationSounds(boolean enabled) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires WRITE_SETTINGS permission"); + } + mPlaySounds = enabled; + SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0")); + } + + /** + * Update the state of the USB mass storage notification + */ + void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) { + + try { + + if (getMassStorageConnected() && !suppressIfConnected) { + Intent intent = new Intent(); + intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class); + PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); + setUsbStorageNotification( + com.android.internal.R.string.usb_storage_notification_title, + com.android.internal.R.string.usb_storage_notification_message, + com.android.internal.R.drawable.stat_sys_data_usb, + sound, true, pi); + } else { + setUsbStorageNotification(0, 0, 0, false, false, null); + } + } catch (RemoteException e) { + // Nothing to do + } + } + + void handlePossibleExplicitUnmountBroadcast(String path) { + if (mMounted) { + mMounted = false; + Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, + Uri.parse("file://" + path)); + mContext.sendBroadcast(intent); + } + } + + /** * Broadcasts the USB mass storage connected event to all clients. */ void notifyUmsConnected() { String storageState = Environment.getExternalStorageState(); if (!storageState.equals(Environment.MEDIA_REMOVED) && - !storageState.equals(Environment.MEDIA_BAD_REMOVAL)) { - setUsbStorageNotificationVisibility(true); + !storageState.equals(Environment.MEDIA_BAD_REMOVAL) && + !storageState.equals(Environment.MEDIA_CHECKING)) { + + updateUsbMassStorageNotification(false, true); } + Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED); mContext.sendBroadcast(intent); } @@ -150,7 +250,7 @@ class MountService extends IMountService.Stub { * Broadcasts the USB mass storage disconnected event to all clients. */ void notifyUmsDisconnected() { - setUsbStorageNotificationVisibility(false); + updateUsbMassStorageNotification(false, false); Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); mContext.sendBroadcast(intent); } @@ -159,6 +259,15 @@ class MountService extends IMountService.Stub { * Broadcasts the media removed event to all clients. */ void notifyMediaRemoved(String path) { + updateUsbMassStorageNotification(true, false); + + setMediaStorageNotification( + com.android.internal.R.string.ext_media_nomedia_notification_title, + com.android.internal.R.string.ext_media_nomedia_notification_message, + com.android.internal.R.drawable.stat_sys_no_sim, + true, false, null); + handlePossibleExplicitUnmountBroadcast(path); + Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); mContext.sendBroadcast(intent); @@ -168,18 +277,68 @@ class MountService extends IMountService.Stub { * Broadcasts the media unmounted event to all clients. */ void notifyMediaUnmounted(String path) { + if (mShowSafeUnmountNotificationWhenUnmounted) { + setMediaStorageNotification( + com.android.internal.R.string.ext_media_safe_unmount_notification_title, + com.android.internal.R.string.ext_media_safe_unmount_notification_message, + com.android.internal.R.drawable.stat_notify_sim_toolkit, + true, true, null); + mShowSafeUnmountNotificationWhenUnmounted = false; + } else { + setMediaStorageNotification(0, 0, 0, false, false, null); + } + updateUsbMassStorageNotification(false, false); + Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); mContext.sendBroadcast(intent); } /** + * Broadcasts the media checking event to all clients. + */ + void notifyMediaChecking(String path) { + setMediaStorageNotification( + com.android.internal.R.string.ext_media_checking_notification_title, + com.android.internal.R.string.ext_media_checking_notification_message, + com.android.internal.R.drawable.stat_notify_sim_toolkit, + true, false, null); + + updateUsbMassStorageNotification(true, false); + Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING, + Uri.parse("file://" + path)); + mContext.sendBroadcast(intent); + } + + /** + * Broadcasts the media nofs event to all clients. + */ + void notifyMediaNoFs(String path) { + + Intent intent = new Intent(); + intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class); + PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); + + setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title, + com.android.internal.R.string.ext_media_nofs_notification_message, + com.android.internal.R.drawable.stat_sys_no_sim, + true, false, pi); + updateUsbMassStorageNotification(false, false); + intent = new Intent(Intent.ACTION_MEDIA_NOFS, + Uri.parse("file://" + path)); + mContext.sendBroadcast(intent); + } + + /** * Broadcasts the media mounted event to all clients. */ void notifyMediaMounted(String path, boolean readOnly) { + setMediaStorageNotification(0, 0, 0, false, false, null); + updateUsbMassStorageNotification(false, false); Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); intent.putExtra("read-only", readOnly); + mMounted = true; mContext.sendBroadcast(intent); } @@ -187,7 +346,15 @@ class MountService extends IMountService.Stub { * Broadcasts the media shared event to all clients. */ void notifyMediaShared(String path) { - Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED, + Intent intent = new Intent(); + intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class); + PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); + setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title, + com.android.internal.R.string.usb_storage_stop_notification_message, + com.android.internal.R.drawable.stat_sys_warning, + false, true, pi); + handlePossibleExplicitUnmountBroadcast(path); + intent = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); mContext.sendBroadcast(intent); } @@ -196,16 +363,39 @@ class MountService extends IMountService.Stub { * Broadcasts the media bad removal event to all clients. */ void notifyMediaBadRemoval(String path) { + updateUsbMassStorageNotification(true, false); + setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title, + com.android.internal.R.string.ext_media_badremoval_notification_message, + com.android.internal.R.drawable.stat_sys_warning, + true, true, null); + + handlePossibleExplicitUnmountBroadcast(path); Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); mContext.sendBroadcast(intent); + + intent = new Intent(Intent.ACTION_MEDIA_REMOVED, + Uri.parse("file://" + path)); + mContext.sendBroadcast(intent); } /** * Broadcasts the media unmountable event to all clients. */ void notifyMediaUnmountable(String path) { - Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, + Intent intent = new Intent(); + intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class); + PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); + + setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title, + com.android.internal.R.string.ext_media_unmountable_notification_message, + com.android.internal.R.drawable.stat_sys_no_sim, + true, false, pi); + updateUsbMassStorageNotification(false, false); + + handlePossibleExplicitUnmountBroadcast(path); + + intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); mContext.sendBroadcast(intent); } @@ -219,90 +409,129 @@ class MountService extends IMountService.Stub { mContext.sendBroadcast(intent); } - private void sdDoorStateChanged(String doorState) { - File directory = Environment.getExternalStorageDirectory(); - String storageState = Environment.getExternalStorageState(); - - if (directory != null) { - try { - if (doorState.equals("open") && (storageState.equals(Environment.MEDIA_MOUNTED) || - storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY))) { - // request SD card unmount if SD card door is opened - unmountMedia(directory.getPath()); - } else if (doorState.equals("closed") && storageState.equals(Environment.MEDIA_UNMOUNTED)) { - // attempt to remount SD card - mountMedia(directory.getPath()); - } - } catch (RemoteException e) { - // Nothing to do. - } - } - } - /** - * Sets the visibility of the USB storage notification. This should be - * called when a USB cable is connected and also when it is disconnected. - * - * @param visible Whether to show or hide the notification. + * Sets the USB storage notification. */ - private void setUsbStorageNotificationVisibility(boolean visible) { + private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible, + PendingIntent pi) { + + if (!visible && mUsbStorageNotification == null) { + return; + } + NotificationManager notificationManager = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); + if (notificationManager == null) { return; } - - /* - * The convention for notification IDs is to use the icon's resource ID - * when the icon is only used by a single notification type, which is - * the case here. - */ - Notification notification = getUsbStorageNotification(); - final int notificationId = notification.icon; if (visible) { - notificationManager.notify(notificationId, notification); + Resources r = Resources.getSystem(); + CharSequence title = r.getText(titleId); + CharSequence message = r.getText(messageId); + + if (mUsbStorageNotification == null) { + mUsbStorageNotification = new Notification(); + mUsbStorageNotification.icon = icon; + mUsbStorageNotification.when = 0; + } + + if (sound && mPlaySounds) { + mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND; + } else { + mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND; + } + + mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT; + + mUsbStorageNotification.tickerText = title; + if (pi == null) { + Intent intent = new Intent(); + pi = PendingIntent.getBroadcast(mContext, 0, intent, 0); + } + + mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi); + } + + final int notificationId = mUsbStorageNotification.icon; + if (visible) { + notificationManager.notify(notificationId, mUsbStorageNotification); } else { notificationManager.cancel(notificationId); } } + private synchronized boolean getMediaStorageNotificationDismissable() { + if ((mMediaStorageNotification != null) && + ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) == + Notification.FLAG_AUTO_CANCEL)) + return true; + + return false; + } + /** - * Gets the USB storage notification. - * - * @return A {@link Notification} that leads to the dialog to enable USB storage. + * Sets the media storage notification. */ - private synchronized Notification getUsbStorageNotification() { - Resources r = Resources.getSystem(); - CharSequence title = - r.getText(com.android.internal.R.string.usb_storage_notification_title); - CharSequence message = - r.getText(com.android.internal.R.string.usb_storage_notification_message); - - if (mUsbStorageNotification == null) { - mUsbStorageNotification = new Notification(); - mUsbStorageNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb; - mUsbStorageNotification.when = 0; - mUsbStorageNotification.flags = Notification.FLAG_AUTO_CANCEL; - mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND; + private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible, + boolean dismissable, PendingIntent pi) { + + if (!visible && mMediaStorageNotification == null) { + return; } - mUsbStorageNotification.tickerText = title; - mUsbStorageNotification.setLatestEventInfo(mContext, title, message, - getUsbStorageDialogIntent()); + NotificationManager notificationManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); - return mUsbStorageNotification; - } + if (notificationManager == null) { + return; + } + + if (mMediaStorageNotification != null && visible) { + /* + * Dismiss the previous notification - we're about to + * re-use it. + */ + final int notificationId = mMediaStorageNotification.icon; + notificationManager.cancel(notificationId); + } + + if (visible) { + Resources r = Resources.getSystem(); + CharSequence title = r.getText(titleId); + CharSequence message = r.getText(messageId); + + if (mMediaStorageNotification == null) { + mMediaStorageNotification = new Notification(); + mMediaStorageNotification.when = 0; + if (mPlaySounds) { + mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND; + } + } + + if (dismissable) { + mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL; + } else { + mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT; + } + + mMediaStorageNotification.tickerText = title; + if (pi == null) { + Intent intent = new Intent(); + pi = PendingIntent.getBroadcast(mContext, 0, intent, 0); + } + + mMediaStorageNotification.icon = icon; + mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi); + } - /** - * Creates a pending intent to start the USB storage activity. - * - * @return A {@link PendingIntent} that start the USB storage activity. - */ - private PendingIntent getUsbStorageDialogIntent() { - Intent intent = new Intent(); - intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class); - return PendingIntent.getActivity(mContext, 0, intent, 0); + final int notificationId = mMediaStorageNotification.icon; + if (visible) { + notificationManager.notify(notificationId, mMediaStorageNotification); + } else { + notificationManager.cancel(notificationId); + } } } diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java index 11dbe63..1ea0bac 100644 --- a/services/java/com/android/server/NetStatService.java +++ b/services/java/com/android/server/NetStatService.java @@ -26,20 +26,35 @@ public class NetStatService extends INetStatService.Stub { } - public int getTxPackets() { - return NetStat.netStatGetTxPkts(); + public long getMobileTxPackets() { + return NetStat.getMobileTxPkts(); } - public int getRxPackets() { - return NetStat.netStatGetRxPkts(); + public long getMobileRxPackets() { + return NetStat.getMobileRxPkts(); } - public int getTxBytes() { - return NetStat.netStatGetTxBytes(); + public long getMobileTxBytes() { + return NetStat.getMobileTxBytes(); } - public int getRxBytes() { - return NetStat.netStatGetRxBytes(); + public long getMobileRxBytes() { + return NetStat.getMobileRxBytes(); } + public long getTotalTxPackets() { + return NetStat.getTotalTxPkts(); + } + + public long getTotalRxPackets() { + return NetStat.getTotalRxPkts(); + } + + public long getTotalTxBytes() { + return NetStat.getTotalTxBytes(); + } + + public long getTotalRxBytes() { + return NetStat.getTotalRxBytes(); + } } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index eb9ebe9..e5de7f9 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -865,7 +865,7 @@ class NotificationManagerService extends INotificationManager.Stub // ====================================================================== @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission("android.permission.DUMP") + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump NotificationManager from from pid=" + Binder.getCallingPid() diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 58ad426..221ba46 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -97,6 +97,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; @@ -983,6 +984,20 @@ class PackageManagerService extends IPackageManager.Stub { } return null; } + + public String[] getSystemSharedLibraryNames() { + Set libSet; + synchronized (mPackages) { + libSet = mSharedLibraries.keySet(); + } + int size = libSet.size(); + if (size > 0) { + String[] libs = new String[size]; + libSet.toArray(libs); + return libs; + } + return null; + } public int checkPermission(String permName, String pkgName) { synchronized (mPackages) { @@ -2678,7 +2693,7 @@ class PackageManagerService extends IPackageManager.Stub { grantPermissionsLP(pkg, false); } } - + private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) { final PackageSetting ps = (PackageSetting)pkg.mExtras; if (ps == null) { @@ -2724,7 +2739,19 @@ class PackageManagerService extends IPackageManager.Stub { == PackageManager.SIGNATURE_MATCH); if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - allowed = true; + // For updated system applications, the signatureOrSystem permission + // is granted only if it had been defined by the original application. + if ((pkg.applicationInfo.flags + & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName); + if(sysPs.grantedPermissions.contains(perm)) { + allowed = true; + } else { + allowed = false; + } + } else { + allowed = true; + } } } } else { @@ -3157,6 +3184,7 @@ class PackageManagerService extends IPackageManager.Stub { if (removedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedUid); + extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras); } if (addedPackage != null) { @@ -3194,7 +3222,7 @@ class PackageManagerService extends IPackageManager.Stub { // There appears to be a subtle deadlock condition if the sendPackageBroadcast call appears // in the synchronized block above. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - res.removedInfo.sendBroadcast(); + res.removedInfo.sendBroadcast(false, true); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, @@ -3842,7 +3870,7 @@ class PackageManagerService extends IPackageManager.Stub { } if(res && sendBroadCast) { - info.sendBroadcast(); + info.sendBroadcast(deleteCodeAndResources, false); } return res; } @@ -3852,9 +3880,13 @@ class PackageManagerService extends IPackageManager.Stub { int uid = -1; int removedUid = -1; - void sendBroadcast() { + void sendBroadcast(boolean fullRemove, boolean replacing) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid); + extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove); + if (replacing) { + extras.putBoolean(Intent.EXTRA_REPLACING, true); + } if (removedPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras); } @@ -4463,6 +4495,10 @@ class PackageManagerService extends IPackageManager.Stub { mSystemReady = true; } + public boolean isSafeMode() { + return mSafeMode; + } + public boolean hasSystemUidErrors() { return mHasSystemUidErrors; } @@ -4482,7 +4518,7 @@ class PackageManagerService extends IPackageManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump ActivityManager from from pid=" + Binder.getCallingPid() @@ -5637,23 +5673,8 @@ class PackageManagerService extends IPackageManager.Stub { } for (PackageSetting pkg : mDisabledSysPackages.values()) { - serializer.startTag(null, "updated-package"); - serializer.attribute(null, "name", pkg.name); - serializer.attribute(null, "codePath", pkg.codePathString); - serializer.attribute(null, "ts", pkg.getTimeStampStr()); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } - if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", - Integer.toString(pkg.userId)); - } else { - serializer.attribute(null, "sharedUserId", - Integer.toString(pkg.userId)); - } - serializer.endTag(null, "updated-package"); + writeDisabledSysPackage(serializer, pkg); } - serializer.startTag(null, "preferred-packages"); int N = mPreferredPackages.size(); @@ -5716,6 +5737,43 @@ class PackageManagerService extends IPackageManager.Stub { //Debug.stopMethodTracing(); } + void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg) + throws java.io.IOException { + serializer.startTag(null, "updated-package"); + serializer.attribute(null, "name", pkg.name); + serializer.attribute(null, "codePath", pkg.codePathString); + serializer.attribute(null, "ts", pkg.getTimeStampStr()); + if (!pkg.resourcePathString.equals(pkg.codePathString)) { + serializer.attribute(null, "resourcePath", pkg.resourcePathString); + } + if (pkg.sharedUser == null) { + serializer.attribute(null, "userId", + Integer.toString(pkg.userId)); + } else { + serializer.attribute(null, "sharedUserId", + Integer.toString(pkg.userId)); + } + serializer.startTag(null, "perms"); + if (pkg.sharedUser == null) { + // If this is a shared user, the permissions will + // be written there. We still need to write an + // empty permissions list so permissionsFixed will + // be set. + for (final String name : pkg.grantedPermissions) { + BasePermission bp = mPermissions.get(name); + if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) { + // We only need to write signature or system permissions but this wont + // match the semantics of grantedPermissions. So write all permissions. + serializer.startTag(null, "item"); + serializer.attribute(null, "name", name); + serializer.endTag(null, "item"); + } + } + } + serializer.endTag(null, "perms"); + serializer.endTag(null, "updated-package"); + } + void writePackage(XmlSerializer serializer, final PackageSetting pkg) throws java.io.IOException { serializer.startTag(null, "package"); @@ -5892,33 +5950,7 @@ class PackageManagerService extends IPackageManager.Stub { } else if (tagName.equals("preferred-activities")) { readPreferredActivitiesLP(parser); } else if(tagName.equals("updated-package")) { - String name = parser.getAttributeValue(null, "name"); - String codePathStr = parser.getAttributeValue(null, "codePath"); - String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); - if(resourcePathStr == null) { - resourcePathStr = codePathStr; - } - - int pkgFlags = 0; - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - PackageSetting ps = new PackageSetting(name, - new File(codePathStr), - new File(resourcePathStr), pkgFlags); - String timeStampStr = parser.getAttributeValue(null, "ts"); - if (timeStampStr != null) { - try { - long timeStamp = Long.parseLong(timeStampStr); - ps.setTimeStamp(timeStamp, timeStampStr); - } catch (NumberFormatException e) { - } - } - String idStr = parser.getAttributeValue(null, "userId"); - ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; - if(ps.userId <= 0) { - String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; - } - mDisabledSysPackages.put(name, ps); + readDisabledSysPackageLP(parser); } else { Log.w(TAG, "Unknown element under : " + parser.getName()); @@ -6056,6 +6088,58 @@ class PackageManagerService extends IPackageManager.Stub { } } + private void readDisabledSysPackageLP(XmlPullParser parser) + throws XmlPullParserException, IOException { + String name = parser.getAttributeValue(null, "name"); + String codePathStr = parser.getAttributeValue(null, "codePath"); + String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + if(resourcePathStr == null) { + resourcePathStr = codePathStr; + } + + int pkgFlags = 0; + pkgFlags |= ApplicationInfo.FLAG_SYSTEM; + PackageSetting ps = new PackageSetting(name, + new File(codePathStr), + new File(resourcePathStr), pkgFlags); + String timeStampStr = parser.getAttributeValue(null, "ts"); + if (timeStampStr != null) { + try { + long timeStamp = Long.parseLong(timeStampStr); + ps.setTimeStamp(timeStamp, timeStampStr); + } catch (NumberFormatException e) { + } + } + String idStr = parser.getAttributeValue(null, "userId"); + ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; + if(ps.userId <= 0) { + String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); + ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + } + int outerDepth = parser.getDepth(); + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("perms")) { + readGrantedPermissionsLP(parser, + ps.grantedPermissions); + } else { + reportSettingsProblem(Log.WARN, + "Unknown element under : " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + mDisabledSysPackages.put(name, ps); + } + private void readPackageLP(XmlPullParser parser) throws XmlPullParserException, IOException { String name = null; diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index ca0ad1a..7c111d3 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -486,8 +486,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage public void acquireWakeLock(int flags, IBinder lock, String tag) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - synchronized (mLocks) { - acquireWakeLockLocked(flags, lock, tag); + long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLocks) { + acquireWakeLockLocked(flags, lock, tag); + } + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -572,12 +577,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } if (acquireType >= 0) { + long origId = Binder.clearCallingIdentity(); try { - long origId = Binder.clearCallingIdentity(); mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType); - Binder.restoreCallingIdentity(origId); } catch (RemoteException e) { // Ignore + } finally { + Binder.restoreCallingIdentity(origId); } } } @@ -627,12 +633,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage releaseType = wl.monitorType; if (releaseType >= 0) { + long origId = Binder.clearCallingIdentity(); try { - long origId = Binder.clearCallingIdentity(); mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType); - Binder.restoreCallingIdentity(origId); } catch (RemoteException e) { // Ignore + } finally { + Binder.restoreCallingIdentity(origId); } } } @@ -757,7 +764,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump PowerManager from from pid=" + Binder.getCallingPid() @@ -960,8 +967,10 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock); } if (mContext != null) { - mContext.sendOrderedBroadcast(mScreenOnIntent, null, - mScreenOnBroadcastDone, mHandler, 0, null, null); + if (ActivityManagerNative.isSystemReady()) { + mContext.sendOrderedBroadcast(mScreenOnIntent, null, + mScreenOnBroadcastDone, mHandler, 0, null, null); + } } else { synchronized (mLocks) { EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2, @@ -1232,6 +1241,14 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } if (reallyTurnScreenOn) { err = Power.setScreenState(true); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteScreenOn(); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e); + } finally { + Binder.restoreCallingIdentity(identity); + } } else { Power.setScreenState(false); // But continue as if we really did turn the screen on... @@ -1250,6 +1267,14 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage } } else { mScreenOffTime = SystemClock.elapsedRealtime(); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteScreenOff(); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e); + } finally { + Binder.restoreCallingIdentity(identity); + } if (!mScreenBrightness.animating) { err = turnScreenOffLocked(becauseOfUser); } else { diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java index f56088c..461b006 100644 --- a/services/java/com/android/server/SensorService.java +++ b/services/java/com/android/server/SensorService.java @@ -105,17 +105,17 @@ class SensorService extends ISensorService.Stub { return _sensors_control_open(); } - public boolean enableSensor(IBinder binder, int sensor, int enable) + public boolean enableSensor(IBinder binder, String name, int sensor, int enable) throws RemoteException { - if (localLOGV) Log.d(TAG, "enableSensor " + sensor + " " + enable); + if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); // Inform battery statistics service of status change int uid = Binder.getCallingUid(); long identity = Binder.clearCallingIdentity(); if (enable == SENSOR_DISABLE) { - mBatteryStats.noteStopSensor(uid, sensor); + mBatteryStats.noteStopSensor(uid, name, sensor); } else { - mBatteryStats.noteStartSensor(uid, sensor); + mBatteryStats.noteStartSensor(uid, name, sensor); } Binder.restoreCallingIdentity(identity); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 7f7a52e..d624573 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -16,35 +16,36 @@ package com.android.server; +import com.android.server.am.ActivityManagerService; +import com.android.server.status.StatusBarService; + +import dalvik.system.PathClassLoader; +import dalvik.system.VMRuntime; + import android.app.ActivityManagerNative; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentService; import android.content.Context; +import android.content.Intent; import android.content.pm.IPackageManager; import android.database.ContentObserver; import android.database.Cursor; import android.media.AudioService; +import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.IBinder; -import android.provider.Settings; import android.provider.Contacts.People; -import android.server.BluetoothDeviceService; +import android.provider.Settings; import android.server.BluetoothA2dpService; -import android.server.checkin.FallbackCheckinService; +import android.server.BluetoothDeviceService; import android.server.search.SearchManagerService; import android.util.EventLog; import android.util.Log; -import dalvik.system.TouchDex; -import dalvik.system.VMRuntime; - -import com.android.server.am.ActivityManagerService; -import com.android.server.status.StatusBarService; - import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -180,7 +181,7 @@ class ServerThread extends Thread { StatusBarService statusBar = null; InputMethodManagerService imm = null; - + if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { Log.i(TAG, "Starting Status Bar Service."); @@ -205,7 +206,7 @@ class ServerThread extends Thread { } catch (Throwable e) { Log.e(TAG, "Failure starting Input Manager Service", e); } - + try { Log.i(TAG, "Starting Hardware Service."); ServiceManager.addService("hardware", new HardwareService(context)); @@ -272,9 +273,14 @@ class ServerThread extends Thread { } try { - Log.i(TAG, "Starting Checkin Service"); - addService(context, "checkin", "com.google.android.server.checkin.CheckinService", - FallbackCheckinService.class); + Log.i(TAG, "Starting Checkin Service."); + Intent intent = new Intent().setComponent(new ComponentName( + "com.google.android.server.checkin", + "com.google.android.server.checkin.CheckinService")); + if (context.startService(intent) == null) { + Log.w(TAG, "Using fallback Checkin Service."); + ServiceManager.addService("checkin", new FallbackCheckinService(context)); + } } catch (Throwable e) { Log.e(TAG, "Failure starting Checkin Service", e); } @@ -318,6 +324,7 @@ class ServerThread extends Thread { false, new AdbSettingsObserver()); // It is now time to start up the app processes... + boolean safeMode = wm.detectSafeMode(); if (statusBar != null) { statusBar.systemReady(); } @@ -342,51 +349,6 @@ class ServerThread extends Thread { Looper.loop(); Log.d(TAG, "System ServerThread is exiting!"); } - - private void addService(Context context, String name, String serviceClass, - Class fallback) { - - final IBinder service = findService(context, serviceClass, fallback); - if (service != null) { - ServiceManager.addService(name, service); - } else { - Log.e(TAG, "Failure starting service '" + name + "' with class " + serviceClass); - } - } - - private IBinder findService(Context context, String serviceClass, - Class fallback) { - - IBinder service = null; - try { - Class klass = Class.forName(serviceClass); - Constructor c = klass.getConstructor(Context.class); - service = (IBinder) c.newInstance(context); - } catch (ClassNotFoundException e) { - // Ignore - } catch (IllegalAccessException e) { - // Ignore - } catch (NoSuchMethodException e) { - // Ignore - } catch (InvocationTargetException e) { - // Ignore - } catch (InstantiationException e) { - // Ignore - } - - if (service == null && fallback != null) { - Log.w(TAG, "Could not find " + serviceClass + ", trying fallback"); - try { - service = fallback.newInstance(); - } catch (IllegalAccessException e) { - // Ignore - } catch (InstantiationException e) { - // Ignore - } - } - - return service; - } } class DemoThread extends Thread diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index dbaf086..b5cf1aa 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -363,7 +363,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump telephony.registry from from pid=" + Binder.getCallingPid() diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 2d61b1e..c009fac 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -22,6 +22,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; +import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -204,8 +205,6 @@ public class WifiService extends IWifiManager.Stub { mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK); synchronized (sDriverStopWakeLock) { if (sDriverStopWakeLock.isHeld()) { - if (DBG) Log.d(TAG, "Releasing driver-stop wakelock " + - sDriverStopWakeLock); sDriverStopWakeLock.release(); } } @@ -213,9 +212,18 @@ public class WifiService extends IWifiManager.Stub { } ); - Log.d(TAG, "WifiService starting up with Wi-Fi " + - (wifiEnabled ? "enabled" : "disabled")); - registerForBroadcasts(); + Log.i(TAG, "WifiService starting up with Wi-Fi " + + (wifiEnabled ? "enabled" : "disabled")); + + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateWifiState(); + } + }, + new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); + setWifiEnabledBlocking(wifiEnabled, false); } @@ -293,7 +301,7 @@ public class WifiService extends IWifiManager.Stub { decrementHiddentNetworkPresentCounter(); } } - mIsHiddenNetworkPresent.put(netId, new Boolean(present)); + mIsHiddenNetworkPresent.put(netId, present); } } else { Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!"); @@ -422,6 +430,7 @@ public class WifiService extends IWifiManager.Stub { /** * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} + * @param enable {@code true} to enable, {@code false} to disable. * @return {@code true} if the enable/disable operation was * started or is already in the queue. */ @@ -429,10 +438,6 @@ public class WifiService extends IWifiManager.Stub { enforceChangePermission(); if (mWifiHandler == null) return false; - /* - * Remove any enable/disable Wi-Fi messages we may have in the queue - * before adding a new one - */ synchronized (mWifiHandler) { sWakeLock.acquire(); sendEnableMessage(enable, true); @@ -458,40 +463,42 @@ public class WifiService extends IWifiManager.Stub { return false; } - updateWifiState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING); + setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING); if (enable) { if (!WifiNative.loadDriver()) { Log.e(TAG, "Failed to load Wi-Fi driver."); - updateWifiState(WIFI_STATE_UNKNOWN); + setWifiEnabledState(WIFI_STATE_UNKNOWN); return false; } if (!WifiNative.startSupplicant()) { WifiNative.unloadDriver(); Log.e(TAG, "Failed to start supplicant daemon."); - updateWifiState(WIFI_STATE_UNKNOWN); + setWifiEnabledState(WIFI_STATE_UNKNOWN); return false; } + registerForBroadcasts(); mWifiStateTracker.startEventLoop(); } else { - // Remove notification (it will no-op if it isn't visible) + mContext.unregisterReceiver(mReceiver); + // Remove notification (it will no-op if it isn't visible) mWifiStateTracker.setNotificationVisible(false, 0, false, 0); boolean failedToStopSupplicantOrUnloadDriver = false; if (!WifiNative.stopSupplicant()) { Log.e(TAG, "Failed to stop supplicant daemon."); - updateWifiState(WIFI_STATE_UNKNOWN); + setWifiEnabledState(WIFI_STATE_UNKNOWN); failedToStopSupplicantOrUnloadDriver = true; } - + // We must reset the interface before we unload the driver mWifiStateTracker.resetInterface(); - + if (!WifiNative.unloadDriver()) { Log.e(TAG, "Failed to unload Wi-Fi driver."); if (!failedToStopSupplicantOrUnloadDriver) { - updateWifiState(WIFI_STATE_UNKNOWN); + setWifiEnabledState(WIFI_STATE_UNKNOWN); failedToStopSupplicantOrUnloadDriver = true; } } @@ -505,7 +512,7 @@ public class WifiService extends IWifiManager.Stub { if (persist) { persistWifiEnabled(enable); } - updateWifiState(eventualWifiState); + setWifiEnabledState(eventualWifiState); /* * Initialize the hidden networks state and the number of allowed @@ -519,7 +526,7 @@ public class WifiService extends IWifiManager.Stub { return true; } - private void updateWifiState(int wifiState) { + private void setWifiEnabledState(int wifiState) { final int previousWifiState = mWifiState; // Update state @@ -527,6 +534,7 @@ public class WifiService extends IWifiManager.Stub { // Broadcast final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); mContext.sendStickyBroadcast(intent); @@ -551,7 +559,7 @@ public class WifiService extends IWifiManager.Stub { * {@link WifiManager#WIFI_STATE_ENABLING}, * {@link WifiManager#WIFI_STATE_UNKNOWN} */ - public int getWifiState() { + public int getWifiEnabledState() { enforceAccessPermission(); return mWifiState; } @@ -1082,9 +1090,7 @@ public class WifiService extends IWifiManager.Stub { */ removeNetworkIfHidden(netId); - synchronized (mWifiStateTracker) { - return WifiNative.removeNetworkCommand(netId); - } + return mWifiStateTracker.removeNetwork(netId); } /** @@ -1221,7 +1227,6 @@ public class WifiService extends IWifiManager.Stub { if (scanResult != null) { scanResult.level = -scanResultLevel; scanList.add(scanResult); - //if (DBG) Log.d(TAG, "ScanResult: " + scanResult); } } else if (DBG) { Log.w(TAG, @@ -1344,7 +1349,7 @@ public class WifiService extends IWifiManager.Stub { if (result && mNeedReconfig) { mNeedReconfig = false; result = WifiNative.reloadConfigCommand(); - + if (result) { Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION); mContext.sendBroadcast(intent); @@ -1446,9 +1451,7 @@ public class WifiService extends IWifiManager.Stub { int stayAwakeConditions = Settings.System.getInt(mContext.getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0); - if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { - /* do nothing, we'll check isAirplaneModeOn later. */ - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { + if (action.equals(Intent.ACTION_SCREEN_ON)) { mAlarmManager.cancel(mIdleIntent); mDeviceIdle = false; mScreenOff = false; @@ -1543,7 +1546,6 @@ public class WifiService extends IWifiManager.Stub { } private void sendStartMessage(boolean scanOnlyMode) { - if (DBG) Log.d(TAG, "sendStartMessage(" + scanOnlyMode + ")"); Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget(); } @@ -1561,6 +1563,9 @@ public class WifiService extends IWifiManager.Stub { } synchronized (mWifiHandler) { + if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) { + return; + } if (wifiShouldBeEnabled) { if (wifiShouldBeStarted) { sWakeLock.acquire(); @@ -1573,6 +1578,15 @@ public class WifiService extends IWifiManager.Stub { mContext.getContentResolver(), Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, DEFAULT_WAKELOCK_TIMEOUT); + /* + * The following wakelock is held in order to ensure + * that the connectivity manager has time to fail over + * to the mobile data network. The connectivity manager + * releases it once mobile data connectivity has been + * established. If connectivity cannot be established, + * the wakelock is released after wakeLockTimeout + * milliseconds have elapsed. + */ sDriverStopWakeLock.acquire(); mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI); mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout); @@ -1585,18 +1599,15 @@ public class WifiService extends IWifiManager.Stub { } private void registerForBroadcasts() { + IntentFilter intentFilter = new IntentFilter(); if (isAirplaneSensitive()) { - mContext.registerReceiver(mReceiver, - new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); + intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); } - mContext.registerReceiver(mReceiver, - new IntentFilter(Intent.ACTION_SCREEN_ON)); - mContext.registerReceiver(mReceiver, - new IntentFilter(Intent.ACTION_SCREEN_OFF)); - mContext.registerReceiver(mReceiver, - new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - mContext.registerReceiver(mReceiver, - new IntentFilter(ACTION_DEVICE_IDLE)); + intentFilter.addAction(Intent.ACTION_SCREEN_ON); + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); + intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + intentFilter.addAction(ACTION_DEVICE_IDLE); + mContext.registerReceiver(mReceiver, intentFilter); } private boolean isAirplaneSensitive() { @@ -1664,7 +1675,7 @@ public class WifiService extends IWifiManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingPermission(android.Manifest.permission.DUMP) + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump WifiService from from pid=" + Binder.getCallingPid() @@ -1672,11 +1683,14 @@ public class WifiService extends IWifiManager.Stub { return; } pw.println("Wi-Fi is " + stateName(mWifiState)); - pw.println("stay-awake conditions: " + + pw.println("Stay-awake conditions: " + Settings.System.getInt(mContext.getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0)); pw.println(); + pw.println("Internal state:"); + pw.println(mWifiStateTracker); + pw.println(); pw.println("Latest scan results:"); List scanResults = mWifiStateTracker.getScanResultsList(); if (scanResults != null && scanResults.size() != 0) { @@ -1786,13 +1800,6 @@ public class WifiService extends IWifiManager.Stub { return -1; } - private synchronized void clear() { - if (!mList.isEmpty()) { - mList.clear(); - updateWifiState(); - } - } - private void dump(PrintWriter pw) { for (WifiLock l : mList) { pw.print(" "); diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 7ed0aec..09f5d8f 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -122,7 +122,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo static final boolean DEBUG = false; static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_ANIM = false; + static final boolean DEBUG_LAYERS = false; static final boolean DEBUG_INPUT = false; + static final boolean DEBUG_INPUT_METHOD = false; static final boolean DEBUG_VISIBILITY = false; static final boolean DEBUG_ORIENTATION = false; static final boolean DEBUG_APP_TRANSITIONS = false; @@ -202,6 +204,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final boolean mHaveInputMethods; + final boolean mLimitedAlphaCompositing; + final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); final IActivityManager mActivityManager; @@ -306,6 +310,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final float[] mTmpFloats = new float[9]; + boolean mSafeMode; boolean mDisplayEnabled = false; boolean mSystemBooted = false; int mRotation = 0; @@ -316,7 +321,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo boolean mLayoutNeeded = true; boolean mAnimationPending = false; - boolean mSurfacesChanged = false; boolean mDisplayFrozen = false; boolean mWindowsFreezingScreen = false; long mFreezeGcPending = 0; @@ -347,6 +351,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // This just indicates the window the input method is on top of, not // necessarily the window its input is going to. WindowState mInputMethodTarget = null; + boolean mInputMethodTargetWaitingAnim; + int mInputMethodAnimLayerAdjustment; WindowState mInputMethodWindow = null; final ArrayList mInputMethodDialogs = new ArrayList(); @@ -461,6 +467,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo boolean haveInputMethods) { mContext = context; mHaveInputMethods = haveInputMethods; + mLimitedAlphaCompositing = context.getResources().getBoolean( + com.android.internal.R.bool.config_sf_limitedAlpha); mPowerManager = pm; mPowerManager.setPolicy(mPolicy); @@ -734,7 +742,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } - int findDesiredInputMethodWindowIndexLocked() { + int findDesiredInputMethodWindowIndexLocked(boolean willMove) { final ArrayList localmWindows = mWindows; final int N = localmWindows.size(); WindowState w = null; @@ -753,17 +761,67 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } } + + if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target=" + + w + " willMove=" + willMove); + + if (willMove && w != null) { + final WindowState curTarget = mInputMethodTarget; + if (curTarget != null && curTarget.mAppToken != null) { + int curIndex = -1; + if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition=" + + mNextAppTransition + " curTarget animating=" + + curTarget.isAnimating() + + " layer=" + curTarget.mAnimLayer + + " new layer=" + w.mAnimLayer); + if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { + // If we are currently setting up for an animation, + // hold everything until we can find out what will happen. + mInputMethodTargetWaitingAnim = true; + curIndex = localmWindows.indexOf(curTarget); + } else if (curTarget.isAnimating() && + curTarget.mAnimLayer > w.mAnimLayer) { + // If the window we are currently targeting is involved + // with an animation, and it is on top of the next target + // we will be over, then hold off on moving until + // that is done. + curIndex = localmWindows.indexOf(curTarget); + } + if (curIndex >= 0) { + return curIndex + 1; + } + } + } + //Log.i(TAG, "Placing input method @" + (i+1)); if (w != null) { - mInputMethodTarget = w; + if (willMove) { + RuntimeException e = new RuntimeException(); + e.fillInStackTrace(); + if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from " + + mInputMethodTarget + " to " + w, e); + mInputMethodTarget = w; + if (w.mAppToken != null) { + setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment); + } else { + setInputMethodAnimLayerAdjustment(0); + } + } return i+1; } - mInputMethodTarget = null; + if (willMove) { + RuntimeException e = new RuntimeException(); + e.fillInStackTrace(); + if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from " + + mInputMethodTarget + " to null", e); + mInputMethodTarget = null; + setInputMethodAnimLayerAdjustment(0); + } return -1; } void addInputMethodWindowToListLocked(WindowState win) { - int pos = findDesiredInputMethodWindowIndexLocked(); + int pos = findDesiredInputMethodWindowIndexLocked(true); if (pos >= 0) { win.mTargetAppToken = mInputMethodTarget.mAppToken; mWindows.add(pos, win); @@ -775,6 +833,33 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo moveInputMethodDialogsLocked(pos); } + void setInputMethodAnimLayerAdjustment(int adj) { + if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj); + mInputMethodAnimLayerAdjustment = adj; + WindowState imw = mInputMethodWindow; + if (imw != null) { + imw.mAnimLayer = imw.mLayer + adj; + if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw + + " anim layer: " + imw.mAnimLayer); + int wi = imw.mChildWindows.size(); + while (wi > 0) { + wi--; + WindowState cw = (WindowState)imw.mChildWindows.get(wi); + cw.mAnimLayer = cw.mLayer + adj; + if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw + + " anim layer: " + cw.mAnimLayer); + } + } + int di = mInputMethodDialogs.size(); + while (di > 0) { + di --; + imw = mInputMethodDialogs.get(di); + imw.mAnimLayer = imw.mLayer + adj; + if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw + + " anim layer: " + imw.mAnimLayer); + } + } + private int tmpRemoveWindowLocked(int interestingPos, WindowState win) { int wpos = mWindows.indexOf(win); if (wpos >= 0) { @@ -814,9 +899,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } if (pos >= 0) { final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken; - WindowState wp = (WindowState)mWindows.get(pos); - if (wp == mInputMethodWindow) { - pos++; + if (pos < mWindows.size()) { + WindowState wp = (WindowState)mWindows.get(pos); + if (wp == mInputMethodWindow) { + pos++; + } } for (int i=0; i= 0) { // In this case, the input method windows are to be placed // immediately above the window they are targeting. @@ -915,7 +1002,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } void adjustInputMethodDialogsLocked() { - moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked()); + moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true)); } public int addWindow(Session session, IWindow client, @@ -975,7 +1062,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo + attrs.token + ". Aborting."); return WindowManagerImpl.ADD_BAD_APP_TOKEN; } - token = new WindowToken(attrs.token, -1); + token = new WindowToken(attrs.token, -1, false); addToken = true; } else if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW) { @@ -1087,11 +1174,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo + ": window=" + win); } + // sendNewConfiguration() checks caller permissions so we must call it with + // privilege. updateOrientationFromAppTokens() clears and resets the caller + // identity anyway, so it's safe to just clear & restore around this whole + // block. + final long origId = Binder.clearCallingIdentity(); if (reportNewConfig) { - final long origId = Binder.clearCallingIdentity(); sendNewConfiguration(); - Binder.restoreCallingIdentity(origId); + } else { + // Update Orientation after adding a window, only if the window needs to be + // displayed right away + if (win.isVisibleOrAdding()) { + if (updateOrientationFromAppTokens(null) != null) { + sendNewConfiguration(); + } + } } + Binder.restoreCallingIdentity(origId); return res; } @@ -1125,7 +1224,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo + " inPendingTransaction=" + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false) + " mDisplayFrozen=" + mDisplayFrozen); - + // Visibility of the removed window. Will be used later to update orientation later on. + boolean wasVisible = false; // First, see if we need to run an animation. If we do, we have // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the @@ -1133,7 +1233,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (win.mSurface != null && !mDisplayFrozen) { // If we are not currently running the exit animation, we // need to see about starting one. - if (win.isVisibleLw()) { + if (wasVisible=win.isVisibleLw()) { + int transit = WindowManagerPolicy.TRANSIT_EXIT; if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; @@ -1161,6 +1262,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } removeWindowInnerLocked(session, win); + // Removing a visible window will effect the computed orientation + // So just update orientation if needed. + if (wasVisible) { + if (updateOrientationFromAppTokens(null) != null) { + sendNewConfiguration(); + } + } updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); Binder.restoreCallingIdentity(origId); } @@ -1191,10 +1299,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo TAG, "**** Removing window " + win + ": count=" + token.windows.size()); if (token.windows.size() == 0) { - if (atoken != token) { + if (!token.explicit) { mTokenMap.remove(token.token); mTokenList.remove(token); - } else { + } else if (atoken != null) { atoken.firstWindowDrawn = false; } } @@ -1287,7 +1395,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo Surface outSurface) { boolean displayed = false; boolean inTouchMode; - + Configuration newConfig = null; long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { @@ -1435,6 +1543,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (assignLayers) { assignLayersLocked(); } + newConfig = updateOrientationFromAppTokensLocked(null); performLayoutAndPlaceSurfacesLocked(); if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); @@ -1456,6 +1565,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo inTouchMode = mInTouchMode; } + if (newConfig != null) { + sendNewConfiguration(); + } + Binder.restoreCallingIdentity(origId); return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0) @@ -1708,7 +1821,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo Log.w(TAG, "Attempted to add existing input method token: " + token); return; } - wtoken = new WindowToken(token, type); + wtoken = new WindowToken(token, type, true); mTokenMap.put(token, wtoken); mTokenList.add(wtoken); } @@ -1812,12 +1925,32 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } - public Configuration updateOrientationFromAppTokens( - IBinder freezeThisOneIfNeeded) { - boolean changed = false; - synchronized(mWindowMap) { + public int getOrientationFromWindowsLocked() { + int pos = mWindows.size() - 1; + while (pos >= 0) { + WindowState wtoken = (WindowState) mWindows.get(pos); + pos--; + if (wtoken.mAppToken != null) { + // We hit an application window. so the orientation will be determined by the + // app window. No point in continuing further. + return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + } + if (!wtoken.isVisibleLw()) { + continue; + } + int req = wtoken.mAttrs.screenOrientation; + if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) || + (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){ + continue; + } else { + return req; + } + } + return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + } + + public int getOrientationFromAppTokensLocked() { int pos = mAppTokens.size() - 1; - int req = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; int curGroup = 0; int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean haveGroup = false; @@ -1838,7 +1971,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // the orientation behind it, then we'll stick with the // user's orientation. if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { - break; + return lastOrientation; } } int or = wtoken.requestedOrientation; @@ -1849,10 +1982,45 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || or == ActivityInfo.SCREEN_ORIENTATION_USER) { - req = or; - break; + return or; } } + return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + } + + public Configuration updateOrientationFromAppTokens( + IBinder freezeThisOneIfNeeded) { + Configuration config; + long ident = Binder.clearCallingIdentity(); + synchronized(mWindowMap) { + config = updateOrientationFromAppTokensLocked(freezeThisOneIfNeeded); + } + if (config != null) { + mLayoutNeeded = true; + performLayoutAndPlaceSurfacesLocked(); + } + Binder.restoreCallingIdentity(ident); + return config; + } + + /* + * The orientation is computed from non-application windows first. If none of + * the non-application windows specify orientation, the orientation is computed from + * application tokens. + * @see android.view.IWindowManager#updateOrientationFromAppTokens( + * android.os.IBinder) + */ + public Configuration updateOrientationFromAppTokensLocked( + IBinder freezeThisOneIfNeeded) { + boolean changed = false; + Configuration config = null; + long ident = Binder.clearCallingIdentity(); + try { + int req = getOrientationFromWindowsLocked(); + if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { + req = getOrientationFromAppTokensLocked(); + } + if (req != mForcedAppOrientation) { changed = true; mForcedAppOrientation = req; @@ -1873,14 +2041,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo ActivityInfo.CONFIG_ORIENTATION); } } - Configuration config = computeNewConfigurationLocked(); - if (config != null) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - return config; + return computeNewConfiguration(); } } + } finally { + Binder.restoreCallingIdentity(ident); } return null; @@ -2871,6 +3036,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return KeyInputQueue.getKeycodeState(devid, sw); } + public boolean hasKeys(int[] keycodes, boolean[] keyExists) { + return KeyInputQueue.hasKeys(keycodes, keyExists); + } + public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (mSystemBooted) { @@ -2987,18 +3156,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } else { mRequestedRotation = rotation; } - if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from "+rotation); - rotation = mPolicy.rotationForOrientation(mForcedAppOrientation); - if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to "+rotation); + if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation); + rotation = mPolicy.rotationForOrientation(mForcedAppOrientation, + mRotation, mDisplayEnabled); + if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation); changed = mDisplayEnabled && mRotation != rotation; if (changed) { - mRotation = rotation; if (DEBUG_ORIENTATION) Log.v(TAG, "Rotation changed to " + rotation + " from " + mRotation + " (forceApp=" + mForcedAppOrientation + ", req=" + mRequestedRotation + ")"); + mRotation = rotation; mWindowsFreezingScreen = true; mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), @@ -3298,21 +3468,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return null; } + /* + * Instruct the Activity Manager to fetch the current configuration and broadcast + * that to config-changed listeners if appropriate. + */ void sendNewConfiguration() { - Configuration config; - synchronized (mWindowMap) { - config = computeNewConfigurationLocked(); - } - - if (config != null) { - try { - mActivityManager.updateConfiguration(config); - } catch (RemoteException e) { - } + try { + mActivityManager.updateConfiguration(null); + } catch (RemoteException e) { } } - Configuration computeNewConfigurationLocked() { + public Configuration computeNewConfiguration() { synchronized (mWindowMap) { if (mDisplay == null) { return null; @@ -4610,6 +4777,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } }; + public boolean detectSafeMode() { + mSafeMode = mPolicy.detectSafeMode(); + return mSafeMode; + } + public void systemReady() { mPolicy.systemReady(); } @@ -5639,6 +5811,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mAnimating = false; mAnimation = null; mAnimLayer = mLayer; + if (mIsImWindow) { + mAnimLayer += mInputMethodAnimLayerAdjustment; + } + if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this + + " anim layer: " + mAnimLayer); mHasTransformation = false; mPolicyVisibility = mPolicyVisibilityAfterAnim; mTransformation.clear(); @@ -5755,7 +5932,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // transforming since it is more important to have that // animation be smooth. mShownAlpha = mAlpha; - if (false && (!PixelFormat.formatHasAlpha(mAttrs.format) + if (!mLimitedAlphaCompositing + || (!PixelFormat.formatHasAlpha(mAttrs.format) || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) && x == frame.left && y == frame.top))) { //Log.i(TAG, "Applying alpha transform"); @@ -5944,21 +6122,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return mHasDrawn; } - public void showLw(boolean doAnimation) { + public boolean showLw(boolean doAnimation) { if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) { - mSurfacesChanged = true; mPolicyVisibility = true; mPolicyVisibilityAfterAnim = true; if (doAnimation) { applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); } requestAnimationLocked(0); + return true; } + return false; } - public void hideLw(boolean doAnimation) { - if (mPolicyVisibility || mPolicyVisibilityAfterAnim) { - mSurfacesChanged = true; + public boolean hideLw(boolean doAnimation) { + boolean current = doAnimation ? mPolicyVisibilityAfterAnim + : mPolicyVisibility; + if (current) { if (doAnimation) { applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); if (mAnimation == null) { @@ -5968,10 +6148,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (doAnimation) { mPolicyVisibilityAfterAnim = false; } else { + mPolicyVisibilityAfterAnim = false; mPolicyVisibility = false; } requestAnimationLocked(0); + return true; } + return false; } void dump(PrintWriter pw, String prefix) { @@ -6054,6 +6237,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // The type of window this token is for, as per WindowManager.LayoutParams. final int windowType; + // Set if this token was explicitly added by a client, so should + // not be removed when all windows are removed. + final boolean explicit; + // If this is an AppWindowToken, this is non-null. AppWindowToken appWindowToken; @@ -6069,9 +6256,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // Temporary for finding which tokens no longer have visible windows. boolean hasVisible; - WindowToken(IBinder _token, int type) { + WindowToken(IBinder _token, int type, boolean _explicit) { token = _token; windowType = type; + explicit = _explicit; } void dump(PrintWriter pw, String prefix) { @@ -6151,7 +6339,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo boolean firstWindowDrawn; AppWindowToken(IApplicationToken _token) { - super(_token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION); + super(_token.asBinder(), + WindowManager.LayoutParams.TYPE_APPLICATION, true); appWindowToken = this; appToken = _token; } @@ -6198,17 +6387,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo for (int i=0; i 0) { - di --; - imw = mInputMethodDialogs.get(di); - imw.mAnimLayer = imw.mLayer + adj; - } + setInputMethodAnimLayerAdjustment(adj); } } } @@ -6295,7 +6477,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo clearAnimation(); animating = false; - + if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) { + moveInputMethodWindowsIfNeededLocked(true); + } + if (DEBUG_ANIM) Log.v( TAG, "Animation done in " + this + ": reportedVisible=" + reportedVisible); @@ -6519,6 +6704,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo synchronized(mWindowMap) { lastFocus = mLastFocus; newFocus = mCurrentFocus; + if (lastFocus == newFocus) { + // Focus is not changing, so nothing to do. + return; + } mLastFocus = newFocus; //Log.i(TAG, "Focus moving from " + lastFocus // + " to " + newFocus); @@ -6848,7 +7037,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo synchronized (mWindowMap) { // The focus for the client is the window immediately below // where we would place the input method window. - int idx = findDesiredInputMethodWindowIndexLocked(); + int idx = findDesiredInputMethodWindowIndexLocked(false); if (idx > 0) { WindowState imFocus = (WindowState)mWindows.get(idx-1); if (imFocus != null && imFocus.mSession.mClient != null && @@ -6888,13 +7077,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } private final void assignLayersLocked() { - if (mInLayout) { - if (Config.DEBUG) { - throw new RuntimeException("Recursive call!"); - } - return; - } - int N = mWindows.size(); int curBaseLayer = 0; int curLayer = 0; @@ -6916,6 +7098,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } else { w.mAnimLayer = w.mLayer; } + if (w.mIsImWindow) { + w.mAnimLayer += mInputMethodAnimLayerAdjustment; + } + if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": " + + w.mAnimLayer); //System.out.println( // "Assigned layer " + curLayer + " to " + w.mClient.asBinder()); } @@ -6927,6 +7114,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (Config.DEBUG) { throw new RuntimeException("Recursive call!"); } + Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout"); return; } @@ -6999,7 +7187,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo WindowState win = (WindowState) mWindows.get(i); boolean gone = win.mViewVisibility == View.GONE - || !win.mRelayoutCalled; + || !win.mRelayoutCalled + || win.mToken.hidden; // If this view is GONE, then skip it -- keep the current // frame, and let the caller know so they can ignore it @@ -7285,6 +7474,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // This has changed the visibility of windows, so perform // a new layout to get them all up-to-date. mLayoutNeeded = true; + moveInputMethodWindowsIfNeededLocked(true); performLayoutLockedInner(); updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES); @@ -7297,7 +7487,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo final boolean someoneLosingFocus = mLosingFocus.size() != 0; - mSurfacesChanged = false; boolean obscured = false; boolean blurring = false; boolean dimming = false; @@ -7673,7 +7862,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo mDimCurrentAlpha += mDimDeltaPerMs * (currentTime-mLastDimAnimTime); boolean more = true; - if (mDimDeltaPerMs > 0) { + if (mDisplayFrozen) { + // If the display is frozen, there is no reason to animate. + more = false; + } else if (mDimDeltaPerMs > 0) { if (mDimCurrentAlpha > mDimTargetAlpha) { more = false; } @@ -7811,7 +8003,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } /** - * Have the surface flinger show a surface, robustly dealing wit + * Have the surface flinger show a surface, robustly dealing with * error conditions. In particular, if there is not enough memory * to show the surface, then we will try to get rid of other surfaces * in order to succeed. @@ -7925,9 +8117,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (mCurrentFocus != newFocus) { // This check makes sure that we don't already have the focus // change message pending. - if (mLastFocus == mCurrentFocus) { - mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); - } + mH.removeMessages(H.REPORT_FOCUS_CHANGE); + mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); if (localLOGV) Log.v( TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus); final WindowState oldFocus = mCurrentFocus; @@ -8218,13 +8409,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.println(" mSystemBooted=" + mSystemBooted + " mDisplayEnabled=" + mDisplayEnabled); pw.println(" mLayoutNeeded=" + mLayoutNeeded - + " mSurfacesChanged=" + mSurfacesChanged + " mBlurShown=" + mBlurShown); pw.println(" mDimShown=" + mDimShown + " current=" + mDimCurrentAlpha + " target=" + mDimTargetAlpha + " delta=" + mDimDeltaPerMs + " lastAnimTime=" + mLastDimAnimTime); + pw.println(" mInputMethodAnimLayerAdjustment=" + + mInputMethodAnimLayerAdjustment); pw.println(" mDisplayFrozen=" + mDisplayFrozen + " mWindowsFreezingScreen=" + mWindowsFreezingScreen + " mAppsFreezingScreen=" + mAppsFreezingScreen); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 361c7f7..f5efe4b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -48,6 +48,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; @@ -96,6 +97,7 @@ import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.PrintWriter; +import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; @@ -631,6 +633,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * any user id that can impact battery performance. */ final BatteryStatsService mBatteryStatsService; + + /** + * information about component usage + */ + final UsageStatsService mUsageStatsService; /** * Current configuration information. HistoryRecord objects are given @@ -1053,6 +1060,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen m.mLaunchingActivity.setReferenceCounted(false); m.mBatteryStatsService.publish(context); + m.mUsageStatsService.publish(context); synchronized (thr) { thr.mReady = true; @@ -1186,8 +1194,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen procs = service.mLRUProcesses; } } - pw.println("Applications Memory Usage (kB):"); - dumpApplicationMemoryUsage(fd, pw, procs, " "); + dumpApplicationMemoryUsage(fd, pw, procs, " ", args); } } @@ -1224,6 +1231,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeLocked(); + + mUsageStatsService = new UsageStatsService( new File( + systemDir, "usagestats.bin").toString()); mConfiguration.makeDefault(); mProcessStats.init(); @@ -1522,6 +1532,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen app.thread.scheduleLaunchActivity(new Intent(r.intent), r, r.info, r.icicle, results, newIntents, !andResume, isNextTransitionForward()); + // Update usage stats for launched activity + updateUsageStats(r, true); } catch (RemoteException e) { if (r.launchFailed) { // This is the second time we failed -- finish activity @@ -1804,6 +1816,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen prev.shortComponentName); prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving, prev.configChangeFlags); + updateUsageStats(prev, false); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Log.w(TAG, "Exception thrown during pause", e); @@ -1848,6 +1861,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private final void completePauseLocked() { HistoryRecord prev = mPausingActivity; if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev); + if (prev != null) { if (prev.finishing) { if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev); @@ -2085,6 +2099,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ensureActivitiesVisibleLocked(r, starting, null, configChanges); } } + + private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) { + if (resumed) { + mUsageStatsService.noteResumeComponent(resumedComponent.realActivity); + } else { + mUsageStatsService.notePauseComponent(resumedComponent.realActivity); + } + } /** * Ensure that the top activity in the stack is resumed. @@ -2290,6 +2312,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY, System.identityHashCode(next), next.task.taskId, next.shortComponentName); + updateUsageStats(next, true); next.app.thread.scheduleResumeActivity(next, isNextTransitionForward()); @@ -2453,9 +2476,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. if (prev.task != r.task) prev = null; - // (2) The current activity is not the first in the task. - else if (!prev.frontOfTask) prev = null; - // (3) The current activity is already displayed. + // (2) The current activity is already displayed. else if (prev.nowVisible) prev = null; } mWindowManager.setAppStartingWindow( @@ -2537,6 +2558,40 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } /** + * Find the activity in the history stack within the given task. Returns + * the index within the history at which it's found, or < 0 if not found. + */ + private final int findActivityInHistoryLocked(HistoryRecord r, int task) { + int i = mHistory.size(); + while (i > 0) { + i--; + HistoryRecord candidate = (HistoryRecord)mHistory.get(i); + if (candidate.task.taskId != task) { + break; + } + if (candidate.realActivity.equals(r.realActivity)) { + return i; + } + } + + return -1; + } + + /** + * Reorder the history stack so that the activity at the given index is + * brought to the front. + */ + private final HistoryRecord moveActivityToFrontLocked(int where) { + HistoryRecord newTop = (HistoryRecord)mHistory.remove(where); + int top = mHistory.size(); + HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1); + mHistory.add(top, newTop); + oldTop.frontOfTask = false; + newTop.frontOfTask = true; + return newTop; + } + + /** * Deliver a new Intent to an existing activity, so that its onNewIntent() * method will be called at the proper time. */ @@ -2969,6 +3024,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen resumeTopActivityLocked(null); return START_DELIVERED_TO_TOP; } + } else if (!addingToTask && + (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) { + // In this case, we are launching an activity in our own task + // that may already be running somewhere in the history, and + // we want to shuffle it to the front of the stack if so. + int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId); + if (where >= 0) { + HistoryRecord top = moveActivityToFrontLocked(where); + logStartActivity(LOG_AM_NEW_INTENT, r, top.task); + deliverNewIntentLocked(top, r.intent); + resumeTopActivityLocked(null); + return START_DELIVERED_TO_TOP; + } } // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting @@ -4142,8 +4210,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = ActivityThread.getPackageManager(); + int pkgUid = -1; synchronized(this) { - int pkgUid = -1; try { pkgUid = pm.getPackageUid(packageName); } catch (RemoteException e) { @@ -4156,7 +4224,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen android.Manifest.permission.CLEAR_APP_USER_DATA, pid, uid, -1) == PackageManager.PERMISSION_GRANTED) { - uninstallPackageLocked(packageName, pkgUid, false); + restartPackageLocked(packageName, pkgUid); } else { throw new SecurityException(pid+" does not have permission:"+ android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" + @@ -4167,6 +4235,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { //clear application user data pm.clearApplicationUserData(packageName, observer); + Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, + Uri.fromParts("package", packageName, null)); + intent.putExtra(Intent.EXTRA_UID, pkgUid); + broadcastIntentLocked(null, null, intent, + null, null, 0, null, null, null, + false, false, MY_PID, Process.SYSTEM_UID); } catch (RemoteException e) { } } finally { @@ -4188,25 +4262,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen long callingId = Binder.clearCallingIdentity(); try { + IPackageManager pm = ActivityThread.getPackageManager(); + int pkgUid = -1; synchronized(this) { - uninstallPackageLocked(packageName, -1, false); - broadcastIntentLocked(null, null, - new Intent(Intent.ACTION_PACKAGE_RESTARTED, - Uri.fromParts("package", packageName, null)), - null, null, 0, null, null, null, - false, false, MY_PID, Process.SYSTEM_UID); + try { + pkgUid = pm.getPackageUid(packageName); + } catch (RemoteException e) { + } + if (pkgUid == -1) { + Log.w(TAG, "Invalid packageName:"+packageName); + return; + } + restartPackageLocked(packageName, pkgUid); } } finally { Binder.restoreCallingIdentity(callingId); } } + private void restartPackageLocked(final String packageName, int uid) { + uninstallPackageLocked(packageName, uid, false); + Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, + Uri.fromParts("package", packageName, null)); + intent.putExtra(Intent.EXTRA_UID, uid); + broadcastIntentLocked(null, null, intent, + null, null, 0, null, null, null, + false, false, MY_PID, Process.SYSTEM_UID); + } + private final void uninstallPackageLocked(String name, int uid, boolean callerWillRestart) { if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name); int i, N; + final String procNamePrefix = name + ":"; + if (uid < 0) { + try { + uid = ActivityThread.getPackageManager().getPackageUid(name); + } catch (RemoteException e) { + } + } + Iterator> badApps = mProcessCrashTimes.getMap().values().iterator(); while (badApps.hasNext()) { SparseArray ba = badApps.next(); @@ -4217,14 +4314,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ArrayList procs = new ArrayList(); - final String procNamePrefix = name + ":"; - if (uid < 0) { - try { - uid = ActivityThread.getPackageManager().getPackageUid(name); - } catch (RemoteException e) { - } - } - // Remove all processes this package may have touched: all with the // same UID (except for the system or root user), and all whose name // matches the package name. @@ -7226,6 +7315,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public boolean testIsSystemReady() { + // no need to synchronize(this) just to read & return the value + return mSystemReady; + } + public void systemReady() { // In the simulator, startRunning will never have been called, which // normally sets a few crucial variables. Do it here instead. @@ -7628,6 +7722,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityManager.RunningAppProcessInfo currApp = new ActivityManager.RunningAppProcessInfo(app.processName, app.pid, app.getPackageList()); + int adj = app.curAdj; + if (adj >= CONTENT_PROVIDER_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY; + } else if (adj >= HIDDEN_APP_MIN_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; + currApp.lru = adj - HIDDEN_APP_MIN_ADJ; + } else if (adj >= SECONDARY_SERVER_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; + } else if (adj >= VISIBLE_APP_ADJ) { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; + } else { + currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + } + //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance + // + " lru=" + currApp.lru); if (runList == null) { runList = new ArrayList(); } @@ -8176,28 +8285,53 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } private static final void dumpApplicationMemoryUsage(FileDescriptor fd, - PrintWriter pw, List list, String prefix) { + PrintWriter pw, List list, String prefix, String[] args) { + final boolean isCheckinRequest = scanArgs(args, "-c"); + long uptime = SystemClock.uptimeMillis(); + long realtime = SystemClock.elapsedRealtime(); + + if (isCheckinRequest) { + // short checkin version + pw.println(uptime + "," + realtime); + pw.flush(); + } else { + pw.println("Applications Memory Usage (kB):"); + pw.println("Uptime: " + uptime + " Realtime: " + realtime); + } for (int i = list.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = (ProcessRecord)list.get(i); if (r.thread != null) { - pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **"); - pw.flush(); - - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); + if (!isCheckinRequest) { + pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **"); + pw.flush(); + } try { - data.writeFileDescriptor(fd); - r.thread.asBinder().transact(IBinder.DUMP_TRANSACTION, data, reply, 0); - + r.thread.asBinder().dump(fd, args); } catch (RemoteException e) { - pw.println("Got RemoteException!"); - pw.flush(); + if (!isCheckinRequest) { + pw.println("Got RemoteException!"); + pw.flush(); + } } + } + } + } - data.recycle(); - reply.recycle(); + /** + * Searches array of arguments for the specified string + * @param args array of argument strings + * @param value value to search for + * @return true if the value is contained in the array + */ + private static boolean scanArgs(String[] args, String value) { + if (args != null) { + for (String arg : args) { + if (value.equals(arg)) { + return true; + } } } + return false; } private final int indexOfTokenLocked(IBinder token, boolean required) { @@ -9120,6 +9254,36 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return 0; } + public IBinder peekService(Intent service, String resolvedType) { + // Refuse possible leaked file descriptors + if (service != null && service.hasFileDescriptors() == true) { + throw new IllegalArgumentException("File descriptors passed in Intent"); + } + + IBinder ret = null; + + synchronized(this) { + ServiceLookupResult r = findServiceLocked(service, resolvedType); + + if (r != null) { + // r.record is null if findServiceLocked() failed the caller permission check + if (r.record == null) { + throw new SecurityException( + "Permission Denial: Accessing service " + r.record.name + + " from pid=" + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + r.permission); + } + IntentBindRecord ib = r.record.bindings.get(r.record.intent); + if (ib != null) { + ret = ib.binder; + } + } + } + + return ret; + } + public boolean stopServiceToken(ComponentName className, IBinder token, int startId) { synchronized(this) { @@ -9928,6 +10092,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } synchronized(this) { + if (!mSystemReady) { + // if the caller really truly claims to know what they're doing, go + // ahead and allow the broadcast without launching any receivers + int flags = intent.getFlags(); + if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { + intent = new Intent(intent); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){ + Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent + + " before boot completion"); + throw new IllegalStateException("Cannot broadcast before boot completed"); + } + } + final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); @@ -10639,6 +10817,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // ========================================================= // CONFIGURATION // ========================================================= + + public ConfigurationInfo getDeviceConfigurationInfo() { + ConfigurationInfo config = new ConfigurationInfo(); + synchronized (this) { + config.reqTouchScreen = mConfiguration.touchscreen; + config.reqKeyboardType = mConfiguration.keyboard; + config.reqNavigation = mConfiguration.navigation; + if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) { + config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) { + config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + } + return config; + } public Configuration getConfiguration() { Configuration ci; @@ -10653,6 +10847,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "updateConfiguration()"); synchronized(this) { + if (values == null && mWindowManager != null) { + // sentinel: fetch the current configuration from the window manager + values = mWindowManager.computeNewConfiguration(); + } + final long origId = Binder.clearCallingIdentity(); updateConfigurationLocked(values, null); Binder.restoreCallingIdentity(origId); diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index bf1bc8c..1cd6298 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -65,6 +65,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } public BatteryStatsImpl getStatistics() { + mContext.enforceCallingPermission( + android.Manifest.permission.BATTERY_STATS, null); return mStats; } @@ -82,17 +84,59 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } - public void noteStartSensor(int uid, int sensor) { + public void noteStartSensor(int uid, String name, int sensor) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStartSensor(sensor); + mStats.getUidStatsLocked(uid).noteStartSensor(name, sensor); } } - public void noteStopSensor(int uid, int sensor) { + public void noteStopSensor(int uid, String name, int sensor) { enforceCallingPermission(); synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStopSensor(sensor); + mStats.getUidStatsLocked(uid).noteStopSensor(name, sensor); + } + } + + public void noteStartGps(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteStartGps(uid); + } + } + + public void noteStopGps(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteStopGps(uid); + } + } + + public void noteRequestGpsOn(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteRequestGpsOn(uid); + } + } + + public void noteRequestGpsOff(int uid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteRequestGpsOff(uid); + } + } + + public void noteScreenOn() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScreenOn(); + } + } + + public void noteScreenOff() { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScreenOff(); } } @@ -106,10 +150,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } public long getAwakeTimeBattery() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BATTERY_STATS, null); return mStats.getAwakeTimeBattery(); } public long getAwakeTimePlugged() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BATTERY_STATS, null); return mStats.getAwakeTimePlugged(); } @@ -117,7 +165,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub { if (Binder.getCallingPid() == Process.myPid()) { return; } - mContext.enforcePermission(android.Manifest.permission.BATTERY_STATS, + mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, Binder.getCallingPid(), Binder.getCallingUid(), null); } diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java index b370b1c..b407208 100644 --- a/services/java/com/android/server/am/HistoryRecord.java +++ b/services/java/com/android/server/am/HistoryRecord.java @@ -23,6 +23,7 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Bundle; @@ -184,6 +185,11 @@ class HistoryRecord extends IApplicationToken.Stub { dataDir = aInfo.applicationInfo.dataDir; nonLocalizedLabel = aInfo.nonLocalizedLabel; labelRes = aInfo.labelRes; + if (nonLocalizedLabel == null && labelRes == 0) { + ApplicationInfo app = aInfo.applicationInfo; + nonLocalizedLabel = app.nonLocalizedLabel; + labelRes = app.labelRes; + } icon = aInfo.getIconResource(); theme = aInfo.getThemeResource(); if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0 diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java new file mode 100755 index 0000000..001987f --- /dev/null +++ b/services/java/com/android/server/am/UsageStatsService.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2006-2007 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.am; + +import com.android.internal.app.IUsageStats; +import android.content.ComponentName; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import com.android.internal.os.PkgUsageStats; +import android.os.Process; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.Log; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * This service collects the statistics associated with usage + * of various components, like when a particular package is launched or + * paused and aggregates events like number of time a component is launched + * total duration of a component launch. + */ +public final class UsageStatsService extends IUsageStats.Stub { + public static final String SERVICE_NAME = "usagestats"; + private static final boolean localLOGV = false; + private static final String TAG = "UsageStats"; + static IUsageStats sService; + private Context mContext; + private String mFileName; + final private Map mStats; + private String mResumedPkg; + + private class PkgUsageStatsExtended { + int mLaunchCount; + long mUsageTime; + long mChgTime; + PkgUsageStatsExtended() { + mLaunchCount = 0; + mUsageTime = 0; + mChgTime = SystemClock.elapsedRealtime(); + } + void updateResume() { + mLaunchCount ++; + mChgTime = SystemClock.elapsedRealtime(); + } + void updatePause() { + long currTime = SystemClock.elapsedRealtime(); + mUsageTime += (currTime - mChgTime); + mChgTime = currTime; + } + } + + UsageStatsService(String filename) { + mFileName = filename; + mStats = new HashMap(); + } + + public void publish(Context context) { + mContext = context; + ServiceManager.addService(SERVICE_NAME, asBinder()); + } + + public static IUsageStats getService() { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(SERVICE_NAME); + sService = asInterface(b); + return sService; + } + + public void noteResumeComponent(ComponentName componentName) { + enforceCallingPermission(); + String pkgName; + if ((componentName == null) || + ((pkgName = componentName.getPackageName()) == null)) { + return; + } + if ((mResumedPkg != null) && (mResumedPkg.equalsIgnoreCase(pkgName))) { + // Moving across activities in same package. just return + return; + } + if (localLOGV) Log.i(TAG, "started component:"+pkgName); + PkgUsageStatsExtended pus = mStats.get(pkgName); + if (pus == null) { + pus = new PkgUsageStatsExtended(); + mStats.put(pkgName, pus); + } + pus.updateResume(); + mResumedPkg = pkgName; + } + + public void notePauseComponent(ComponentName componentName) { + enforceCallingPermission(); + String pkgName; + if ((componentName == null) || + ((pkgName = componentName.getPackageName()) == null)) { + return; + } + if ((mResumedPkg == null) || (!pkgName.equalsIgnoreCase(mResumedPkg))) { + Log.w(TAG, "Something wrong here, Didn't expect "+pkgName+" to be paused"); + return; + } + if (localLOGV) Log.i(TAG, "paused component:"+pkgName); + PkgUsageStatsExtended pus = mStats.get(pkgName); + if (pus == null) { + // Weird some error here + Log.w(TAG, "No package stats for pkg:"+pkgName); + return; + } + pus.updatePause(); + } + + public void enforceCallingPermission() { + if (Binder.getCallingPid() == Process.myPid()) { + return; + } + mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), null); + } + + public PkgUsageStats getPkgUsageStats(ComponentName componentName) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.PACKAGE_USAGE_STATS, null); + String pkgName; + if ((componentName == null) || + ((pkgName = componentName.getPackageName()) == null)) { + return null; + } + PkgUsageStatsExtended pus = mStats.get(pkgName); + if (pus == null) { + return null; + } + return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime); + } + + public PkgUsageStats[] getAllPkgUsageStats() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.PACKAGE_USAGE_STATS, null); + synchronized (mStats) { + Set keys = mStats.keySet(); + int size = keys.size(); + if (size <= 0) { + return null; + } + PkgUsageStats retArr[] = new PkgUsageStats[size]; + int i = 0; + for (String key: keys) { + PkgUsageStatsExtended pus = mStats.get(key); + retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime); + i++; + } + return retArr; + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + StringBuilder sb = new StringBuilder(); + synchronized (mStats) { + Set keys = mStats.keySet(); + for (String key: keys) { + PkgUsageStatsExtended ps = mStats.get(key); + sb.append("pkg="); + sb.append(key); + sb.append(", launchCount="); + sb.append(ps.mLaunchCount); + sb.append(", usageTime="); + sb.append(ps.mUsageTime+" ms\n"); + } + } + pw.write(sb.toString()); + } +} diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index 00ff7be..3a5b13c 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -157,6 +157,7 @@ public class StatusBarPolicy { private IconData mBluetoothData; private int mBluetoothHeadsetState; private int mBluetoothA2dpState; + private boolean mBluetoothEnabled; // wifi private static final int[] sWifiSignalImages = new int[] { @@ -286,7 +287,16 @@ public class StatusBarPolicy { mBluetoothData = IconData.makeIcon("bluetooth", null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); mBluetoothIcon = service.addIcon(mBluetoothData, null); - updateBluetooth(null); + BluetoothDevice bluetooth = + (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); + if (bluetooth != null) { + mBluetoothEnabled = bluetooth.isEnabled(); + } else { + mBluetoothEnabled = false; + } + mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED; + mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED; + mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); // Gps status mGpsEnabledIconData = IconData.makeIcon("gps", @@ -767,30 +777,17 @@ public class StatusBarPolicy { } private final void updateBluetooth(Intent intent) { - boolean visible = false; - if (intent == null) { // Initialize - BluetoothDevice bluetooth = - (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE); - if (bluetooth != null) { - visible = bluetooth.isEnabled(); - } - mService.setIconVisibility(mBluetoothIcon, visible); - return; - } - int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; - String action = intent.getAction(); + String action = intent.getAction(); if (action.equals(BluetoothIntent.DISABLED_ACTION)) { - visible = false; + mBluetoothEnabled = false; } else if (action.equals(BluetoothIntent.ENABLED_ACTION)) { - visible = true; + mBluetoothEnabled = true; } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { - visible = true; mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, BluetoothHeadset.STATE_ERROR); } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { - visible = true; mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, BluetoothA2dp.STATE_DISCONNECTED); } else { @@ -805,7 +802,7 @@ public class StatusBarPolicy { mBluetoothData.iconId = iconId; mService.updateIcon(mBluetoothIcon, mBluetoothData, null); - mService.setIconVisibility(mBluetoothIcon, visible); + mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); } private final void updateWifi(Intent intent) { diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 3b6e354..a4844b1 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -322,9 +322,11 @@ public class StatusBarService extends IStatusBar.Stub } public void systemReady() { + final StatusBarView view = mStatusBarView; WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, - 25, + view.getContext().getResources().getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height), WindowManager.LayoutParams.TYPE_STATUS_BAR, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, @@ -333,7 +335,7 @@ public class StatusBarService extends IStatusBar.Stub lp.setTitle("StatusBar"); lp.windowAnimations = R.style.Animation_StatusBar; - WindowManagerImpl.getDefault().addView(mStatusBarView, lp); + WindowManagerImpl.getDefault().addView(view, lp); } // ================================================================================ -- cgit v1.1