diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /services | |
parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'services')
86 files changed, 0 insertions, 54654 deletions
diff --git a/services/Android.mk b/services/Android.mk deleted file mode 100644 index 5e912d6..0000000 --- a/services/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# the library -# ============================================================ -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(call all-subdir-java-files) - -LOCAL_MODULE:= services - -LOCAL_JAVA_LIBRARIES := android.policy - -include $(BUILD_JAVA_LIBRARY) - -include $(BUILD_DROIDDOC) - diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java deleted file mode 100644 index d8012b2..0000000 --- a/services/java/com/android/server/AlarmManagerService.java +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (C) 2006 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.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.IAlarmManager; -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.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.TimeZone; - -class AlarmManagerService extends IAlarmManager.Stub { - private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP; - private static final int RTC_MASK = 1 << AlarmManager.RTC; - private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP; - private static final int ELAPSED_REALTIME_MASK = 1 << AlarmManager.ELAPSED_REALTIME; - private static final int TIME_CHANGED_MASK = 1 << 16; - - private static final String TAG = "AlarmManager"; - private static final String ClockReceiver_TAG = "ClockReceiver"; - private static final boolean localLOGV = false; - private static final int ALARM_EVENT = 1; - private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; - - private static final Intent mBackgroundIntent - = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); - - private final Context mContext; - - private Object mLock = new Object(); - - private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>(); - private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>(); - - // slots corresponding with the inexact-repeat interval buckets, - // ordered from shortest to longest - private static final long sInexactSlotIntervals[] = { - AlarmManager.INTERVAL_FIFTEEN_MINUTES, - AlarmManager.INTERVAL_HALF_HOUR, - AlarmManager.INTERVAL_HOUR, - AlarmManager.INTERVAL_HALF_DAY, - AlarmManager.INTERVAL_DAY - }; - private long mInexactDeliveryTimes[] = { 0, 0, 0, 0, 0}; - - private int mDescriptor; - private int mBroadcastRefCount = 0; - private PowerManager.WakeLock mWakeLock; - private final AlarmThread mWaitThread = new AlarmThread(); - private final AlarmHandler mHandler = new AlarmHandler(); - private ClockReceiver mClockReceiver; - private UninstallReceiver mUninstallReceiver; - private final ResultReceiver mResultReceiver = new ResultReceiver(); - private final PendingIntent mTimeTickSender; - private final PendingIntent mDateChangeSender; - - private static final class FilterStats { - int count; - } - - private static final class BroadcastStats { - long aggregateTime; - int numWakeup; - long startTime; - int nesting; - HashMap<Intent.FilterComparison, FilterStats> filterStats - = new HashMap<Intent.FilterComparison, FilterStats>(); - } - - private final HashMap<String, BroadcastStats> mBroadcastStats - = new HashMap<String, BroadcastStats>(); - - public AlarmManagerService(Context context) { - mContext = context; - mDescriptor = init(); - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - - mTimeTickSender = PendingIntent.getBroadcast(context, 0, - new Intent(Intent.ACTION_TIME_TICK).addFlags( - Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0); - mDateChangeSender = PendingIntent.getBroadcast(context, 0, - new Intent(Intent.ACTION_DATE_CHANGED), 0); - - // now that we have initied the driver schedule the alarm - mClockReceiver= new ClockReceiver(); - mClockReceiver.scheduleTimeTickEvent(); - mClockReceiver.scheduleDateChangedEvent(); - mUninstallReceiver = new UninstallReceiver(); - - if (mDescriptor != -1) { - mWaitThread.start(); - } else { - Log.w(TAG, "Failed to open alarm driver. Falling back to a handler."); - } - } - - protected void finalize() throws Throwable { - try { - close(mDescriptor); - } finally { - super.finalize(); - } - } - - public void set(int type, long triggerAtTime, PendingIntent operation) { - setRepeating(type, triggerAtTime, 0, operation); - } - - public void setRepeating(int type, long triggerAtTime, long interval, - PendingIntent operation) { - if (operation == null) { - Log.w(TAG, "set/setRepeating ignored because there is no intent"); - return; - } - synchronized (mLock) { - Alarm alarm = new Alarm(); - alarm.type = type; - alarm.when = triggerAtTime; - alarm.repeatInterval = interval; - alarm.operation = operation; - - // Remove this alarm if already scheduled. - removeLocked(operation); - - if (localLOGV) Log.v(TAG, "set: " + alarm); - - int index = addAlarmLocked(alarm); - if (index == 0) { - setLocked(alarm); - } - } - } - - public void setInexactRepeating(int type, long triggerAtTime, long interval, - PendingIntent operation) { - if (operation == null) { - Log.w(TAG, "setInexactRepeating ignored because there is no intent"); - return; - } - - // find the slot in the delivery-times array that we will use - int intervalSlot; - for (intervalSlot = 0; intervalSlot < sInexactSlotIntervals.length; intervalSlot++) { - if (sInexactSlotIntervals[intervalSlot] == interval) { - break; - } - } - - // Non-bucket intervals just fall back to the less-efficient - // unbucketed recurring alarm implementation - if (intervalSlot >= sInexactSlotIntervals.length) { - setRepeating(type, triggerAtTime, interval, operation); - return; - } - - // Align bucketed alarm deliveries by trying to match - // the shortest-interval bucket already scheduled - long bucketTime = 0; - for (int slot = 0; slot < mInexactDeliveryTimes.length; slot++) { - if (mInexactDeliveryTimes[slot] > 0) { - bucketTime = mInexactDeliveryTimes[slot]; - break; - } - } - - if (bucketTime == 0) { - // If nothing is scheduled yet, just start at the requested time - bucketTime = triggerAtTime; - } else { - // Align the new alarm with the existing bucketed sequence. To achieve - // alignment, we slide the start time around by min{interval, slot interval} - long adjustment = (interval <= sInexactSlotIntervals[intervalSlot]) - ? interval : sInexactSlotIntervals[intervalSlot]; - - // The bucket may have started in the past; adjust - while (bucketTime < triggerAtTime) { - bucketTime += adjustment; - } - - // Or the bucket may be set to start more than an interval beyond - // our requested trigger time; pull it back to meet our needs - while (bucketTime > triggerAtTime + adjustment) { - bucketTime -= adjustment; - } - } - - // Remember where this bucket started (reducing the amount of later - // fixup required) and set the alarm with the new, bucketed start time. - if (localLOGV) Log.v(TAG, "setInexactRepeating: interval=" + interval - + " bucketTime=" + bucketTime); - mInexactDeliveryTimes[intervalSlot] = bucketTime; - setRepeating(type, bucketTime, interval, operation); - } - - public void setTimeZone(String tz) { - mContext.enforceCallingOrSelfPermission( - "android.permission.SET_TIME_ZONE", - "setTimeZone"); - - if (TextUtils.isEmpty(tz)) return; - TimeZone zone = TimeZone.getTimeZone(tz); - // Prevent reentrant calls from stepping on each other when writing - // the time zone property - boolean timeZoneWasChanged = false; - synchronized (this) { - String current = SystemProperties.get(TIMEZONE_PROPERTY); - if (current == null || !current.equals(zone.getID())) { - if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); - timeZoneWasChanged = true; - SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); - - // Update the kernel timezone information - // Kernel tracks time offsets as 'minutes west of GMT' - int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; - setKernelTimezone(mDescriptor, -(gmtOffset)); - } - } - - TimeZone.setDefault(null); - - if (timeZoneWasChanged) { - Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); - intent.putExtra("time-zone", zone.getID()); - mContext.sendBroadcast(intent); - } - } - - public void remove(PendingIntent operation) { - if (operation == null) { - return; - } - synchronized (mLock) { - removeLocked(operation); - } - } - - public void removeLocked(PendingIntent operation) { - removeLocked(mRtcWakeupAlarms, operation); - removeLocked(mRtcAlarms, operation); - removeLocked(mElapsedRealtimeWakeupAlarms, operation); - removeLocked(mElapsedRealtimeAlarms, operation); - } - - private void removeLocked(ArrayList<Alarm> alarmList, - PendingIntent operation) { - if (alarmList.size() <= 0) { - return; - } - - // iterator over the list removing any it where the intent match - Iterator<Alarm> it = alarmList.iterator(); - - while (it.hasNext()) { - Alarm alarm = it.next(); - if (alarm.operation.equals(operation)) { - it.remove(); - } - } - } - - public void removeLocked(String packageName) { - removeLocked(mRtcWakeupAlarms, packageName); - removeLocked(mRtcAlarms, packageName); - removeLocked(mElapsedRealtimeWakeupAlarms, packageName); - removeLocked(mElapsedRealtimeAlarms, packageName); - } - - private void removeLocked(ArrayList<Alarm> alarmList, - String packageName) { - if (alarmList.size() <= 0) { - return; - } - - // iterator over the list removing any it where the intent match - Iterator<Alarm> it = alarmList.iterator(); - - while (it.hasNext()) { - Alarm alarm = it.next(); - if (alarm.operation.getTargetPackage().equals(packageName)) { - it.remove(); - } - } - } - - private ArrayList<Alarm> getAlarmList(int type) { - switch (type) { - case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms; - case AlarmManager.RTC: return mRtcAlarms; - case AlarmManager.ELAPSED_REALTIME_WAKEUP: return mElapsedRealtimeWakeupAlarms; - case AlarmManager.ELAPSED_REALTIME: return mElapsedRealtimeAlarms; - } - - return null; - } - - private int addAlarmLocked(Alarm alarm) { - ArrayList<Alarm> alarmList = getAlarmList(alarm.type); - - int index = Collections.binarySearch(alarmList, alarm); - index = (index < 0) ? ((index + 1) * -1) : index; - if (localLOGV) Log.v( - TAG, "Adding alarm " + alarm + " at " + index); - alarmList.add(index, alarm); - - return index; - } - - public long timeToNextAlarm() { - long nextAlarm = 0xfffffffffffffffl; - synchronized (mLock) { - for (int i=AlarmManager.RTC_WAKEUP; - i<=AlarmManager.ELAPSED_REALTIME; i++) { - ArrayList<Alarm> alarmList = getAlarmList(i); - if (alarmList.size() > 0) { - Alarm a = alarmList.get(0); - if (a.when < nextAlarm) { - nextAlarm = a.when; - } - } - } - } - return nextAlarm; - } - - private void setLocked(Alarm alarm) - { - if (mDescriptor != -1) - { - set(mDescriptor, alarm.type, (alarm.when * 1000 * 1000)); - } - else - { - Message msg = Message.obtain(); - msg.what = ALARM_EVENT; - - mHandler.removeMessages(ALARM_EVENT); - mHandler.sendMessageAtTime(msg, alarm.when); - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump AlarmManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mLock) { - pw.println("Current Alarm Manager state:"); - if (mRtcWakeupAlarms.size() > 0) { - pw.println(" "); - pw.println(" Realtime wakeup alarms that are scheduled:"); - dumpAlarmList(pw, mRtcWakeupAlarms, " ", "RTC_WAKEUP"); - } - if (mRtcAlarms.size() > 0) { - pw.println(" "); - pw.println(" Realtime alarms that are scheduled:"); - dumpAlarmList(pw, mRtcAlarms, " ", "RTC"); - } - if (mElapsedRealtimeWakeupAlarms.size() > 0) { - pw.println(" "); - pw.println(" Elapsed realtime wakeup alarms that are scheduled:"); - dumpAlarmList(pw, mElapsedRealtimeWakeupAlarms, " ", "ELAPSED_REALTIME_WAKEUP"); - } - if (mElapsedRealtimeAlarms.size() > 0) { - pw.println(" "); - pw.println(" Elapsed realtime alarms that are scheduled:"); - dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED_REALTIME"); - } - - pw.println(" "); - pw.println(" Broadcast ref count: " + mBroadcastRefCount); - - pw.println(" "); - pw.println(" Alarm Stats:"); - for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) { - BroadcastStats bs = be.getValue(); - pw.println(" " + be.getKey()); - pw.println(" " + bs.aggregateTime + "ms running, " - + bs.numWakeup + " wakeups"); - for (Map.Entry<Intent.FilterComparison, FilterStats> fe - : bs.filterStats.entrySet()) { - pw.println(" " + fe.getValue().count + " alarms: " - + fe.getKey().getIntent()); - } - } - } - } - - private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, String prefix, String label) { - for (int i=list.size()-1; i>=0; i--) { - Alarm a = list.get(i); - pw.println(prefix + label + " #" + i + ":"); - a.dump(pw, prefix + " "); - } - } - - private native int init(); - private native void close(int fd); - private native void set(int fd, int type, long nanoseconds); - private native int waitForAlarm(int fd); - private native int setKernelTimezone(int fd, int minuteswest); - - private void triggerAlarmsLocked(ArrayList<Alarm> alarmList, - ArrayList<Alarm> triggerList, - long now) - { - Iterator<Alarm> it = alarmList.iterator(); - ArrayList<Alarm> repeats = new ArrayList<Alarm>(); - - while (it.hasNext()) - { - Alarm alarm = it.next(); - - if (localLOGV) Log.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm); - - if (alarm.when > now) - { - // don't fire alarms in the future - break; - } - - // add it to the trigger list so we can trigger it without the lock held. - // recurring alarms may have passed several alarm intervals while the - // phone was asleep or off, so pass a trigger count when sending them. - if (localLOGV) Log.v(TAG, "Alarm triggering: " + alarm); - alarm.count = 1; - if (alarm.repeatInterval > 0) { - // this adjustment will be zero if we're late by - // less than one full repeat interval - alarm.count += (now - alarm.when) / alarm.repeatInterval; - } - triggerList.add(alarm); - - // remove the alarm from the list - it.remove(); - - // if it repeats queue it up to be read-added to the list - if (alarm.repeatInterval > 0) - { - repeats.add(alarm); - } - } - - // reset any repeating alarms. - it = repeats.iterator(); - while (it.hasNext()) - { - Alarm alarm = it.next(); - alarm.when += alarm.count * alarm.repeatInterval; - addAlarmLocked(alarm); - } - - if (alarmList.size() > 0) - { - setLocked(alarmList.get(0)); - } - } - - private class Alarm implements Comparable<Alarm> { - public int type; - public int count; - public long when; - public long repeatInterval; - public PendingIntent operation; - - public Alarm() { - when = 0; - repeatInterval = 0; - operation = null; - } - - public int compareTo(Alarm obj) - { - if (obj.when > this.when) return -1; - if (obj.when < this.when) return 1; - if (obj.operation.equals(this.operation) - && obj.repeatInterval == this.repeatInterval) return 0; - return -1; - } - - public String toString() - { - return "Alarm{" - + Integer.toHexString(System.identityHashCode(this)) - + " type " + type + " " + operation.getTargetPackage() + "}"; - } - - public void dump(PrintWriter pw, String prefix) - { - pw.println(prefix + this); - pw.println(prefix + "type=" + type + " when=" + when - + " repeatInterval=" + repeatInterval - + " count=" + count); - pw.println(prefix + "operation=" + operation); - } - } - - private class AlarmThread extends Thread - { - public AlarmThread() - { - super("AlarmManager"); - } - - public void run() - { - while (true) - { - int result = waitForAlarm(mDescriptor); - - ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); - - if ((result & TIME_CHANGED_MASK) != 0) { - remove(mTimeTickSender); - mClockReceiver.scheduleTimeTickEvent(); - mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED)); - } - - synchronized (mLock) { - final long nowRTC = System.currentTimeMillis(); - final long nowELAPSED = SystemClock.elapsedRealtime(); - if (localLOGV) Log.v( - TAG, "Checking for alarms... rtc=" + nowRTC - + ", elapsed=" + nowELAPSED); - - if ((result & RTC_WAKEUP_MASK) != 0) - triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); - - if ((result & RTC_MASK) != 0) - triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); - - if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) - triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); - - if ((result & ELAPSED_REALTIME_MASK) != 0) - triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); - - // now trigger the alarms - Iterator<Alarm> it = triggerList.iterator(); - while (it.hasNext()) { - Alarm alarm = it.next(); - try { - if (localLOGV) Log.v(TAG, "sending alarm " + alarm); - alarm.operation.send(mContext, 0, - mBackgroundIntent.putExtra( - Intent.EXTRA_ALARM_COUNT, alarm.count), - mResultReceiver, mHandler); - - // we have an active broadcast so stay awake. - if (mBroadcastRefCount == 0) { - mWakeLock.acquire(); - } - mBroadcastRefCount++; - - BroadcastStats bs = getStatsLocked(alarm.operation); - if (bs.nesting == 0) { - bs.startTime = nowELAPSED; - } else { - bs.nesting++; - } - if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP - || alarm.type == AlarmManager.RTC_WAKEUP) { - bs.numWakeup++; - ActivityManagerNative.noteWakeupAlarm( - alarm.operation); - } - } catch (PendingIntent.CanceledException e) { - if (alarm.repeatInterval > 0) { - // This IntentSender is no longer valid, but this - // is a repeating alarm, so toss the hoser. - remove(alarm.operation); - } - } catch (RuntimeException e) { - Log.w(TAG, "Failure sending alarm.", e); - } - } - } - } - } - } - - private class AlarmHandler extends Handler { - public static final int ALARM_EVENT = 1; - public static final int MINUTE_CHANGE_EVENT = 2; - public static final int DATE_CHANGE_EVENT = 3; - - public AlarmHandler() { - } - - public void handleMessage(Message msg) { - if (msg.what == ALARM_EVENT) { - ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); - synchronized (mLock) { - final long nowRTC = System.currentTimeMillis(); - triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowRTC); - triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowRTC); - } - - // now trigger the alarms without the lock held - Iterator<Alarm> it = triggerList.iterator(); - while (it.hasNext()) - { - Alarm alarm = it.next(); - try { - alarm.operation.send(); - } catch (PendingIntent.CanceledException e) { - if (alarm.repeatInterval > 0) { - // This IntentSender is no longer valid, but this - // is a repeating alarm, so toss the hoser. - remove(alarm.operation); - } - } - } - } - } - } - - class ClockReceiver extends BroadcastReceiver { - public ClockReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_DATE_CHANGED); - mContext.registerReceiver(this, filter); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { - scheduleTimeTickEvent(); - } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { - // Since the kernel does not keep track of DST, we need to - // reset the TZ information at the beginning of each day - // based off of the current Zone gmt offset + userspace tracked - // daylight savings information. - TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); - int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000; - - setKernelTimezone(mDescriptor, -(gmtOffset)); - scheduleDateChangedEvent(); - } - } - - public void scheduleTimeTickEvent() { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.add(Calendar.MINUTE, 1); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - - set(AlarmManager.RTC, calendar.getTimeInMillis(), mTimeTickSender); - } - - public void scheduleDateChangedEvent() { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.add(Calendar.DAY_OF_MONTH, 1); - calendar.set(Calendar.HOUR, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - - set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender); - } - } - - class UninstallReceiver extends BroadcastReceiver { - public UninstallReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - filter.addDataScheme("package"); - mContext.registerReceiver(this, filter); - } - - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mLock) { - Uri data = intent.getData(); - if (data != null) { - String pkg = data.getSchemeSpecificPart(); - removeLocked(pkg); - mBroadcastStats.remove(pkg); - } - } - } - } - - private final BroadcastStats getStatsLocked(PendingIntent pi) { - String pkg = pi.getTargetPackage(); - BroadcastStats bs = mBroadcastStats.get(pkg); - if (bs == null) { - bs = new BroadcastStats(); - mBroadcastStats.put(pkg, bs); - } - return bs; - } - - class ResultReceiver implements PendingIntent.OnFinished { - public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, - String resultData, Bundle resultExtras) { - synchronized (mLock) { - BroadcastStats bs = getStatsLocked(pi); - if (bs != null) { - bs.nesting--; - if (bs.nesting <= 0) { - bs.nesting = 0; - bs.aggregateTime += SystemClock.elapsedRealtime() - - bs.startTime; - Intent.FilterComparison fc = new Intent.FilterComparison(intent); - FilterStats fs = bs.filterStats.get(fc); - if (fs == null) { - fs = new FilterStats(); - bs.filterStats.put(fc, fs); - } - fs.count++; - } - } - mBroadcastRefCount--; - if (mBroadcastRefCount == 0) { - mWakeLock.release(); - } - } - } - } -} diff --git a/services/java/com/android/server/AttributeCache.java b/services/java/com/android/server/AttributeCache.java deleted file mode 100644 index 459ae52..0000000 --- a/services/java/com/android/server/AttributeCache.java +++ /dev/null @@ -1,129 +0,0 @@ -/* -** -** Copyright 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; - -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.Intent; -import android.content.BroadcastReceiver; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.provider.Settings; -import android.util.Config; -import android.util.Log; - -import java.util.WeakHashMap; - -public final class AttributeCache extends BroadcastReceiver { - private static AttributeCache sInstance = null; - - private final Context mContext; - private final WeakHashMap<Key, Entry> mMap = - new WeakHashMap<Key, Entry>(); - private final WeakHashMap<String, Context> mContexts = - new WeakHashMap<String, Context>(); - - final static class Key { - public final String packageName; - public final int resId; - public final int[] styleable; - - public Key(String inPackageName, int inResId, int[] inStyleable) { - packageName = inPackageName; - resId = inResId; - styleable = inStyleable; - } - - @Override public boolean equals(Object obj) { - try { - if (obj != null) { - Key other = (Key)obj; - return packageName.equals(other.packageName) - && resId == other.resId - && styleable == other.styleable; - } - } catch (ClassCastException e) { - } - return false; - } - - @Override public int hashCode() { - return packageName.hashCode() + resId; - } - } - - public final static class Entry { - public final Context context; - public final TypedArray array; - - public Entry(Context c, TypedArray ta) { - context = c; - array = ta; - } - } - - public static void init(Context context) { - if (sInstance == null) { - sInstance = new AttributeCache(context); - } - } - - public static AttributeCache instance() { - return sInstance; - } - - public AttributeCache(Context context) { - mContext = context; - } - - public Entry get(String packageName, int resId, int[] styleable) { - synchronized (this) { - Key key = new Key(packageName, resId, styleable); - Entry ent = mMap.get(key); - if (ent != null) { - return ent; - } - Context context = mContexts.get(packageName); - if (context == null) { - try { - context = mContext.createPackageContext(packageName, 0); - if (context == null) { - return null; - } - mContexts.put(packageName, context); - } catch (PackageManager.NameNotFoundException e) { - return null; - } - } - try { - ent = new Entry(context, - context.obtainStyledAttributes(resId, styleable)); - mMap.put(key, ent); - } catch (Resources.NotFoundException e) { - return null; - } - return ent; - } - } - @Override public void onReceive(Context context, Intent intent) { - } -} - diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java deleted file mode 100644 index 9c9a580..0000000 --- a/services/java/com/android/server/BatteryService.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import com.android.internal.app.IBatteryStats; -import com.android.server.am.BatteryStatsService; - -import android.app.ActivityManagerNative; -import android.content.Context; -import android.content.Intent; -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; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.String; - -/** - * <p>BatteryService monitors the charging status, and charge level of the device - * battery. When these values change this service broadcasts the new values - * to all {@link android.content.BroadcastReceiver IntentReceivers} that are - * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED - * BATTERY_CHANGED} action.</p> - * <p>The new values are stored in the Intent data and can be retrieved by - * calling {@link android.content.Intent#getExtra Intent.getExtra} with the - * following keys:</p> - * <p>"scale" - int, the maximum value for the charge level</p> - * <p>"level" - int, charge level, from 0 through "scale" inclusive</p> - * <p>"status" - String, the current charging status.<br /> - * <p>"health" - String, the current battery health.<br /> - * <p>"present" - boolean, true if the battery is present<br /> - * <p>"icon-small" - int, suggested small icon to use for this state</p> - * <p>"plugged" - int, 0 if the device is not plugged in; 1 if plugged - * into an AC power adapter; 2 if plugged in via USB.</p> - * <p>"voltage" - int, current battery voltage in millivolts</p> - * <p>"temperature" - int, current battery temperature in tenths of - * a degree Centigrade</p> - * <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p> - */ -class BatteryService extends Binder { - private static final String TAG = BatteryService.class.getSimpleName(); - - 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; - - private boolean mAcOnline; - private boolean mUsbOnline; - private int mBatteryStatus; - private int mBatteryHealth; - private boolean mBatteryPresent; - private int mBatteryLevel; - private int mBatteryVoltage; - private int mBatteryTemperature; - private String mBatteryTechnology; - - private int mLastBatteryStatus; - private int mLastBatteryHealth; - private boolean mLastBatteryPresent; - private int mLastBatteryLevel; - private int mLastBatteryVoltage; - private int mLastBatteryTemperature; - - private int mPlugType; - private int mLastPlugType = -1; // Extra state so we can detect first run - - private long mDischargeStartTime; - private int mDischargeStartLevel; - - public BatteryService(Context context) { - mContext = context; - mBatteryStats = BatteryStatsService.getService(); - - mUEventObserver.startObserving("SUBSYSTEM=power_supply"); - - // set initial status - update(); - } - - final boolean isPowered() { - // assume we are powered if battery state is unknown so the "stay on while plugged in" option will work. - return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN); - } - - final boolean isPowered(int plugTypeSet) { - // assume we are powered if battery state is unknown so - // the "stay on while plugged in" option will work. - if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { - return true; - } - if (plugTypeSet == 0) { - return false; - } - int plugTypeBit = 0; - if (mAcOnline) { - plugTypeBit |= BatteryManager.BATTERY_PLUGGED_AC; - } - if (mUsbOnline) { - plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB; - } - return (plugTypeSet & plugTypeBit) != 0; - } - - final int getPlugType() { - return mPlugType; - } - - private UEventObserver mUEventObserver = new UEventObserver() { - @Override - public void onUEvent(UEventObserver.UEvent event) { - update(); - } - }; - - // returns battery level as a percentage - final int getBatteryLevel() { - return mBatteryLevel; - } - - private native void native_update(); - - private synchronized final void update() { - native_update(); - if (mAcOnline) { - mPlugType = BatteryManager.BATTERY_PLUGGED_AC; - } else if (mUsbOnline) { - mPlugType = BatteryManager.BATTERY_PLUGGED_USB; - } else { - mPlugType = BATTERY_PLUGGED_NONE; - } - if (mBatteryStatus != mLastBatteryStatus || - mBatteryHealth != mLastBatteryHealth || - mBatteryPresent != mLastBatteryPresent || - mBatteryLevel != mLastBatteryLevel || - mPlugType != mLastPlugType || - 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 || - mPlugType != mLastPlugType) { - EventLog.writeEvent(LOG_BATTERY_STATUS, - mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0, - mPlugType, mBatteryTechnology); - } - if (mBatteryLevel != mLastBatteryLevel || - mBatteryVoltage != mLastBatteryVoltage || - mBatteryTemperature != mLastBatteryTemperature) { - EventLog.writeEvent(LOG_BATTERY_LEVEL, - mBatteryLevel, mBatteryVoltage, mBatteryTemperature); - } - - mLastBatteryStatus = mBatteryStatus; - mLastBatteryHealth = mBatteryHealth; - mLastBatteryPresent = mBatteryPresent; - mLastBatteryLevel = mBatteryLevel; - mLastPlugType = mPlugType; - mLastBatteryVoltage = mBatteryVoltage; - mLastBatteryTemperature = mBatteryTemperature; - - sendIntent(); - } - } - - private final void sendIntent() { - // Pack up the values and broadcast them to everyone - Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - try { - mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE); - } catch (RemoteException e) { - // Should never happen. - } - - int icon = getIcon(mBatteryLevel); - - intent.putExtra("status", mBatteryStatus); - intent.putExtra("health", mBatteryHealth); - intent.putExtra("present", mBatteryPresent); - intent.putExtra("level", mBatteryLevel); - intent.putExtra("scale", BATTERY_SCALE); - intent.putExtra("icon-small", icon); - intent.putExtra("plugged", mPlugType); - intent.putExtra("voltage", mBatteryVoltage); - intent.putExtra("temperature", mBatteryTemperature); - intent.putExtra("technology", mBatteryTechnology); - - if (false) { - Log.d(TAG, "updateBattery level:" + mBatteryLevel + - " scale:" + BATTERY_SCALE + " status:" + mBatteryStatus + - " health:" + mBatteryHealth + " present:" + mBatteryPresent + - " voltage: " + mBatteryVoltage + - " temperature: " + mBatteryTemperature + - " technology: " + mBatteryTechnology + - " AC powered:" + mAcOnline + " USB powered:" + mUsbOnline + - " icon:" + icon ); - } - - ActivityManagerNative.broadcastStickyIntent(intent, null); - } - - private final int getIcon(int level) { - if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { - return com.android.internal.R.drawable.stat_sys_battery_charge; - } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING || - mBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING || - mBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) { - return com.android.internal.R.drawable.stat_sys_battery; - } else { - return com.android.internal.R.drawable.stat_sys_battery_unknown; - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - - pw.println("Permission Denial: can't dump Battery service from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (this) { - pw.println("Current Battery Service state:"); - pw.println(" AC powered: " + mAcOnline); - pw.println(" USB powered: " + mUsbOnline); - pw.println(" status: " + mBatteryStatus); - pw.println(" health: " + mBatteryHealth); - pw.println(" present: " + mBatteryPresent); - pw.println(" level: " + mBatteryLevel); - pw.println(" scale: " + BATTERY_SCALE); - pw.println(" voltage:" + mBatteryVoltage); - pw.println(" temperature: " + mBatteryTemperature); - pw.println(" technology: " + mBatteryTechnology); - } - } -} diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java deleted file mode 100644 index 590b1e4..0000000 --- a/services/java/com/android/server/BootReceiver.java +++ /dev/null @@ -1,40 +0,0 @@ -/* -** -** Copyright 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; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.BroadcastReceiver; -import android.provider.Settings; - -public class BootReceiver extends BroadcastReceiver -{ - @Override - public void onReceive(Context context, Intent intent) - { - Intent service = new Intent(context, com.android.server.LoadAverageService.class); - ContentResolver res = context.getContentResolver(); - boolean shown = Settings.System.getInt( - res, Settings.System.SHOW_PROCESSES, 0) != 0; - if (shown) { - context.startService(service); - } - } -} - diff --git a/services/java/com/android/server/BrickReceiver.java b/services/java/com/android/server/BrickReceiver.java deleted file mode 100644 index 6c4db0d..0000000 --- a/services/java/com/android/server/BrickReceiver.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.Intent; -import android.content.BroadcastReceiver; -import android.os.SystemService; -import android.util.Log; - -public class BrickReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Log.w("BrickReceiver", "!!! BRICKING DEVICE !!!"); - SystemService.start("brick"); - } -} diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java deleted file mode 100644 index aa8cded..0000000 --- a/services/java/com/android/server/ClipboardService.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.text.IClipboard; -import android.content.Context; - -/** - * Implementation of the clipboard for copy and paste. - */ -public class ClipboardService extends IClipboard.Stub { - private CharSequence mClipboard = ""; - - /** - * Instantiates the clipboard. - */ - public ClipboardService(Context context) { } - - // javadoc from interface - public void setClipboardText(CharSequence text) { - synchronized (this) { - if (text == null) { - text = ""; - } - - mClipboard = text; - } - } - - // javadoc from interface - public CharSequence getClipboardText() { - synchronized (this) { - return mClipboard; - } - } - - // javadoc from interface - public boolean hasClipboardText() { - synchronized (this) { - return mClipboard.length() > 0; - } - } -} diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java deleted file mode 100644 index 760988d..0000000 --- a/services/java/com/android/server/ConnectivityService.java +++ /dev/null @@ -1,741 +0,0 @@ -/* - * 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.app.Notification; -import android.app.NotificationManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.IConnectivityManager; -import android.net.MobileDataStateTracker; -import android.net.NetworkInfo; -import android.net.NetworkStateTracker; -import android.net.wifi.WifiStateTracker; -import android.os.Binder; -import android.os.Handler; -import android.os.Looper; -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; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * @hide - */ -public class ConnectivityService extends IConnectivityManager.Stub { - - private static final boolean DBG = false; - private static final String TAG = "ConnectivityService"; - - // Event log tags (must be in sync with event-log-tags) - private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; - - /** - * Sometimes we want to refer to the individual network state - * trackers separately, and sometimes we just want to treat them - * abstractly. - */ - private NetworkStateTracker mNetTrackers[]; - private WifiStateTracker mWifiStateTracker; - private MobileDataStateTracker mMobileDataStateTracker; - private WifiWatchdogService mWifiWatchdogService; - - private Context mContext; - private int mNetworkPreference; - private NetworkStateTracker mActiveNetwork; - - private int mNumDnsEntries; - private static int sDnsChangeCounter; - - private boolean mTestMode; - private static ConnectivityService sServiceInstance; - - private static class ConnectivityThread extends Thread { - private Context mContext; - - private ConnectivityThread(Context context) { - super("ConnectivityThread"); - mContext = context; - } - - @Override - public void run() { - Looper.prepare(); - synchronized (this) { - sServiceInstance = new ConnectivityService(mContext); - notifyAll(); - } - Looper.loop(); - } - - public static ConnectivityService getServiceInstance(Context context) { - ConnectivityThread thread = new ConnectivityThread(context); - thread.start(); - - synchronized (thread) { - while (sServiceInstance == null) { - try { - // Wait until sServiceInstance has been initialized. - thread.wait(); - } catch (InterruptedException ignore) { - Log.e(TAG, - "Unexpected InterruptedException while waiting for ConnectivityService thread"); - } - } - } - - return sServiceInstance; - } - } - - public static ConnectivityService getInstance(Context context) { - return ConnectivityThread.getServiceInstance(context); - } - - private ConnectivityService(Context context) { - if (DBG) Log.v(TAG, "ConnectivityService starting up"); - mContext = context; - mNetTrackers = new NetworkStateTracker[2]; - Handler handler = new MyHandler(); - - mNetworkPreference = getPersistedNetworkPreference(); - - /* - * Create the network state trackers for Wi-Fi and mobile - * data. Maybe this could be done with a factory class, - * but it's not clear that it's worth it, given that - * the number of different network types is not going - * to change very often. - */ - if (DBG) Log.v(TAG, "Starting Wifi Service."); - mWifiStateTracker = new WifiStateTracker(context, handler); - WifiService wifiService = new WifiService(context, mWifiStateTracker); - ServiceManager.addService(Context.WIFI_SERVICE, wifiService); - mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; - - mMobileDataStateTracker = new MobileDataStateTracker(context, handler); - mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker; - - mActiveNetwork = null; - mNumDnsEntries = 0; - - mTestMode = SystemProperties.get("cm.test.mode").equals("true") - && SystemProperties.get("ro.build.type").equals("eng"); - - for (NetworkStateTracker t : mNetTrackers) - t.startMonitoring(); - - // Constructing this starts it too - mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker); - } - - /** - * Sets the preferred network. - * @param preference the new preference - */ - public synchronized void setNetworkPreference(int preference) { - enforceChangePermission(); - if (ConnectivityManager.isNetworkTypeValid(preference)) { - if (mNetworkPreference != preference) { - persistNetworkPreference(preference); - mNetworkPreference = preference; - enforcePreference(); - } - } - } - - public int getNetworkPreference() { - enforceAccessPermission(); - return mNetworkPreference; - } - - private void persistNetworkPreference(int networkPreference) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference); - } - - private int getPersistedNetworkPreference() { - final ContentResolver cr = mContext.getContentResolver(); - - final int networkPrefSetting = Settings.Secure - .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); - if (networkPrefSetting != -1) { - return networkPrefSetting; - } - - return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; - } - - /** - * Make the state of network connectivity conform to the preference settings. - * In this method, we only tear down a non-preferred network. Establishing - * a connection to the preferred network is taken care of when we handle - * the disconnect event from the non-preferred network - * (see {@link #handleDisconnect(NetworkInfo)}). - */ - private void enforcePreference() { - if (mActiveNetwork == null) - return; - - for (NetworkStateTracker t : mNetTrackers) { - if (t == mActiveNetwork) { - int netType = t.getNetworkInfo().getType(); - int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ? - ConnectivityManager.TYPE_MOBILE : - ConnectivityManager.TYPE_WIFI); - - if (t.getNetworkInfo().getType() != mNetworkPreference) { - NetworkStateTracker otherTracker = mNetTrackers[otherNetType]; - if (otherTracker.isAvailable()) { - teardown(t); - } - } - } - } - } - - private boolean teardown(NetworkStateTracker netTracker) { - if (netTracker.teardown()) { - netTracker.setTeardownRequested(true); - return true; - } else { - return false; - } - } - - /** - * Return NetworkInfo for the active (i.e., connected) network interface. - * It is assumed that at most one network is active at a time. If more - * than one is active, it is indeterminate which will be returned. - * @return the info for the active network, or {@code null} if none is active - */ - public NetworkInfo getActiveNetworkInfo() { - enforceAccessPermission(); - for (NetworkStateTracker t : mNetTrackers) { - NetworkInfo info = t.getNetworkInfo(); - if (info.isConnected()) { - return info; - } - } - return null; - } - - public NetworkInfo getNetworkInfo(int networkType) { - enforceAccessPermission(); - if (ConnectivityManager.isNetworkTypeValid(networkType)) { - NetworkStateTracker t = mNetTrackers[networkType]; - if (t != null) - return t.getNetworkInfo(); - } - return null; - } - - public NetworkInfo[] getAllNetworkInfo() { - enforceAccessPermission(); - NetworkInfo[] result = new NetworkInfo[mNetTrackers.length]; - int i = 0; - for (NetworkStateTracker t : mNetTrackers) { - result[i++] = t.getNetworkInfo(); - } - return result; - } - - public boolean setRadios(boolean turnOn) { - boolean result = true; - enforceChangePermission(); - for (NetworkStateTracker t : mNetTrackers) { - result = t.setRadio(turnOn) && result; - } - return result; - } - - public boolean setRadio(int netType, boolean turnOn) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(netType)) { - return false; - } - NetworkStateTracker tracker = mNetTrackers[netType]; - return tracker != null && tracker.setRadio(turnOn); - } - - public int startUsingNetworkFeature(int networkType, String feature) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - return -1; - } - NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); - } - return -1; - } - - public int stopUsingNetworkFeature(int networkType, String feature) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - return -1; - } - NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid()); - } - return -1; - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. - * @param networkType the type of the network over which traffic to the specified - * host is to be routed - * @param hostAddress the IP address of the host to which the route is desired - * @return {@code true} on success, {@code false} on failure - */ - public boolean requestRouteToHost(int networkType, int hostAddress) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - return false; - } - NetworkStateTracker tracker = mNetTrackers[networkType]; - /* - * If there's only one connected network, and it's the one requested, - * then we don't have to do anything - the requested route already - * exists. If it's not the requested network, then it's not possible - * to establish the requested route. Finally, if there is more than - * one connected network, then we must insert an entry in the routing - * table. - */ - if (getNumConnectedNetworks() > 1) { - return tracker.requestRouteToHost(hostAddress); - } else { - return tracker.getNetworkInfo().getType() == networkType; - } - } - - /** - * @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; - - for (NetworkStateTracker nt : mNetTrackers) { - if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - ++numConnectedNets; - } - } - return numConnectedNets; - } - - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE, - "ConnectivityService"); - } - - private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE, - "ConnectivityService"); - - } - - /** - * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network, - * we ignore it. If it is for the active network, we send out a broadcast. - * But first, we check whether it might be possible to connect to a different - * network. - * @param info the {@code NetworkInfo} for the network - */ - private void handleDisconnect(NetworkInfo info) { - - if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); - - mNetTrackers[info.getType()].setTeardownRequested(false); - /* - * If the disconnected network is not the active one, then don't report - * this as a loss of connectivity. What probably happened is that we're - * getting the disconnect for a network that we explicitly disabled - * in accordance with network preference policies. - */ - if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType()) - return; - - NetworkStateTracker newNet; - if (info.getType() == ConnectivityManager.TYPE_MOBILE) { - newNet = mWifiStateTracker; - } else /* info().getType() == TYPE_WIFI */ { - newNet = mMobileDataStateTracker; - } - - /** - * See if the other network is available to fail over to. - * If is not available, we enable it anyway, so that it - * will be able to connect when it does become available, - * but we report a total loss of connectivity rather than - * report that we are attempting to fail over. - */ - NetworkInfo switchTo = null; - if (newNet.isAvailable()) { - mActiveNetwork = newNet; - switchTo = newNet.getNetworkInfo(); - switchTo.setFailover(true); - if (!switchTo.isConnectedOrConnecting()) { - newNet.reconnect(); - } - } else { - newNet.reconnect(); - } - - boolean otherNetworkConnected = false; - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - if (info.getReason() != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); - } - if (info.getExtraInfo() != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); - } - if (switchTo != null) { - otherNetworkConnected = switchTo.isConnected(); - if (DBG) { - if (otherNetworkConnected) { - Log.v(TAG, "Switching to already connected " + switchTo.getTypeName()); - } else { - Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName()); - } - } - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); - } else { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() + - (switchTo == null ? "" : " other=" + switchTo.getTypeName())); - - mContext.sendStickyBroadcast(intent); - /* - * If the failover network is already connected, then immediately send out - * a followup broadcast indicating successful failover - */ - if (switchTo != null && otherNetworkConnected) - sendConnectedBroadcast(switchTo); - } - - private void sendConnectedBroadcast(NetworkInfo info) { - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - if (info.getReason() != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); - } - if (info.getExtraInfo() != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); - } - mContext.sendStickyBroadcast(intent); - } - - /** - * Called when an attempt to fail over to another network has failed. - * @param info the {@link NetworkInfo} for the failed network - */ - private void handleConnectionFailure(NetworkInfo info) { - mNetTrackers[info.getType()].setTeardownRequested(false); - if (getActiveNetworkInfo() == null) { - String reason = info.getReason(); - String extraInfo = info.getExtraInfo(); - - if (DBG) { - String reasonText; - if (reason == null) { - reasonText = "."; - } else { - reasonText = " (" + reason + ")."; - } - Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText); - } - - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - if (reason != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); - } - if (extraInfo != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); - } - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - mContext.sendStickyBroadcast(intent); - } - } - - private void handleConnect(NetworkInfo info) { - if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName()); - - // snapshot isFailover, because sendConnectedBroadcast() resets it - boolean isFailover = info.isFailover(); - NetworkStateTracker thisNet = mNetTrackers[info.getType()]; - NetworkStateTracker deadnet = null; - NetworkStateTracker otherNet; - if (info.getType() == ConnectivityManager.TYPE_MOBILE) { - otherNet = mWifiStateTracker; - } else /* info().getType() == TYPE_WIFI */ { - otherNet = mMobileDataStateTracker; - } - /* - * Check policy to see whether we are connected to a non-preferred - * network that now needs to be torn down. - */ - NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); - NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); - if (wifiInfo.isConnected() && mobileInfo.isConnected()) { - if (mNetworkPreference == ConnectivityManager.TYPE_WIFI) - deadnet = mMobileDataStateTracker; - else - deadnet = mWifiStateTracker; - } - - boolean toredown = false; - thisNet.setTeardownRequested(false); - if (!mTestMode && deadnet != null) { - if (DBG) Log.v(TAG, "Policy requires " + - deadnet.getNetworkInfo().getTypeName() + " teardown"); - toredown = teardown(deadnet); - if (DBG && !toredown) { - Log.d(TAG, "Network declined teardown request"); - } - } - - /* - * Note that if toredown is true, deadnet cannot be null, so there is - * no danger of a null pointer exception here.. - */ - if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { - mActiveNetwork = thisNet; - if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName()); - thisNet.updateNetworkSettings(); - sendConnectedBroadcast(info); - if (isFailover) { - otherNet.releaseWakeLock(); - } - } else { - if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " + - info.getTypeName()); - } - } - - private void handleScanResultsAvailable(NetworkInfo info) { - int networkType = info.getType(); - if (networkType != ConnectivityManager.TYPE_WIFI) { - if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network." - + " Don't know how to handle."); - } - - mNetTrackers[networkType].interpretScanResultsAvailable(); - } - - private void handleNotificationChange(boolean visible, int id, Notification notification) { - NotificationManager notificationManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - - if (visible) { - notificationManager.notify(id, notification); - } else { - notificationManager.cancel(id); - } - } - - /** - * After any kind of change in the connectivity state of any network, - * make sure that anything that depends on the connectivity state of - * more than one network is set up correctly. We're mainly concerned - * with making sure that the list of DNS servers is set up according - * to which networks are connected, and ensuring that the right routing - * table entries exist. - */ - private void handleConnectivityChange() { - /* - * If both mobile and wifi are enabled, add the host routes that - * will allow MMS traffic to pass on the mobile network. But - * remove the default route for the mobile network, so that there - * will be only one default route, to ensure that all traffic - * except MMS will travel via Wi-Fi. - */ - int numConnectedNets = handleConfigurationChange(); - if (numConnectedNets > 1) { - mMobileDataStateTracker.addPrivateRoutes(); - mMobileDataStateTracker.removeDefaultRoute(); - } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) { - mMobileDataStateTracker.removePrivateRoutes(); - mMobileDataStateTracker.restoreDefaultRoute(); - } - } - - private int handleConfigurationChange() { - /* - * Set DNS properties. Always put Wi-Fi entries at the front of - * the list if it is active. - */ - int index = 1; - String lastDns = ""; - int numConnectedNets = 0; - int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI; - int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; - - for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) { - NetworkStateTracker nt = mNetTrackers[netType]; - if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - ++numConnectedNets; - String[] dnsList = nt.getNameServers(); - for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { - // skip duplicate entries - if (!dnsList[i].equals(lastDns)) { - SystemProperties.set("net.dns" + index++, dnsList[i]); - lastDns = dnsList[i]; - } - } - } - } - // Null out any DNS properties that are no longer used - for (int i = index; i <= mNumDnsEntries; i++) { - SystemProperties.set("net.dns" + i, ""); - } - mNumDnsEntries = index - 1; - // Notify the name resolver library of the change - SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++)); - return numConnectedNets; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ConnectivityService from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - if (mActiveNetwork == null) { - pw.println("No active network"); - } else { - pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName()); - } - pw.println(); - for (NetworkStateTracker nst : mNetTrackers) { - pw.println(nst.getNetworkInfo()); - pw.println(nst); - pw.println(); - } - } - - private class MyHandler extends Handler { - @Override - public void handleMessage(Message msg) { - NetworkInfo info; - switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: - info = (NetworkInfo) msg.obj; - if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " + - info.getState() + "/" + info.getDetailedState()); - - // Connectivity state changed: - // [31-13] Reserved for future use - // [12-9] Network subtype (for mobile network, as defined by TelephonyManager) - // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState) - // [2-0] Network type (as defined by ConnectivityManager) - int eventLogParam = (info.getType() & 0x7) | - ((info.getDetailedState().ordinal() & 0x3f) << 3) | - (info.getSubtype() << 9); - EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam); - - if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { - handleConnectionFailure(info); - } else if (info.getState() == NetworkInfo.State.DISCONNECTED) { - handleDisconnect(info); - } else if (info.getState() == NetworkInfo.State.SUSPENDED) { - // TODO: need to think this over. - // the logic here is, handle SUSPENDED the same as DISCONNECTED. The - // only difference being we are broadcasting an intent with NetworkInfo - // that's suspended. This allows the applications an opportunity to - // handle DISCONNECTED and SUSPENDED differently, or not. - handleDisconnect(info); - } else if (info.getState() == NetworkInfo.State.CONNECTED) { - handleConnect(info); - } - handleConnectivityChange(); - break; - - case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: - info = (NetworkInfo) msg.obj; - handleScanResultsAvailable(info); - break; - - case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED: - handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj); - - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: - handleConfigurationChange(); - break; - - case NetworkStateTracker.EVENT_ROAMING_CHANGED: - // fill me in - break; - - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: - // fill me in - break; - } - } - } -} diff --git a/services/java/com/android/server/DemoDataSet.java b/services/java/com/android/server/DemoDataSet.java deleted file mode 100644 index 0de7c1e..0000000 --- a/services/java/com/android/server/DemoDataSet.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 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; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.res.AssetManager; -import android.net.Uri; -import android.os.Environment; -import android.provider.Contacts; -import android.provider.Settings; -import android.provider.MediaStore.Images; -import android.util.Config; -import android.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; - -public class DemoDataSet -{ - private final static String LOG_TAG = "DemoDataSet"; - - private ContentResolver mContentResolver; - - public final void add(Context context) - { - mContentResolver = context.getContentResolver(); - - // Remove all the old data - mContentResolver.delete(Contacts.People.CONTENT_URI, null, null); - - // Add the new data - addDefaultData(); - - // Add images from /android/images - addDefaultImages(); - } - - private final void addDefaultImages() - { - File rootDirectory = Environment.getRootDirectory(); - String [] files - = new File(rootDirectory, "images").list(); - int count = files.length; - - if (count == 0) { - Log.i(LOG_TAG, "addDefaultImages: no images found!"); - return; - } - - for (int i = 0; i < count; i++) - { - String name = files[i]; - String path = rootDirectory + "/" + name; - - try { - Images.Media.insertImage(mContentResolver, path, name, null); - } catch (FileNotFoundException e) { - Log.e(LOG_TAG, "Failed to import image " + path, e); - } - } - } - - private final void addDefaultData() - { - Log.i(LOG_TAG, "Adding default data..."); - -// addImage("Violet", "images/violet.png"); -// addImage("Corky", "images/corky.png"); - - // PENDING: should this be done here?!?! - Intent intent = new Intent( - Intent.ACTION_CALL, Uri.fromParts("voicemail", "", null)); - addShortcut("1", intent); - } - - private final Uri addImage(String name, Uri file) - { - ContentValues imagev = new ContentValues(); - imagev.put("name", name); - - Uri url = null; - - AssetManager ass = AssetManager.getSystem(); - InputStream in = null; - OutputStream out = null; - - try - { - in = ass.open(file.toString()); - - url = mContentResolver.insert(Images.Media.INTERNAL_CONTENT_URI, imagev); - out = mContentResolver.openOutputStream(url); - - final int size = 8 * 1024; - byte[] buf = new byte[size]; - - int count = 0; - do - { - count = in.read(buf, 0, size); - if (count > 0) { - out.write(buf, 0, count); - } - } while (count > 0); - } - catch (Exception e) - { - Log.e(LOG_TAG, "Failed to insert image '" + file + "'", e); - url = null; - } - - return url; - } - - private final Uri addShortcut(String shortcut, Intent intent) - { - if (Config.LOGV) Log.v(LOG_TAG, "addShortcut: shortcut=" + shortcut + ", intent=" + intent); - return Settings.Bookmarks.add(mContentResolver, intent, null, null, - shortcut != null ? shortcut.charAt(0) : 0, 0); - } -} diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java deleted file mode 100644 index 85861bb..0000000 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (C) 2007-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 com.android.server.am.ActivityManagerService; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageManager; -import android.os.Binder; -import android.os.Handler; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.StatFs; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.provider.Settings.Gservices; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.provider.Settings; - -/** - * This class implements a service to monitor the amount of disk storage space - * on the device. If the free storage on device is less than a tunable threshold value - * (default is 10%. this value is a gservices parameter) a low memory notification is - * displayed to alert the user. If the user clicks on the low memory notification the - * Application Manager application gets launched to let the user free storage space. - * Event log events: - * A low memory event with the free storage on device in bytes is logged to the event log - * when the device goes low on storage space. - * The amount of free storage on the device is periodically logged to the event log. The log - * interval is a gservices parameter with a default value of 12 hours - * When the free storage differential goes below a threshold(again a gservices parameter with - * a default value of 2MB), the free memory is logged to the event log - */ -class DeviceStorageMonitorService extends Binder { - private static final String TAG = "DeviceStorageMonitorService"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final int DEVICE_MEMORY_WHAT = 1; - private static final int MONITOR_INTERVAL = 1; //in minutes - private static final int LOW_MEMORY_NOTIFICATION_ID = 1; - private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; - private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes - private static final int EVENT_LOG_STORAGE_BELOW_THRESHOLD = 2744; - private static final int EVENT_LOG_LOW_STORAGE_NOTIFICATION = 2745; - private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746; - private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB - private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000; - private long mFreeMem; - private long mLastReportedFreeMem; - private long mLastReportedFreeMemTime; - private boolean mLowMemFlag=false; - private Context mContext; - private ContentResolver mContentResolver; - int mBlkSize; - long mTotalMemory; - StatFs mFileStats; - private static final String DATA_PATH="/data"; - long mThreadStartTime = -1; - boolean mClearSucceeded = false; - boolean mClearingCache; - private Intent mStorageLowIntent; - private Intent mStorageOkIntent; - private CachePackageDataObserver mClearCacheObserver; - private static final int _TRUE = 1; - private static final int _FALSE = 0; - - /** - * This string is used for ServiceManager access to this class. - */ - static final String SERVICE = "devicestoragemonitor"; - - /** - * Handler that checks the amount of disk space on the device and sends a - * notification if the device runs low on disk space - */ - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - //dont handle an invalid message - if (msg.what != DEVICE_MEMORY_WHAT) { - Log.e(TAG, "Will not process invalid message"); - return; - } - checkMemory(msg.arg1 == _TRUE); - } - }; - - class CachePackageDataObserver extends IPackageDataObserver.Stub { - public void onRemoveCompleted(String packageName, boolean succeeded) { - mClearSucceeded = succeeded; - mClearingCache = false; - if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded - +", mClearingCache:"+mClearingCache+" Forcing memory check"); - postCheckMemoryMsg(false, 0); - } - } - - private final void restatDataDir() { - mFileStats.restat(DATA_PATH); - mFreeMem = mFileStats.getAvailableBlocks()*mBlkSize; - // Allow freemem to be overridden by debug.freemem for testing - String debugFreeMem = SystemProperties.get("debug.freemem"); - if (!"".equals(debugFreeMem)) { - mFreeMem = Long.parseLong(debugFreeMem); - } - // Read the log interval from Gservices - long freeMemLogInterval = Gservices.getLong(mContentResolver, - Gservices.SYS_FREE_STORAGE_LOG_INTERVAL, - DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000; - //log the amount of free memory in event log - long currTime = SystemClock.elapsedRealtime(); - if((mLastReportedFreeMemTime == 0) || - (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) { - mLastReportedFreeMemTime = currTime; - EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, mFreeMem); - } - // Read the reporting threshold from Gservices - long threshold = Gservices.getLong(mContentResolver, - Gservices.DISK_FREE_CHANGE_REPORTING_THRESHOLD, - DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD); - // If mFree changed significantly log the new value - long delta = mFreeMem - mLastReportedFreeMem; - if (delta > threshold || delta < -threshold) { - mLastReportedFreeMem = mFreeMem; - EventLog.writeEvent(EVENT_LOG_STORAGE_BELOW_THRESHOLD, mFreeMem); - } - } - - private final void clearCache() { - if (mClearCacheObserver == null) { - // Lazy instantiation - mClearCacheObserver = new CachePackageDataObserver(); - } - mClearingCache = true; - try { - if (localLOGV) Log.i(TAG, "Clearing cache"); - IPackageManager.Stub.asInterface(ServiceManager.getService("package")). - freeStorageAndNotify(getMemThreshold(), mClearCacheObserver); - } catch (RemoteException e) { - Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e); - mClearingCache = false; - mClearSucceeded = false; - } - } - - private final void checkMemory(boolean checkCache) { - //if the thread that was started to clear cache is still running do nothing till its - //finished clearing cache. Ideally this flag could be modified by clearCache - // and should be accessed via a lock but even if it does this test will fail now and - //hopefully the next time this flag will be set to the correct value. - if(mClearingCache) { - if(localLOGV) Log.i(TAG, "Thread already running just skip"); - //make sure the thread is not hung for too long - long diffTime = System.currentTimeMillis() - mThreadStartTime; - if(diffTime > (10*60*1000)) { - Log.w(TAG, "Thread that clears cache file seems to run for ever"); - } - } else { - restatDataDir(); - if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem); - - //post intent to NotificationManager to display icon if necessary - long memThreshold = getMemThreshold(); - if (mFreeMem < memThreshold) { - if (!mLowMemFlag) { - if (checkCache) { - // See if clearing cache helps - // Note that clearing cache is asynchronous and so we do a - // memory check again once the cache has been cleared. - mThreadStartTime = System.currentTimeMillis(); - mClearSucceeded = false; - clearCache(); - } else { - Log.i(TAG, "Running low on memory. Sending notification"); - sendNotification(); - mLowMemFlag = true; - } - } else { - if (localLOGV) Log.v(TAG, "Running low on memory " + - "notification already sent. do nothing"); - } - } else { - if (mLowMemFlag) { - Log.i(TAG, "Memory available. Cancelling notification"); - cancelNotification(); - mLowMemFlag = false; - } - } - } - if(localLOGV) Log.i(TAG, "Posting Message again"); - //keep posting messages to itself periodically - postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL); - } - - private void postCheckMemoryMsg(boolean clearCache, long delay) { - // Remove queued messages - mHandler.removeMessages(DEVICE_MEMORY_WHAT); - mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT, - clearCache ?_TRUE : _FALSE, 0), - delay); - } - - /* - * just query settings to retrieve the memory threshold. - * Preferred this over using a ContentObserver since Settings.Gservices caches the value - * any way - */ - private long getMemThreshold() { - int value = Settings.Gservices.getInt( - mContentResolver, - Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE, - DEFAULT_THRESHOLD_PERCENTAGE); - if(localLOGV) Log.v(TAG, "Threshold Percentage="+value); - //evaluate threshold value - return mTotalMemory*value; - } - - /** - * Constructor to run service. initializes the disk space threshold value - * and posts an empty message to kickstart the process. - */ - public DeviceStorageMonitorService(Context context) { - mLastReportedFreeMemTime = 0; - mContext = context; - mContentResolver = mContext.getContentResolver(); - //create StatFs object - mFileStats = new StatFs(DATA_PATH); - //initialize block size - mBlkSize = mFileStats.getBlockSize(); - //initialize total storage on device - mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100; - mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); - mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); - checkMemory(true); - } - - - /** - * This method sends a notification to NotificationManager to display - * an error dialog indicating low disk space and launch the Installer - * application - */ - private final void sendNotification() { - if(localLOGV) Log.i(TAG, "Sending low memory notification"); - //log the event to event log with the amount of free storage(in bytes) left on the device - EventLog.writeEvent(EVENT_LOG_LOW_STORAGE_NOTIFICATION, mFreeMem); - // Pack up the values and broadcast them to everyone - Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE); - lowMemIntent.putExtra("memory", mFreeMem); - lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( - Context.NOTIFICATION_SERVICE); - CharSequence title = mContext.getText( - com.android.internal.R.string.low_internal_storage_view_title); - CharSequence details = mContext.getText( - com.android.internal.R.string.low_internal_storage_view_text); - PendingIntent intent = PendingIntent.getActivity(mContext, 0, lowMemIntent, 0); - Notification notification = new Notification(); - notification.icon = com.android.internal.R.drawable.stat_notify_disk_full; - notification.tickerText = title; - notification.flags |= Notification.FLAG_NO_CLEAR; - notification.setLatestEventInfo(mContext, title, details, intent); - mNotificationMgr.notify(LOW_MEMORY_NOTIFICATION_ID, notification); - mContext.sendStickyBroadcast(mStorageLowIntent); - } - - /** - * Cancels low storage notification and sends OK intent. - */ - private final void cancelNotification() { - if(localLOGV) Log.i(TAG, "Canceling low memory notification"); - NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( - Context.NOTIFICATION_SERVICE); - //cancel notification since memory has been freed - mNotificationMgr.cancel(LOW_MEMORY_NOTIFICATION_ID); - - mContext.removeStickyBroadcast(mStorageLowIntent); - mContext.sendBroadcast(mStorageOkIntent); - } - - public void updateMemory() { - int callingUid = getCallingUid(); - if(callingUid != Process.SYSTEM_UID) { - return; - } - // force an early check - postCheckMemoryMsg(true, 0); - } -} diff --git a/services/java/com/android/server/FallbackCheckinService.java b/services/java/com/android/server/FallbackCheckinService.java deleted file mode 100644 index cf22446..0000000 --- a/services/java/com/android/server/FallbackCheckinService.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 deleted file mode 100644 index 4a430e0..0000000 --- a/services/java/com/android/server/GadgetService.java +++ /dev/null @@ -1,1137 +0,0 @@ -/* - * Copyright (C) 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; - -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.GadgetProviderInfo; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.SystemClock; -import android.util.AttributeSet; -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 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; - GadgetProviderInfo info; - ArrayList<GadgetId> instances = new ArrayList(); - PendingIntent broadcast; - boolean zombie; // if we're in safe mode, don't prune this just because nobody references it - - int tag; // for use while saving state (the index) - } - - static class Host { - int uid; - int hostId; - String packageName; - ArrayList<GadgetId> instances = new ArrayList(); - IGadgetHost callbacks; - boolean zombie; // if we're in safe mode, don't prune this just because nobody references it - - int tag; // for use while saving state (the index) - } - - static class GadgetId { - int gadgetId; - Provider provider; - RemoteViews views; - Host host; - } - - Context mContext; - PackageManager mPackageManager; - AlarmManager mAlarmManager; - ArrayList<Provider> mInstalledProviders = new ArrayList(); - int mNextGadgetId = GadgetManager.INVALID_GADGET_ID + 1; - ArrayList<GadgetId> mGadgetIds = new ArrayList(); - ArrayList<Host> mHosts = new ArrayList(); - boolean mSafeMode; - - GadgetService(Context context) { - mContext = context; - mPackageManager = context.getPackageManager(); - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - } - - public void systemReady(boolean safeMode) { - mSafeMode = safeMode; - - loadGadgetList(); - 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_REMOVED); - filter.addDataScheme("package"); - mContext.registerReceiver(mBroadcastReceiver, filter); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mGadgetIds) { - int N = mInstalledProviders.size(); - pw.println("Providers: (size=" + N + ")"); - for (int i=0; i<N; i++) { - Provider p = mInstalledProviders.get(i); - GadgetProviderInfo info = p.info; - pw.println(" [" + i + "] provder=" + info.provider - + " min=(" + info.minWidth + "x" + info.minHeight + ")" - + " updatePeriodMillis=" + info.updatePeriodMillis - + " initialLayout=" + info.initialLayout + " zombie=" + p.zombie); - } - - N = mGadgetIds.size(); - pw.println("GadgetIds: (size=" + N + ")"); - for (int i=0; i<N; i++) { - GadgetId id = mGadgetIds.get(i); - pw.println(" [" + i + "] gadgetId=" + id.gadgetId - + " host=" + id.host.hostId + "/" + id.host.packageName + " provider=" - + (id.provider == null ? "null" : id.provider.info.provider) - + " host.callbacks=" + (id.host != null ? id.host.callbacks : "(no host)") - + " views=" + id.views); - } - - N = mHosts.size(); - pw.println("Hosts: (size=" + N + ")"); - for (int i=0; i<N; i++) { - Host host = mHosts.get(i); - pw.println(" [" + i + "] packageName=" + host.packageName + " uid=" + host.uid - + " hostId=" + host.hostId + " callbacks=" + host.callbacks - + " instances.size=" + host.instances.size() + " zombie=" + host.zombie); - } - } - } - - public int allocateGadgetId(String packageName, int hostId) { - int callingUid = enforceCallingUid(packageName); - synchronized (mGadgetIds) { - int gadgetId = mNextGadgetId++; - - Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); - - GadgetId id = new GadgetId(); - id.gadgetId = gadgetId; - id.host = host; - - host.instances.add(id); - mGadgetIds.add(id); - - saveStateLocked(); - - return gadgetId; - } - } - - public void deleteGadgetId(int gadgetId) { - synchronized (mGadgetIds) { - GadgetId id = lookupGadgetIdLocked(gadgetId); - if (id != null) { - deleteGadgetLocked(id); - saveStateLocked(); - } - } - } - - public void deleteHost(int hostId) { - synchronized (mGadgetIds) { - int callingUid = getCallingUid(); - Host host = lookupHostLocked(callingUid, hostId); - if (host != null) { - deleteHostLocked(host); - saveStateLocked(); - } - } - } - - public void deleteAllHosts() { - synchronized (mGadgetIds) { - int callingUid = getCallingUid(); - final int N = mHosts.size(); - boolean changed = false; - for (int i=0; i<N; i++) { - Host host = mHosts.get(i); - if (host.uid == callingUid) { - deleteHostLocked(host); - changed = true; - } - } - if (changed) { - saveStateLocked(); - } - } - } - - void deleteHostLocked(Host host) { - final int N = host.instances.size(); - for (int i=0; i<N; i++) { - GadgetId id = host.instances.get(i); - deleteGadgetLocked(id); - } - host.instances.clear(); - mHosts.remove(host); - // it's gone or going away, abruptly drop the callback connection - host.callbacks = null; - } - - void deleteGadgetLocked(GadgetId id) { - Host host = id.host; - host.instances.remove(id); - pruneHostLocked(host); - - mGadgetIds.remove(id); - - Provider p = id.provider; - if (p != null) { - p.instances.remove(id); - if (!p.zombie) { - // send the broacast saying that this gadgetId has been deleted - Intent intent = new Intent(GadgetManager.ACTION_GADGET_DELETED); - intent.setComponent(p.info.provider); - intent.putExtra(GadgetManager.EXTRA_GADGET_ID, id.gadgetId); - mContext.sendBroadcast(intent); - if (p.instances.size() == 0) { - // cancel the future updates - cancelBroadcasts(p); - - // send the broacast saying that the provider is not in use any more - intent = new Intent(GadgetManager.ACTION_GADGET_DISABLED); - intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); - } - } - } - } - - void cancelBroadcasts(Provider p) { - if (p.broadcast != null) { - mAlarmManager.cancel(p.broadcast); - long token = Binder.clearCallingIdentity(); - try { - p.broadcast.cancel(); - } finally { - Binder.restoreCallingIdentity(token); - } - p.broadcast = null; - } - } - - public void bindGadgetId(int gadgetId, ComponentName provider) { - mContext.enforceCallingPermission(android.Manifest.permission.BIND_GADGET, - "bindGagetId gadgetId=" + gadgetId + " provider=" + provider); - synchronized (mGadgetIds) { - GadgetId id = lookupGadgetIdLocked(gadgetId); - if (id == null) { - throw new IllegalArgumentException("bad gadgetId"); - } - if (id.provider != null) { - throw new IllegalArgumentException("gadgetId " + gadgetId + " already bound to " - + id.provider.info.provider); - } - Provider p = lookupProviderLocked(provider); - if (p == null) { - throw new IllegalArgumentException("not a gadget provider: " + provider); - } - if (p.zombie) { - throw new IllegalArgumentException("can't bind to a 3rd party provider in" - + " safe mode: " + provider); - } - - id.provider = p; - p.instances.add(id); - int instancesSize = p.instances.size(); - if (instancesSize == 1) { - // tell the provider that it's ready - sendEnableIntentLocked(p); - } - - // send an update now -- We need this update now, and just for this gadgetId. - // It's less critical when the next one happens, so when we schdule the next one, - // we add updatePeriodMillis to its start time. That time will have some slop, - // but that's okay. - sendUpdateIntentLocked(p, new int[] { gadgetId }); - - // schedule the future updates - registerForBroadcastsLocked(p, getGadgetIds(p)); - saveStateLocked(); - } - } - - public GadgetProviderInfo getGadgetInfo(int gadgetId) { - synchronized (mGadgetIds) { - GadgetId id = lookupGadgetIdLocked(gadgetId); - if (id != null && id.provider != null && !id.provider.zombie) { - return id.provider.info; - } - return null; - } - } - - public RemoteViews getGadgetViews(int gadgetId) { - synchronized (mGadgetIds) { - GadgetId id = lookupGadgetIdLocked(gadgetId); - if (id != null) { - return id.views; - } - return null; - } - } - - public List<GadgetProviderInfo> getInstalledProviders() { - synchronized (mGadgetIds) { - final int N = mInstalledProviders.size(); - ArrayList<GadgetProviderInfo> result = new ArrayList(N); - for (int i=0; i<N; i++) { - Provider p = mInstalledProviders.get(i); - if (!p.zombie) { - result.add(p.info); - } - } - return result; - } - } - - public void updateGadgetIds(int[] gadgetIds, RemoteViews views) { - if (gadgetIds == null) { - return; - } - if (gadgetIds.length == 0) { - return; - } - final int N = gadgetIds.length; - - synchronized (mGadgetIds) { - for (int i=0; i<N; i++) { - GadgetId id = lookupGadgetIdLocked(gadgetIds[i]); - updateGadgetInstanceLocked(id, views); - } - } - } - - public void updateGadgetProvider(ComponentName provider, RemoteViews views) { - synchronized (mGadgetIds) { - Provider p = lookupProviderLocked(provider); - if (p == null) { - Log.w(TAG, "updateGadget: provider doesn't exist: " + provider); - return; - } - ArrayList<GadgetId> instances = p.instances; - final int N = instances.size(); - for (int i=0; i<N; i++) { - GadgetId id = instances.get(i); - updateGadgetInstanceLocked(id, views); - } - } - } - - void updateGadgetInstanceLocked(GadgetId id, RemoteViews views) { - // allow for stale gadgetIds and other badness - // lookup also checks that the calling process can access the gadget id - // drop unbound gadget ids (shouldn't be possible under normal circumstances) - if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { - id.views = views; - - // is anyone listening? - if (id.host.callbacks != null) { - try { - // the lock is held, but this is a oneway call - id.host.callbacks.updateGadget(id.gadgetId, views); - } catch (RemoteException e) { - // It failed; remove the callback. No need to prune because - // we know that this host is still referenced by this instance. - id.host.callbacks = null; - } - } - } - } - - public int[] startListening(IGadgetHost callbacks, String packageName, int hostId, - List<RemoteViews> updatedViews) { - int callingUid = enforceCallingUid(packageName); - synchronized (mGadgetIds) { - Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); - host.callbacks = callbacks; - - updatedViews.clear(); - - ArrayList<GadgetId> instances = host.instances; - int N = instances.size(); - int[] updatedIds = new int[N]; - for (int i=0; i<N; i++) { - GadgetId id = instances.get(i); - updatedIds[i] = id.gadgetId; - updatedViews.add(id.views); - } - return updatedIds; - } - } - - public void stopListening(int hostId) { - synchronized (mGadgetIds) { - Host host = lookupHostLocked(getCallingUid(), hostId); - host.callbacks = null; - pruneHostLocked(host); - } - } - - boolean canAccessGadgetId(GadgetId id, int callingUid) { - if (id.host.uid == callingUid) { - // Apps hosting the gadget have access to it. - return true; - } - if (id.provider != null && id.provider.uid == callingUid) { - // Apps providing the gadget have access to it (if the gadgetId has been bound) - return true; - } - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_GADGET) - == PackageManager.PERMISSION_GRANTED) { - // Apps that can bind have access to all gadgetIds. - return true; - } - // Nobody else can access it. - return false; - } - - GadgetId lookupGadgetIdLocked(int gadgetId) { - int callingUid = getCallingUid(); - final int N = mGadgetIds.size(); - for (int i=0; i<N; i++) { - GadgetId id = mGadgetIds.get(i); - if (id.gadgetId == gadgetId && canAccessGadgetId(id, callingUid)) { - return id; - } - } - return null; - } - - Provider lookupProviderLocked(ComponentName provider) { - final int N = mInstalledProviders.size(); - for (int i=0; i<N; i++) { - Provider p = mInstalledProviders.get(i); - if (p.info.provider.equals(provider)) { - return p; - } - } - return null; - } - - Host lookupHostLocked(int uid, int hostId) { - final int N = mHosts.size(); - for (int i=0; i<N; i++) { - Host h = mHosts.get(i); - if (h.uid == uid && h.hostId == hostId) { - return h; - } - } - return null; - } - - Host lookupOrAddHostLocked(int uid, String packageName, int hostId) { - final int N = mHosts.size(); - for (int i=0; i<N; i++) { - Host h = mHosts.get(i); - if (h.hostId == hostId && h.packageName.equals(packageName)) { - return h; - } - } - Host host = new Host(); - host.packageName = packageName; - host.uid = uid; - host.hostId = hostId; - mHosts.add(host); - return host; - } - - void pruneHostLocked(Host host) { - if (host.instances.size() == 0 && host.callbacks == null) { - mHosts.remove(host); - } - } - - void loadGadgetList() { - PackageManager pm = mPackageManager; - - Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE); - List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent, - PackageManager.GET_META_DATA); - - final int N = broadcastReceivers.size(); - for (int i=0; i<N; i++) { - ResolveInfo ri = broadcastReceivers.get(i); - addProviderLocked(ri); - } - } - - boolean addProviderLocked(ResolveInfo ri) { - Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, - ri.activityInfo.name), ri); - if (p != null) { - mInstalledProviders.add(p); - return true; - } else { - return false; - } - } - - void removeProviderLocked(int index, Provider p) { - int N = p.instances.size(); - for (int i=0; i<N; i++) { - GadgetId id = p.instances.get(i); - // Call back with empty RemoteViews - updateGadgetInstanceLocked(id, null); - // Stop telling the host about updates for this from now on - cancelBroadcasts(p); - // clear out references to this gadgetID - id.host.instances.remove(id); - mGadgetIds.remove(id); - id.provider = null; - pruneHostLocked(id.host); - id.host = null; - } - p.instances.clear(); - mInstalledProviders.remove(index); - // no need to send the DISABLE broadcast, since the receiver is gone anyway - cancelBroadcasts(p); - } - - void sendEnableIntentLocked(Provider p) { - Intent intent = new Intent(GadgetManager.ACTION_GADGET_ENABLED); - intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); - } - - void sendUpdateIntentLocked(Provider p, int[] gadgetIds) { - if (gadgetIds != null && gadgetIds.length > 0) { - Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE); - intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds); - intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); - } - } - - void registerForBroadcastsLocked(Provider p, int[] gadgetIds) { - if (p.info.updatePeriodMillis > 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.ACTION_GADGET_UPDATE); - 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<instancesSize; i++) { - gadgetIds[i] = p.instances.get(i).gadgetId; - } - return gadgetIds; - } - - private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { - Provider p = null; - - ActivityInfo activityInfo = ri.activityInfo; - XmlResourceParser parser = null; - try { - parser = activityInfo.loadXmlMetaData(mPackageManager, - GadgetManager.META_DATA_GADGET_PROVIDER); - if (parser == null) { - Log.w(TAG, "No " + GadgetManager.META_DATA_GADGET_PROVIDER + " meta-data for " - + "gadget provider '" + component + '\''); - return null; - } - - AttributeSet attrs = Xml.asAttributeSet(parser); - - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && type != XmlPullParser.START_TAG) { - // drain whitespace, comments, etc. - } - - String nodeName = parser.getName(); - if (!"gadget-provider".equals(nodeName)) { - Log.w(TAG, "Meta-data does not start with gadget-provider tag for" - + " gadget provider '" + component + '\''); - return null; - } - - p = new Provider(); - GadgetProviderInfo info = p.info = new GadgetProviderInfo(); - - info.provider = component; - p.uid = activityInfo.applicationInfo.uid; - - TypedArray sa = mContext.getResources().obtainAttributes(attrs, - com.android.internal.R.styleable.GadgetProviderInfo); - info.minWidth = sa.getDimensionPixelSize( - com.android.internal.R.styleable.GadgetProviderInfo_minWidth, 0); - info.minHeight = sa.getDimensionPixelSize( - com.android.internal.R.styleable.GadgetProviderInfo_minHeight, 0); - info.updatePeriodMillis = sa.getInt( - com.android.internal.R.styleable.GadgetProviderInfo_updatePeriodMillis, 0); - info.initialLayout = sa.getResourceId( - com.android.internal.R.styleable.GadgetProviderInfo_initialLayout, 0); - String className = sa.getString( - com.android.internal.R.styleable.GadgetProviderInfo_configure); - if (className != null) { - info.configure = new ComponentName(component.getPackageName(), className); - } - info.label = activityInfo.loadLabel(mPackageManager).toString(); - info.icon = ri.getIconResource(); - sa.recycle(); - } catch (Exception e) { - // Ok to catch Exception here, because anything going wrong because - // of what a client process passes to us should not be fatal for the - // system process. - Log.w(TAG, "XML parsing failed for gadget provider '" + component + '\'', e); - return null; - } finally { - if (parser != null) parser.close(); - } - return p; - } - - int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { - PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0); - if (pkgInfo == null || pkgInfo.applicationInfo == null) { - throw new PackageManager.NameNotFoundException(); - } - return pkgInfo.applicationInfo.uid; - } - - int enforceCallingUid(String packageName) throws IllegalArgumentException { - int callingUid = getCallingUid(); - int packageUid; - try { - packageUid = getUidForPackage(packageName); - } catch (PackageManager.NameNotFoundException ex) { - throw new IllegalArgumentException("packageName and uid don't match packageName=" - + packageName); - } - if (callingUid != packageUid) { - throw new IllegalArgumentException("packageName and uid don't match packageName=" - + packageName); - } - return callingUid; - } - - void sendInitialBroadcasts() { - synchronized (mGadgetIds) { - final int N = mInstalledProviders.size(); - for (int i=0; i<N; i++) { - Provider p = mInstalledProviders.get(i); - if (p.instances.size() > 0) { - sendEnableIntentLocked(p); - int[] gadgetIds = getGadgetIds(p); - sendUpdateIntentLocked(p, gadgetIds); - registerForBroadcastsLocked(p, gadgetIds); - } - } - } - } - - // only call from initialization -- it assumes that the data structures are all empty - void loadStateLocked() { - File temp = savedStateTempFile(); - File real = savedStateRealFile(); - - // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the - // real one. if there is both a real file and a temp one, assume that the temp one isn't - // fully written and delete it. - if (real.exists()) { - readStateFromFileLocked(real); - if (temp.exists()) { - temp.delete(); - } - } else if (temp.exists()) { - readStateFromFileLocked(temp); - temp.renameTo(real); - } - } - - void saveStateLocked() { - File temp = savedStateTempFile(); - File real = savedStateRealFile(); - - if (!real.exists()) { - // If the real one doesn't exist, it's either because this is the first time - // or because something went wrong while copying them. In this case, we can't - // trust anything that's in temp. In order to have the loadState code not - // use the temporary one until it's fully written, create an empty file - // for real, which will we'll shortly delete. - try { - real.createNewFile(); - } catch (IOException e) { - } - } - - if (temp.exists()) { - temp.delete(); - } - - writeStateToFileLocked(temp); - - real.delete(); - temp.renameTo(real); - } - - void writeStateToFileLocked(File file) { - FileOutputStream stream = null; - int N; - - try { - stream = new FileOutputStream(file, false); - XmlSerializer out = new FastXmlSerializer(); - out.setOutput(stream, "utf-8"); - out.startDocument(null, true); - - - out.startTag(null, "gs"); - - int providerIndex = 0; - N = mInstalledProviders.size(); - for (int i=0; i<N; i++) { - Provider p = mInstalledProviders.get(i); - if (p.instances.size() > 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<N; i++) { - Host host = mHosts.get(i); - out.startTag(null, "h"); - out.attribute(null, "pkg", host.packageName); - out.attribute(null, "id", Integer.toHexString(host.hostId)); - out.endTag(null, "h"); - host.tag = i; - } - - N = mGadgetIds.size(); - for (int i=0; i<N; i++) { - GadgetId id = mGadgetIds.get(i); - out.startTag(null, "g"); - out.attribute(null, "id", Integer.toHexString(id.gadgetId)); - out.attribute(null, "h", Integer.toHexString(id.host.tag)); - if (id.provider != null) { - out.attribute(null, "p", Integer.toHexString(id.provider.tag)); - } - out.endTag(null, "g"); - } - - out.endTag(null, "gs"); - - out.endDocument(); - stream.close(); - } catch (IOException e) { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException ex) { - } - if (file.exists()) { - file.delete(); - } - } - } - - void readStateFromFileLocked(File file) { - FileInputStream stream = null; - - boolean success = false; - - try { - stream = new FileInputStream(file); - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(stream, null); - - int type; - int providerIndex = 0; - HashMap<Integer,Provider> 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 (p == null && mSafeMode) { - // if we're in safe mode, make a temporary one - p = new Provider(); - p.info = new GadgetProviderInfo(); - p.info.provider = new ComponentName(pkg, cl); - p.zombie = true; - mInstalledProviders.add(p); - } - if (p != null) { - // if it wasn't uninstalled or something - 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); - } catch (PackageManager.NameNotFoundException ex) { - host.zombie = true; - } - if (!host.zombie || mSafeMode) { - // In safe mode, we don't discard the hosts we don't recognize - // so that they're not pruned from our list. Otherwise, we do. - host.hostId = Integer.parseInt( - parser.getAttributeValue(null, "id"), 16); - mHosts.add(host); - } - } - 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<N; i++) { - pruneHostLocked(mHosts.get(i)); - } - } else { - // failed reading, clean up - mGadgetIds.clear(); - mHosts.clear(); - final int N = mInstalledProviders.size(); - for (int i=0; i<N; i++) { - mInstalledProviders.get(i).instances.clear(); - } - } - } - - File savedStateTempFile() { - return new File("/data/system/" + SETTINGS_TMP_FILENAME); - //return new File(mContext.getFilesDir(), SETTINGS_FILENAME); - } - - File savedStateRealFile() { - return new File("/data/system/" + SETTINGS_FILENAME); - //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME); - } - - BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - //Log.d(TAG, "received " + action); - if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { - sendInitialBroadcasts(); - } else { - Uri uri = intent.getData(); - if (uri == null) { - return; - } - String pkgName = uri.getSchemeSpecificPart(); - if (pkgName == null) { - return; - } - - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - synchronized (mGadgetIds) { - Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { - // The package was just upgraded - updateProvidersForPackageLocked(pkgName); - } else { - // The package was just added - addProvidersForPackageLocked(pkgName); - } - saveStateLocked(); - } - } - else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { - // The package is being updated. We'll receive a PACKAGE_ADDED shortly. - } else { - synchronized (mGadgetIds) { - removeProvidersForPackageLocked(pkgName); - saveStateLocked(); - } - } - } - } - } - }; - - // TODO: If there's a better way of matching an intent filter against the - // packages for a given package, use that. - void addProvidersForPackageLocked(String pkgName) { - Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE); - List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, - PackageManager.GET_META_DATA); - - final int N = broadcastReceivers.size(); - for (int i=0; i<N; i++) { - ResolveInfo ri = broadcastReceivers.get(i); - ActivityInfo ai = ri.activityInfo; - - if (pkgName.equals(ai.packageName)) { - addProviderLocked(ri); - } - } - } - - // TODO: If there's a better way of matching an intent filter against the - // packages for a given package, use that. - void updateProvidersForPackageLocked(String pkgName) { - HashSet<String> keep = new HashSet(); - Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE); - List<ResolveInfo> 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<N; i++) { - ResolveInfo ri = broadcastReceivers.get(i); - ActivityInfo ai = ri.activityInfo; - if (pkgName.equals(ai.packageName)) { - ComponentName component = new ComponentName(ai.packageName, ai.name); - Provider p = lookupProviderLocked(component); - if (p == null) { - if (addProviderLocked(ri)) { - keep.add(ai.name); - } - } else { - Provider parsed = parseProviderInfoXml(component, ri); - if (parsed != null) { - keep.add(ai.name); - // Use the new GadgetProviderInfo. - GadgetProviderInfo oldInfo = p.info; - p.info = parsed.info; - // If it's enabled - final int M = p.instances.size(); - if (M > 0) { - int[] gadgetIds = getGadgetIds(p); - // Reschedule for the new updatePeriodMillis (don't worry about handling - // it specially if updatePeriodMillis didn't change because we just sent - // an update, and the next one will be updatePeriodMillis from now). - cancelBroadcasts(p); - registerForBroadcastsLocked(p, gadgetIds); - // If it's currently showing, call back with the new GadgetProviderInfo. - for (int j=0; j<M; j++) { - GadgetId id = p.instances.get(j); - if (id.host != null && id.host.callbacks != null) { - try { - id.host.callbacks.providerChanged(id.gadgetId, p.info); - } catch (RemoteException ex) { - // It failed; remove the callback. No need to prune because - // we know that this host is still referenced by this - // instance. - id.host.callbacks = null; - } - } - } - // Now that we've told the host, push out an update. - sendUpdateIntentLocked(p, gadgetIds); - } - } - } - } - } - - // prune the ones we don't want to keep - N = mInstalledProviders.size(); - for (int i=N-1; i>=0; i--) { - Provider p = mInstalledProviders.get(i); - if (pkgName.equals(p.info.provider.getPackageName()) - && !keep.contains(p.info.provider.getClassName())) { - removeProviderLocked(i, p); - } - } - } - - void removeProvidersForPackageLocked(String pkgName) { - int N = mInstalledProviders.size(); - for (int i=N-1; i>=0; i--) { - Provider p = mInstalledProviders.get(i); - if (pkgName.equals(p.info.provider.getPackageName())) { - removeProviderLocked(i, p); - } - } - - // Delete the hosts for this package too - // - // By now, we have removed any gadgets that were in any hosts here, - // so we don't need to worry about sending DISABLE broadcasts to them. - N = mHosts.size(); - for (int i=N-1; i>=0; i--) { - Host host = mHosts.get(i); - if (pkgName.equals(host.packageName)) { - deleteHostLocked(host); - } - } - } -} - diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java deleted file mode 100755 index 40456ff..0000000 --- a/services/java/com/android/server/HardwareService.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.os.Hardware; -import android.os.IHardwareService; -import android.os.Power; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.Binder; -import android.os.SystemClock; -import android.util.Log; - -public class HardwareService extends IHardwareService.Stub { - private static final String TAG = "HardwareService"; - - HardwareService(Context context) { - // Reset the hardware to a default state, in case this is a runtime - // restart instead of a fresh boot. - vibratorOff(); - - mContext = context; - PowerManager pm = (PowerManager)context.getSystemService( - Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mWakeLock.setReferenceCounted(true); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - context.registerReceiver(mIntentReceiver, filter); - } - - public void vibrate(long milliseconds) { - vibratePattern(new long[] { 0, milliseconds }, -1, - new Binder()); - } - - private boolean isAll0(long[] pattern) { - int N = pattern.length; - for (int i = 0; i < N; i++) { - if (pattern[i] != 0) { - return false; - } - } - return true; - } - - public void vibratePattern(long[] pattern, int repeat, IBinder token) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires VIBRATE permission"); - } - // so wakelock calls will succeed - long identity = Binder.clearCallingIdentity(); - try { - if (false) { - String s = ""; - int N = pattern.length; - for (int i=0; i<N; i++) { - s += " " + pattern[i]; - } - Log.i(TAG, "vibrating with pattern: " + s); - } - - // we're running in the server so we can't fail - if (pattern == null || pattern.length == 0 - || isAll0(pattern) - || repeat >= pattern.length || token == null) { - return; - } - - synchronized (this) { - Death death = new Death(token); - try { - token.linkToDeath(death, 0); - } catch (RemoteException e) { - return; - } - - Thread oldThread = mThread; - - if (oldThread != null) { - // stop the old one - synchronized (mThread) { - mThread.mDone = true; - mThread.notify(); - } - } - - if (mDeath != null) { - mToken.unlinkToDeath(mDeath, 0); - } - - mDeath = death; - mToken = token; - - // start the new thread - mThread = new VibrateThread(pattern, repeat); - mThread.start(); - } - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - public void cancelVibrate() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.VIBRATE, - "cancelVibrate"); - - // so wakelock calls will succeed - long identity = Binder.clearCallingIdentity(); - try { - doCancelVibrate(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - public boolean getFlashlightEnabled() { - return Hardware.getFlashlightEnabled(); - } - - public void setFlashlightEnabled(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) - != PackageManager.PERMISSION_GRANTED && - mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission"); - } - Hardware.setFlashlightEnabled(on); - } - - public void enableCameraFlash(int milliseconds) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CAMERA) - != PackageManager.PERMISSION_GRANTED && - mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires CAMERA or HARDWARE_TEST permission"); - } - Hardware.enableCameraFlash(milliseconds); - } - - public void setScreenBacklight(int brightness) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - // Don't let applications turn the screen all the way off - brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); - Hardware.setScreenBacklight(brightness); - } - - public void setKeyboardBacklight(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setKeyboardBacklight(on); - } - - public void setButtonBacklight(boolean on) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setButtonBacklight(on); - } - - public void setLedState(int colorARGB, int onMS, int offMS) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires HARDWARE_TEST permission"); - } - Hardware.setLedState(colorARGB, onMS, offMS); - } - - private void doCancelVibrate() { - synchronized (this) { - if (mThread != null) { - synchronized (mThread) { - mThread.mDone = true; - mThread.notify(); - } - mThread = null; - vibratorOff(); - } - } - } - - private class VibrateThread extends Thread { - long[] mPattern; - int mRepeat; - boolean mDone; - - VibrateThread(long[] pattern, int repeat) { - mPattern = pattern; - mRepeat = repeat; - mWakeLock.acquire(); - } - - private void delay(long duration) { - if (duration > 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; - long[] pattern = mPattern; - int len = pattern.length; - long duration = 0; - - while (!mDone) { - // add off-time duration to any accumulated on-time duration - if (index < len) { - duration += pattern[index++]; - } - - // 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); - } - } else { - if (mRepeat < 0) { - 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) { - if (mThread == this) { - mThread = null; - } - } - } - }; - - private class Death implements IBinder.DeathRecipient { - IBinder mMe; - - Death(IBinder me) { - mMe = me; - } - - public void binderDied() { - synchronized (HardwareService.this) { - if (mMe == mToken) { - doCancelVibrate(); - } - } - } - } - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - doCancelVibrate(); - } - } - }; - - private Context mContext; - private PowerManager.WakeLock mWakeLock; - - volatile VibrateThread mThread; - volatile Death mDeath; - volatile IBinder mToken; - - 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 deleted file mode 100644 index 855734d..0000000 --- a/services/java/com/android/server/HeadsetObserver.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.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; - -import java.io.FileReader; -import java.io.FileNotFoundException; - -/** - * <p>HeadsetObserver monitors for a wired headset. - */ -class HeadsetObserver extends UEventObserver { - private static final String TAG = HeadsetObserver.class.getSimpleName(); - - private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w"; - private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state"; - private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name"; - - private Context mContext; - - private int mHeadsetState; - private String mHeadsetName; - private boolean mAudioRouteNeedsUpdate; - private AudioManager mAudioManager; - - public HeadsetObserver(Context context) { - mContext = context; - - startObserving(HEADSET_UEVENT_MATCH); - - init(); // set initial status - } - - @Override - public void onUEvent(UEventObserver.UEvent event) { - Log.v(TAG, "Headset UEVENT: " + event.toString()); - - try { - update(event.get("SWITCH_NAME"), Integer.parseInt(event.get("SWITCH_STATE"))); - } catch (NumberFormatException e) { - Log.e(TAG, "Could not parse switch state from event " + event); - } - } - - private synchronized final void init() { - char[] buffer = new char[1024]; - - String newName = mHeadsetName; - int newState = mHeadsetState; - try { - FileReader file = new FileReader(HEADSET_STATE_PATH); - int len = file.read(buffer, 0, 1024); - newState = Integer.valueOf((new String(buffer, 0, len)).trim()); - - file = new FileReader(HEADSET_NAME_PATH); - len = file.read(buffer, 0, 1024); - newName = new String(buffer, 0, len).trim(); - - } catch (FileNotFoundException e) { - Log.w(TAG, "This kernel does not have wired headset support"); - } catch (Exception e) { - 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; - 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(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); - - intent.putExtra("state", mHeadsetState); - intent.putExtra("name", mHeadsetName); - - // 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/InputDevice.java b/services/java/com/android/server/InputDevice.java deleted file mode 100644 index 7b8a2a4..0000000 --- a/services/java/com/android/server/InputDevice.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 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; - -import android.util.Log; -import android.view.Display; -import android.view.MotionEvent; -import android.view.Surface; -import android.view.WindowManagerPolicy; - -public class InputDevice { - /** Amount that trackball needs to move in order to generate a key event. */ - static final int TRACKBALL_MOVEMENT_THRESHOLD = 6; - - final int id; - final int classes; - final String name; - final AbsoluteInfo absX; - final AbsoluteInfo absY; - final AbsoluteInfo absPressure; - final AbsoluteInfo absSize; - - long mDownTime = 0; - int mMetaKeysState = 0; - - final MotionState mAbs = new MotionState(0, 0); - final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD); - - static class MotionState { - int xPrecision; - int yPrecision; - float xMoveScale; - float yMoveScale; - MotionEvent currentMove = null; - boolean changed = false; - boolean down = false; - boolean lastDown = false; - long downTime = 0; - int x = 0; - int y = 0; - int pressure = 1; - int size = 0; - - MotionState(int mx, int my) { - xPrecision = mx; - yPrecision = my; - xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f; - yMoveScale = my != 0 ? (1.0f/my) : 1.0f; - } - - MotionEvent generateMotion(InputDevice device, long curTime, - boolean isAbs, Display display, int orientation, - int metaState) { - if (!changed) { - return null; - } - - float scaledX = x; - float scaledY = y; - float temp; - float scaledPressure = 1.0f; - float scaledSize = 0; - int edgeFlags = 0; - if (isAbs) { - int w = display.getWidth()-1; - int h = display.getHeight()-1; - if (orientation == Surface.ROTATION_90 - || orientation == Surface.ROTATION_270) { - int tmp = w; - w = h; - h = tmp; - } - if (device.absX != null) { - scaledX = ((scaledX-device.absX.minValue) - / device.absX.range) * w; - } - if (device.absY != null) { - scaledY = ((scaledY-device.absY.minValue) - / device.absY.range) * h; - } - if (device.absPressure != null) { - scaledPressure = - ((pressure-device.absPressure.minValue) - / (float)device.absPressure.range); - } - if (device.absSize != null) { - scaledSize = - ((size-device.absSize.minValue) - / (float)device.absSize.range); - } - switch (orientation) { - case Surface.ROTATION_90: - temp = scaledX; - scaledX = scaledY; - scaledY = w-temp; - break; - case Surface.ROTATION_180: - scaledX = w-scaledX; - scaledY = h-scaledY; - break; - case Surface.ROTATION_270: - temp = scaledX; - scaledX = h-scaledY; - scaledY = temp; - break; - } - - if (scaledX == 0) { - edgeFlags += MotionEvent.EDGE_LEFT; - } else if (scaledX == display.getWidth() - 1.0f) { - edgeFlags += MotionEvent.EDGE_RIGHT; - } - - if (scaledY == 0) { - edgeFlags += MotionEvent.EDGE_TOP; - } else if (scaledY == display.getHeight() - 1.0f) { - edgeFlags += MotionEvent.EDGE_BOTTOM; - } - - } else { - scaledX *= xMoveScale; - scaledY *= yMoveScale; - switch (orientation) { - case Surface.ROTATION_90: - temp = scaledX; - scaledX = scaledY; - scaledY = -temp; - break; - case Surface.ROTATION_180: - scaledX = -scaledX; - scaledY = -scaledY; - break; - case Surface.ROTATION_270: - temp = scaledX; - scaledX = -scaledY; - scaledY = temp; - break; - } - } - - changed = false; - if (down != lastDown) { - int action; - lastDown = down; - if (down) { - action = MotionEvent.ACTION_DOWN; - downTime = curTime; - } else { - action = MotionEvent.ACTION_UP; - } - currentMove = null; - if (!isAbs) { - x = y = 0; - } - return MotionEvent.obtain(downTime, curTime, action, - scaledX, scaledY, scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); - } else { - if (currentMove != null) { - if (false) Log.i("InputDevice", "Adding batch x=" + scaledX - + " y=" + scaledY + " to " + currentMove); - currentMove.addBatch(curTime, scaledX, scaledY, - scaledPressure, scaledSize, metaState); - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i("KeyInputQueue", "Updating: " + currentMove); - } - return null; - } - MotionEvent me = MotionEvent.obtain(downTime, curTime, - MotionEvent.ACTION_MOVE, scaledX, scaledY, - scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); - currentMove = me; - return me; - } - } - } - - static class AbsoluteInfo { - int minValue; - int maxValue; - int range; - int flat; - int fuzz; - }; - - InputDevice(int _id, int _classes, String _name, - AbsoluteInfo _absX, AbsoluteInfo _absY, - AbsoluteInfo _absPressure, AbsoluteInfo _absSize) { - id = _id; - classes = _classes; - name = _name; - absX = _absX; - absY = _absY; - absPressure = _absPressure; - absSize = _absSize; - } -}; diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java deleted file mode 100644 index 4b45828..0000000 --- a/services/java/com/android/server/InputMethodManagerService.java +++ /dev/null @@ -1,1564 +0,0 @@ -/* - * Copyright (C) 2006-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 com.android.internal.os.HandlerCaller; -import com.android.internal.view.IInputContext; -import com.android.internal.view.IInputMethod; -import com.android.internal.view.IInputMethodCallback; -import com.android.internal.view.IInputMethodClient; -import com.android.internal.view.IInputMethodManager; -import com.android.internal.view.IInputMethodSession; -import com.android.internal.view.InputBindResult; - -import com.android.server.status.IconData; -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; -import android.content.Context; -import android.content.DialogInterface; -import android.content.IntentFilter; -import android.content.DialogInterface.OnCancelListener; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Message; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.Log; -import android.util.PrintWriterPrinter; -import android.util.Printer; -import android.view.IWindowManager; -import android.view.WindowManager; -import android.view.inputmethod.InputBinding; -import android.view.inputmethod.InputMethod; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.EditorInfo; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * This class provides a system service that manages input methods. - */ -public class InputMethodManagerService extends IInputMethodManager.Stub - implements ServiceConnection, Handler.Callback { - static final boolean DEBUG = false; - static final String TAG = "InputManagerService"; - - static final int MSG_SHOW_IM_PICKER = 1; - - static final int MSG_UNBIND_INPUT = 1000; - static final int MSG_BIND_INPUT = 1010; - static final int MSG_SHOW_SOFT_INPUT = 1020; - static final int MSG_HIDE_SOFT_INPUT = 1030; - static final int MSG_ATTACH_TOKEN = 1040; - static final int MSG_CREATE_SESSION = 1050; - - static final int MSG_START_INPUT = 2000; - static final int MSG_RESTART_INPUT = 2010; - - static final int MSG_UNBIND_METHOD = 3000; - static final int MSG_BIND_METHOD = 3010; - - static final long TIME_TO_RECONNECT = 10*1000; - - static final int LOG_IMF_FORCE_RECONNECT_IME = 32000; - - final Context mContext; - final Handler mHandler; - final SettingsObserver mSettingsObserver; - final StatusBarService mStatusBar; - final IBinder mInputMethodIcon; - final IconData mInputMethodData; - final IWindowManager mIWindowManager; - final HandlerCaller mCaller; - - final InputBindResult mNoBinding = new InputBindResult(null, null, -1); - - // All known input methods. mMethodMap also serves as the global - // lock for this class. - final ArrayList<InputMethodInfo> mMethodList - = new ArrayList<InputMethodInfo>(); - final HashMap<String, InputMethodInfo> mMethodMap - = new HashMap<String, InputMethodInfo>(); - - final TextUtils.SimpleStringSplitter mStringColonSplitter - = new TextUtils.SimpleStringSplitter(':'); - - class SessionState { - final ClientState client; - final IInputMethod method; - final IInputMethodSession session; - - @Override - public String toString() { - return "SessionState{uid " + client.uid + " pid " + client.pid - + " method " + Integer.toHexString( - System.identityHashCode(method)) - + " session " + Integer.toHexString( - System.identityHashCode(session)) - + "}"; - } - - SessionState(ClientState _client, IInputMethod _method, - IInputMethodSession _session) { - client = _client; - method = _method; - session = _session; - } - } - - class ClientState { - final IInputMethodClient client; - final IInputContext inputContext; - final int uid; - final int pid; - final InputBinding binding; - - boolean sessionRequested; - SessionState curSession; - - @Override - public String toString() { - return "ClientState{" + Integer.toHexString( - System.identityHashCode(this)) + " uid " + uid - + " pid " + pid + "}"; - } - - ClientState(IInputMethodClient _client, IInputContext _inputContext, - int _uid, int _pid) { - client = _client; - inputContext = _inputContext; - uid = _uid; - pid = _pid; - binding = new InputBinding(null, inputContext.asBinder(), uid, pid); - } - } - - final HashMap<IBinder, ClientState> mClients - = new HashMap<IBinder, ClientState>(); - - /** - * Id of the currently selected input method. - */ - String mCurMethodId; - - /** - * The current binding sequence number, incremented every time there is - * a new bind performed. - */ - int mCurSeq; - - /** - * The client that is currently bound to an input method. - */ - ClientState mCurClient; - - /** - * The input context last provided by the current client. - */ - IInputContext mCurInputContext; - - /** - * The attributes last provided by the current client. - */ - EditorInfo mCurAttribute; - - /** - * The input method ID of the input method service that we are currently - * connected to or in the process of connecting to. - */ - String mCurId; - - /** - * Set to true if our ServiceConnection is currently actively bound to - * a service (whether or not we have gotten its IBinder back yet). - */ - boolean mHaveConnection; - - /** - * Set if the client has asked for the input method to be shown. - */ - boolean mShowRequested; - - /** - * Set if we were explicitly told to show the input method. - */ - 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; - - /** - * The Intent used to connect to the current input method. - */ - Intent mCurIntent; - - /** - * The token we have made for the currently active input method, to - * identify it in the future. - */ - IBinder mCurToken; - - /** - * If non-null, this is the input method service we are currently connected - * to. - */ - IInputMethod mCurMethod; - - /** - * Time that we last initiated a bind to the input method, to determine - * if we should try to disconnect and reconnect to it. - */ - long mLastBindTime; - - /** - * Have we called mCurMethod.bindInput()? - */ - boolean mBoundToMethod; - - /** - * Currently enabled session. Only touched by service thread, not - * protected by a lock. - */ - SessionState mEnabledSession; - - /** - * True if the screen is on. The value is true initially. - */ - boolean mScreenOn = true; - - AlertDialog.Builder mDialogBuilder; - AlertDialog mSwitchingDialog; - InputMethodInfo[] mIms; - CharSequence[] mItems; - - class SettingsObserver extends ContentObserver { - SettingsObserver(Handler handler) { - super(handler); - ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.DEFAULT_INPUT_METHOD), false, this); - } - - @Override public void onChange(boolean selfChange) { - synchronized (mMethodMap) { - updateFromSettingsLocked(); - } - } - } - - class ScreenOnOffReceiver extends android.content.BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { - mScreenOn = true; - } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - mScreenOn = false; - } else { - Log.w(TAG, "Unexpected intent " + intent); - } - - // Inform the current client of the change in active status - try { - if (mCurClient != null && mCurClient.client != null) { - mCurClient.client.setActive(mScreenOn); - } - } catch (RemoteException e) { - Log.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid " - + mCurClient.pid + " uid " + mCurClient.uid); - } - } - } - - class PackageReceiver extends android.content.BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mMethodMap) { - buildInputMethodListLocked(mMethodList, mMethodMap); - - InputMethodInfo curIm = null; - String curInputMethodId = Settings.Secure.getString(context - .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); - final int N = mMethodList.size(); - if (curInputMethodId != null) { - for (int i=0; i<N; i++) { - if (mMethodList.get(i).getId().equals(curInputMethodId)) { - curIm = mMethodList.get(i); - } - } - } - - boolean changed = false; - - Uri uri = intent.getData(); - String pkg = uri != null ? uri.getSchemeSpecificPart() : null; - if (curIm != null && curIm.getPackageName().equals(pkg)) { - ServiceInfo si = null; - try { - si = mContext.getPackageManager().getServiceInfo( - curIm.getComponent(), 0); - } catch (PackageManager.NameNotFoundException ex) { - } - if (si == null) { - // Uh oh, current input method is no longer around! - // Pick another one... - Log.i(TAG, "Current input method removed: " + curInputMethodId); - List<InputMethodInfo> enabled = getEnabledInputMethodListLocked(); - if (enabled != null && enabled.size() > 0) { - changed = true; - curIm = enabled.get(0); - curInputMethodId = curIm.getId(); - Log.i(TAG, "Switching to: " + curInputMethodId); - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - curInputMethodId); - } else if (curIm != null) { - changed = true; - curIm = null; - curInputMethodId = ""; - Log.i(TAG, "Unsetting current input method"); - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - curInputMethodId); - } - } - - } else if (curIm == null) { - // We currently don't have a default input method... is - // one now available? - List<InputMethodInfo> enabled = getEnabledInputMethodListLocked(); - if (enabled != null && enabled.size() > 0) { - changed = true; - curIm = enabled.get(0); - curInputMethodId = curIm.getId(); - Log.i(TAG, "New default input method: " + curInputMethodId); - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - curInputMethodId); - } - } - - if (changed) { - updateFromSettingsLocked(); - } - } - } - } - - class MethodCallback extends IInputMethodCallback.Stub { - final IInputMethod mMethod; - - MethodCallback(IInputMethod method) { - mMethod = method; - } - - public void finishedEvent(int seq, boolean handled) throws RemoteException { - } - - public void sessionCreated(IInputMethodSession session) throws RemoteException { - onSessionCreated(mMethod, session); - } - } - - public InputMethodManagerService(Context context, StatusBarService statusBar) { - mContext = context; - mHandler = new Handler(this); - mIWindowManager = IWindowManager.Stub.asInterface( - ServiceManager.getService(Context.WINDOW_SERVICE)); - mCaller = new HandlerCaller(context, new HandlerCaller.Callback() { - public void executeMessage(Message msg) { - handleMessage(msg); - } - }); - - IntentFilter packageFilt = new IntentFilter(); - packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); - packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); - packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); - packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); - packageFilt.addDataScheme("package"); - mContext.registerReceiver(new PackageReceiver(), packageFilt); - - IntentFilter screenOnOffFilt = new IntentFilter(); - screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON); - screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF); - mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt); - - buildInputMethodListLocked(mMethodList, mMethodMap); - - final String enabledStr = Settings.Secure.getString( - mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS); - Log.i(TAG, "Enabled input methods: " + enabledStr); - if (enabledStr == null) { - Log.i(TAG, "Enabled input methods has not been set, enabling all"); - InputMethodInfo defIm = null; - StringBuilder sb = new StringBuilder(256); - final int N = mMethodList.size(); - for (int i=0; i<N; i++) { - InputMethodInfo imi = mMethodList.get(i); - Log.i(TAG, "Adding: " + imi.getId()); - if (i > 0) sb.append(':'); - sb.append(imi.getId()); - if (defIm == null && imi.getIsDefaultResourceId() != 0) { - try { - Resources res = mContext.createPackageContext( - imi.getPackageName(), 0).getResources(); - if (res.getBoolean(imi.getIsDefaultResourceId())) { - defIm = imi; - Log.i(TAG, "Selected default: " + imi.getId()); - } - } catch (PackageManager.NameNotFoundException ex) { - } catch (Resources.NotFoundException ex) { - } - } - } - if (defIm == null && N > 0) { - defIm = mMethodList.get(0); - Log.i(TAG, "No default found, using " + defIm.getId()); - } - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, sb.toString()); - if (defIm != null) { - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId()); - } - } - - mStatusBar = statusBar; - mInputMethodData = IconData.makeIcon("ime", null, 0, 0, 0); - mInputMethodIcon = statusBar.addIcon(mInputMethodData, null); - statusBar.setIconVisibility(mInputMethodIcon, false); - - mSettingsObserver = new SettingsObserver(mHandler); - updateFromSettingsLocked(); - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - // The input method manager only throws security exceptions, so let's - // log all others. - if (!(e instanceof SecurityException)) { - Log.e(TAG, "Input Method Manager Crash", e); - } - throw e; - } - } - - public void systemReady() { - } - - public List<InputMethodInfo> getInputMethodList() { - synchronized (mMethodMap) { - return new ArrayList<InputMethodInfo>(mMethodList); - } - } - - public List<InputMethodInfo> getEnabledInputMethodList() { - synchronized (mMethodMap) { - return getEnabledInputMethodListLocked(); - } - } - - List<InputMethodInfo> getEnabledInputMethodListLocked() { - final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>(); - - final String enabledStr = Settings.Secure.getString( - mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS); - if (enabledStr != null) { - final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(enabledStr); - - while (splitter.hasNext()) { - InputMethodInfo info = mMethodMap.get(splitter.next()); - if (info != null) { - res.add(info); - } - } - } - - return res; - } - - public void addClient(IInputMethodClient client, - IInputContext inputContext, int uid, int pid) { - synchronized (mMethodMap) { - mClients.put(client.asBinder(), new ClientState(client, - inputContext, uid, pid)); - } - } - - public void removeClient(IInputMethodClient client) { - synchronized (mMethodMap) { - mClients.remove(client.asBinder()); - } - } - - void executeOrSendMessage(IInterface target, Message msg) { - if (target.asBinder() instanceof Binder) { - mCaller.sendMessage(msg); - } else { - handleMessage(msg); - msg.recycle(); - } - } - - void unbindCurrentInputLocked() { - if (mCurClient != null) { - if (DEBUG) Log.v(TAG, "unbindCurrentInputLocked: client = " - + mCurClient.client.asBinder()); - if (mBoundToMethod) { - mBoundToMethod = false; - if (mCurMethod != null) { - executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( - MSG_UNBIND_INPUT, mCurMethod)); - } - } - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO( - MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); - mCurClient.sessionRequested = false; - - // Call setActive(false) on the old client - try { - mCurClient.client.setActive(false); - } catch (RemoteException e) { - Log.w(TAG, "Got RemoteException sending setActive(false) notification to pid " - + mCurClient.pid + " uid " + mCurClient.uid); - } - mCurClient = null; - } - } - - private int getImeShowFlags() { - int flags = 0; - if (mShowForced) { - flags |= InputMethod.SHOW_FORCED - | InputMethod.SHOW_EXPLICIT; - } else if (mShowExplicitlyRequested) { - flags |= InputMethod.SHOW_EXPLICIT; - } - return flags; - } - - private int getAppShowFlags() { - int flags = 0; - if (mShowForced) { - flags |= InputMethodManager.SHOW_FORCED; - } else if (!mShowExplicitlyRequested) { - flags |= InputMethodManager.SHOW_IMPLICIT; - } - return flags; - } - - InputBindResult attachNewInputLocked(boolean initial, boolean needResult) { - if (!mBoundToMethod) { - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_BIND_INPUT, mCurMethod, mCurClient.binding)); - mBoundToMethod = true; - } - final SessionState session = mCurClient.curSession; - if (initial) { - executeOrSendMessage(session.method, mCaller.obtainMessageOOO( - MSG_START_INPUT, session, mCurInputContext, mCurAttribute)); - } else { - 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(getAppShowFlags()); - } - return needResult - ? new InputBindResult(session.session, mCurId, mCurSeq) - : null; - } - - InputBindResult startInputLocked(IInputMethodClient client, - IInputContext inputContext, EditorInfo attribute, - boolean initial, boolean needResult) { - // If no method is currently selected, do nothing. - if (mCurMethodId == null) { - return mNoBinding; - } - - ClientState cs = mClients.get(client.asBinder()); - if (cs == null) { - throw new IllegalArgumentException("unknown client " - + client.asBinder()); - } - - try { - if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) { - // Check with the window manager to make sure this client actually - // has a window with focus. If not, reject. This is thread safe - // because if the focus changes some time before or after, the - // next client receiving focus that has any interest in input will - // be calling through here after that change happens. - Log.w(TAG, "Starting input on non-focused client " + cs.client - + " (uid=" + cs.uid + " pid=" + cs.pid + ")"); - return null; - } - } catch (RemoteException e) { - } - - if (mCurClient != cs) { - // If the client is changing, we need to switch over to the new - // one. - unbindCurrentInputLocked(); - if (DEBUG) Log.v(TAG, "switching to client: client = " - + cs.client.asBinder()); - - // If the screen is on, inform the new client it is active - if (mScreenOn) { - try { - cs.client.setActive(mScreenOn); - } catch (RemoteException e) { - Log.w(TAG, "Got RemoteException sending setActive notification to pid " - + cs.pid + " uid " + cs.uid); - } - } - } - - // Bump up the sequence for this client and attach it. - mCurSeq++; - if (mCurSeq <= 0) mCurSeq = 1; - mCurClient = cs; - mCurInputContext = inputContext; - mCurAttribute = attribute; - - // Check if the input method is changing. - if (mCurId != null && mCurId.equals(mCurMethodId)) { - if (cs.curSession != null) { - // Fast case: if we are already connected to the input method, - // then just return it. - return attachNewInputLocked(initial, needResult); - } - if (mHaveConnection) { - if (mCurMethod != null) { - if (!cs.sessionRequested) { - cs.sessionRequested = true; - if (DEBUG) Log.v(TAG, "Creating new session for client " + cs); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod))); - } - // Return to client, and we will get back with it when - // we have had a session made for it. - return new InputBindResult(null, mCurId, mCurSeq); - } else if (SystemClock.uptimeMillis() - < (mLastBindTime+TIME_TO_RECONNECT)) { - // In this case we have connected to the service, but - // don't yet have its interface. If it hasn't been too - // long since we did the connection, we'll return to - // the client and wait to get the service interface so - // we can report back. If it has been too long, we want - // to fall through so we can try a disconnect/reconnect - // to see if we can get back in touch with the service. - return new InputBindResult(null, mCurId, mCurSeq); - } else { - EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId, - SystemClock.uptimeMillis()-mLastBindTime, 0); - } - } - } - - InputMethodInfo info = mMethodMap.get(mCurMethodId); - if (info == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); - } - - if (mHaveConnection) { - mContext.unbindService(this); - mHaveConnection = false; - } - - if (mCurToken != null) { - try { - if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken); - mIWindowManager.removeWindowToken(mCurToken); - } catch (RemoteException e) { - } - mCurToken = null; - } - - clearCurMethod(); - - mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE); - mCurIntent.setComponent(info.getComponent()); - if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) { - mLastBindTime = SystemClock.uptimeMillis(); - mHaveConnection = true; - 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) { - } - return new InputBindResult(null, mCurId, mCurSeq); - } else { - mCurIntent = null; - Log.w(TAG, "Failure connecting to input method service: " - + mCurIntent); - } - return null; - } - - public InputBindResult startInput(IInputMethodClient client, - IInputContext inputContext, EditorInfo attribute, - boolean initial, boolean needResult) { - synchronized (mMethodMap) { - final long ident = Binder.clearCallingIdentity(); - try { - return startInputLocked(client, inputContext, attribute, - initial, needResult); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void finishInput(IInputMethodClient client) { - } - - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mMethodMap) { - 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) { - if (DEBUG) Log.v(TAG, "Creating first session while with client " - + mCurClient); - executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( - MSG_CREATE_SESSION, mCurMethod, - new MethodCallback(mCurMethod))); - } - } - } - } - } - - void onSessionCreated(IInputMethod method, IInputMethodSession session) { - synchronized (mMethodMap) { - if (mCurMethod != null && method != null - && mCurMethod.asBinder() == method.asBinder()) { - if (mCurClient != null) { - mCurClient.curSession = new SessionState(mCurClient, - method, session); - mCurClient.sessionRequested = false; - InputBindResult res = attachNewInputLocked(true, true); - if (res.method != null) { - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO( - MSG_BIND_METHOD, mCurClient.client, res)); - } - } - } - } - } - - void clearCurMethod() { - if (mCurMethod != null) { - for (ClientState cs : mClients.values()) { - cs.sessionRequested = false; - cs.curSession = null; - } - mCurMethod = null; - } - mStatusBar.setIconVisibility(mInputMethodIcon, false); - } - - public void onServiceDisconnected(ComponentName name) { - synchronized (mMethodMap) { - if (DEBUG) Log.v(TAG, "Service disconnected: " + name - + " mCurIntent=" + mCurIntent); - if (mCurMethod != null && mCurIntent != null - && name.equals(mCurIntent.getComponent())) { - clearCurMethod(); - // We consider this to be a new bind attempt, since the system - // should now try to restart the service for us. - mLastBindTime = SystemClock.uptimeMillis(); - mShowRequested = mInputShown; - mInputShown = false; - if (mCurClient != null) { - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO( - MSG_UNBIND_METHOD, mCurSeq, mCurClient.client)); - } - } - } - } - - public void updateStatusIcon(IBinder token, String packageName, int iconId) { - long ident = Binder.clearCallingIdentity(); - try { - if (token == null || mCurToken != token) { - Log.w(TAG, "Ignoring setInputMethod of token: " + token); - return; - } - - synchronized (mMethodMap) { - if (iconId == 0) { - if (DEBUG) Log.d(TAG, "hide the small icon for the input method"); - mStatusBar.setIconVisibility(mInputMethodIcon, false); - } else if (packageName != null) { - if (DEBUG) Log.d(TAG, "show a small icon for the input method"); - mInputMethodData.iconId = iconId; - mInputMethodData.iconPackage = packageName; - mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null); - mStatusBar.setIconVisibility(mInputMethodIcon, true); - } - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - void updateFromSettingsLocked() { - String id = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); - if (id != null) { - try { - setInputMethodLocked(id); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Unknown input method from prefs: " + id, e); - } - } - } - - void setInputMethodLocked(String id) { - InputMethodInfo info = mMethodMap.get(id); - if (info == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); - } - - if (id.equals(mCurMethodId)) { - return; - } - - final long ident = Binder.clearCallingIdentity(); - try { - mCurMethodId = id; - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, id); - - 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); - } - } - - public void showSoftInput(IInputMethodClient client, int flags) { - long ident = Binder.clearCallingIdentity(); - try { - synchronized (mMethodMap) { - if (mCurClient == null || client == null - || mCurClient.client.asBinder() != client.asBinder()) { - try { - // We need to check if this is the current client with - // focus in the window manager, to allow this call to - // be made before input is started in it. - if (!mIWindowManager.inputMethodClientHasFocus(client)) { - Log.w(TAG, "Ignoring showSoftInput of: " + client); - return; - } - } catch (RemoteException e) { - } - } - - if (DEBUG) Log.v(TAG, "Client requesting input be shown"); - showCurrentInputLocked(flags); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - void showCurrentInputLocked(int flags) { - mShowRequested = true; - 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, getImeShowFlags(), mCurMethod)); - mInputShown = true; - } else if (mHaveConnection && SystemClock.uptimeMillis() - < (mLastBindTime+TIME_TO_RECONNECT)) { - // The client has asked to have the input method shown, but - // we have been sitting here too long with a connection to the - // service and no interface received, so let's disconnect/connect - // to try to prod things along. - EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId, - SystemClock.uptimeMillis()-mLastBindTime,1); - mContext.unbindService(this); - mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE); - } - } - - public void hideSoftInput(IInputMethodClient client, int flags) { - long ident = Binder.clearCallingIdentity(); - try { - synchronized (mMethodMap) { - if (mCurClient == null || client == null - || mCurClient.client.asBinder() != client.asBinder()) { - try { - // We need to check if this is the current client with - // focus in the window manager, to allow this call to - // be made before input is started in it. - if (!mIWindowManager.inputMethodClientHasFocus(client)) { - Log.w(TAG, "Ignoring hideSoftInput of: " + client); - return; - } - } catch (RemoteException e) { - } - } - - if (DEBUG) Log.v(TAG, "Client requesting input be hidden"); - hideCurrentInputLocked(flags); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - void hideCurrentInputLocked(int flags) { - if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 - && (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)); - } - mInputShown = false; - mShowRequested = false; - mShowExplicitlyRequested = false; - mShowForced = false; - } - - public void windowGainedFocus(IInputMethodClient client, - boolean viewHasFocus, boolean isTextEditor, int softInputMode, - boolean first, int windowFlags) { - long ident = Binder.clearCallingIdentity(); - try { - synchronized (mMethodMap) { - if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder() - + " viewHasFocus=" + viewHasFocus - + " isTextEditor=" + isTextEditor - + " softInputMode=#" + Integer.toHexString(softInputMode) - + " first=" + first + " flags=#" - + Integer.toHexString(windowFlags)); - - if (mCurClient == null || client == null - || mCurClient.client.asBinder() != client.asBinder()) { - try { - // We need to check if this is the current client with - // focus in the window manager, to allow this call to - // be made before input is started in it. - if (!mIWindowManager.inputMethodClientHasFocus(client)) { - Log.w(TAG, "Ignoring focus gain of: " + client); - return; - } - } catch (RemoteException e) { - } - } - - switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) { - case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: - if (!isTextEditor || (softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) - != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) { - if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) { - // There is no focus view, and this window will - // 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(InputMethodManager.HIDE_NOT_ALWAYS); - } - } else if (isTextEditor && (softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) - == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE - && (softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { - // There is a focus view, and we are navigating forward - // into the window, so show the input window for the user. - if (DEBUG) Log.v(TAG, "Unspecified window will show input"); - showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT); - } - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED: - // Do nothing. - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN: - if ((softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { - if (DEBUG) Log.v(TAG, "Window asks to hide input going forward"); - hideCurrentInputLocked(0); - } - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: - if (DEBUG) Log.v(TAG, "Window asks to hide input"); - hideCurrentInputLocked(0); - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE: - if ((softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { - if (DEBUG) Log.v(TAG, "Window asks to show input going forward"); - showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT); - } - break; - case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE: - if (DEBUG) Log.v(TAG, "Window asks to always show input"); - showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT); - break; - } - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - public void showInputMethodPickerFromClient(IInputMethodClient client) { - synchronized (mMethodMap) { - if (mCurClient == null || client == null - || mCurClient.client.asBinder() != client.asBinder()) { - Log.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client); - } - - mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER); - } - } - - public void setInputMethod(IBinder token, String id) { - synchronized (mMethodMap) { - if (token == null) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Using null token requires permission " - + android.Manifest.permission.WRITE_SECURE_SETTINGS); - } - } else if (mCurToken != token) { - Log.w(TAG, "Ignoring setInputMethod of token: " + token); - return; - } - - long ident = Binder.clearCallingIdentity(); - try { - setInputMethodLocked(id); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void hideMySoftInput(IBinder token, int flags) { - synchronized (mMethodMap) { - if (token == null || mCurToken != token) { - Log.w(TAG, "Ignoring hideInputMethod of token: " + token); - return; - } - - long ident = Binder.clearCallingIdentity(); - try { - hideCurrentInputLocked(flags); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - void setEnabledSessionInMainThread(SessionState session) { - if (mEnabledSession != session) { - if (mEnabledSession != null) { - try { - if (DEBUG) Log.v(TAG, "Disabling: " + mEnabledSession); - mEnabledSession.method.setSessionEnabled( - mEnabledSession.session, false); - } catch (RemoteException e) { - } - } - mEnabledSession = session; - try { - if (DEBUG) Log.v(TAG, "Enabling: " + mEnabledSession); - session.method.setSessionEnabled( - session.session, true); - } catch (RemoteException e) { - } - } - } - - public boolean handleMessage(Message msg) { - HandlerCaller.SomeArgs args; - switch (msg.what) { - case MSG_SHOW_IM_PICKER: - showInputMethodMenu(); - return true; - - // --------------------------------------------------------- - - case MSG_UNBIND_INPUT: - try { - ((IInputMethod)msg.obj).unbindInput(); - } catch (RemoteException e) { - // There is nothing interesting about the method dying. - } - return true; - case MSG_BIND_INPUT: - args = (HandlerCaller.SomeArgs)msg.obj; - try { - ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2); - } catch (RemoteException e) { - } - return true; - case MSG_SHOW_SOFT_INPUT: - try { - ((IInputMethod)msg.obj).showSoftInput(msg.arg1); - } catch (RemoteException e) { - } - return true; - case MSG_HIDE_SOFT_INPUT: - try { - ((IInputMethod)msg.obj).hideSoftInput(); - } catch (RemoteException e) { - } - return true; - 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) { - } - return true; - case MSG_CREATE_SESSION: - args = (HandlerCaller.SomeArgs)msg.obj; - try { - ((IInputMethod)args.arg1).createSession( - (IInputMethodCallback)args.arg2); - } catch (RemoteException e) { - } - return true; - - // --------------------------------------------------------- - - case MSG_START_INPUT: - args = (HandlerCaller.SomeArgs)msg.obj; - try { - SessionState session = (SessionState)args.arg1; - setEnabledSessionInMainThread(session); - session.method.startInput((IInputContext)args.arg2, - (EditorInfo)args.arg3); - } catch (RemoteException e) { - } - return true; - case MSG_RESTART_INPUT: - args = (HandlerCaller.SomeArgs)msg.obj; - try { - SessionState session = (SessionState)args.arg1; - setEnabledSessionInMainThread(session); - session.method.restartInput((IInputContext)args.arg2, - (EditorInfo)args.arg3); - } catch (RemoteException e) { - } - return true; - - // --------------------------------------------------------- - - case MSG_UNBIND_METHOD: - try { - ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1); - } catch (RemoteException e) { - // There is nothing interesting about the last client dying. - } - return true; - case MSG_BIND_METHOD: - args = (HandlerCaller.SomeArgs)msg.obj; - try { - ((IInputMethodClient)args.arg1).onBindMethod( - (InputBindResult)args.arg2); - } catch (RemoteException e) { - Log.w(TAG, "Client died receiving input method " + args.arg2); - } - return true; - } - return false; - } - - void buildInputMethodListLocked(ArrayList<InputMethodInfo> list, - HashMap<String, InputMethodInfo> map) { - list.clear(); - map.clear(); - - PackageManager pm = mContext.getPackageManager(); - - List<ResolveInfo> services = pm.queryIntentServices( - new Intent(InputMethod.SERVICE_INTERFACE), - PackageManager.GET_META_DATA); - - for (int i = 0; i < services.size(); ++i) { - ResolveInfo ri = services.get(i); - ServiceInfo si = ri.serviceInfo; - ComponentName compName = new ComponentName(si.packageName, si.name); - if (!android.Manifest.permission.BIND_INPUT_METHOD.equals( - si.permission)) { - Log.w(TAG, "Skipping input method " + compName - + ": it does not require the permission " - + android.Manifest.permission.BIND_INPUT_METHOD); - continue; - } - - if (DEBUG) Log.d(TAG, "Checking " + compName); - - try { - InputMethodInfo p = new InputMethodInfo(mContext, ri); - list.add(p); - map.put(p.getId(), p); - - if (DEBUG) { - Log.d(TAG, "Found a third-party input method " + p); - } - - } catch (XmlPullParserException e) { - Log.w(TAG, "Unable to load input method " + compName, e); - } catch (IOException e) { - Log.w(TAG, "Unable to load input method " + compName, e); - } - } - } - - // ---------------------------------------------------------------------- - - void showInputMethodMenu() { - if (DEBUG) Log.v(TAG, "Show switching menu"); - - hideInputMethodMenu(); - - final Context context = mContext; - - final PackageManager pm = context.getPackageManager(); - - String lastInputMethodId = Settings.Secure.getString(context - .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); - if (DEBUG) Log.v(TAG, "Current IME: " + lastInputMethodId); - - final List<InputMethodInfo> immis = getEnabledInputMethodList(); - - int N = (immis == null ? 0 : immis.size()); - - mItems = new CharSequence[N]; - mIms = new InputMethodInfo[N]; - - for (int i = 0; i < N; ++i) { - InputMethodInfo property = immis.get(i); - mItems[i] = property.loadLabel(pm); - mIms[i] = property; - } - - int checkedItem = 0; - for (int i = 0; i < N; ++i) { - if (mIms[i].getId().equals(lastInputMethodId)) { - checkedItem = i; - break; - } - } - - AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - hideInputMethodMenu(); - } - }; - - TypedArray a = context.obtainStyledAttributes(null, - com.android.internal.R.styleable.DialogPreference, - com.android.internal.R.attr.alertDialogStyle, 0); - mDialogBuilder = new AlertDialog.Builder(context) - .setTitle(com.android.internal.R.string.select_input_method) - .setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - hideInputMethodMenu(); - } - }) - .setIcon(a.getDrawable( - com.android.internal.R.styleable.DialogPreference_dialogTitle)); - a.recycle(); - - mDialogBuilder.setSingleChoiceItems(mItems, checkedItem, - new AlertDialog.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - synchronized (mMethodMap) { - InputMethodInfo im = mIms[which]; - hideInputMethodMenu(); - setInputMethodLocked(im.getId()); - } - } - }); - - synchronized (mMethodMap) { - mSwitchingDialog = mDialogBuilder.create(); - mSwitchingDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG); - mSwitchingDialog.show(); - } - } - - void hideInputMethodMenu() { - if (DEBUG) Log.v(TAG, "Hide switching menu"); - - synchronized (mMethodMap) { - if (mSwitchingDialog != null) { - mSwitchingDialog.dismiss(); - mSwitchingDialog = null; - } - - mDialogBuilder = null; - mItems = null; - mIms = null; - } - } - - // ---------------------------------------------------------------------- - - public boolean setInputMethodEnabled(String id, boolean enabled) { - synchronized (mMethodMap) { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires permission " - + android.Manifest.permission.WRITE_SECURE_SETTINGS); - } - - long ident = Binder.clearCallingIdentity(); - try { - // Make sure this is a valid input method. - InputMethodInfo imm = mMethodMap.get(id); - if (imm == null) { - if (imm == null) { - throw new IllegalArgumentException("Unknown id: " + mCurMethodId); - } - } - - StringBuilder builder = new StringBuilder(256); - - boolean removed = false; - String firstId = null; - - // Look through the currently enabled input methods. - String enabledStr = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS); - if (enabledStr != null) { - final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(enabledStr); - while (splitter.hasNext()) { - String curId = splitter.next(); - if (curId.equals(id)) { - if (enabled) { - // We are enabling this input method, but it is - // already enabled. Nothing to do. The previous - // state was enabled. - return true; - } - // We are disabling this input method, and it is - // currently enabled. Skip it to remove from the - // new list. - removed = true; - } else if (!enabled) { - // We are building a new list of input methods that - // doesn't contain the given one. - if (firstId == null) firstId = curId; - if (builder.length() > 0) builder.append(':'); - builder.append(curId); - } - } - } - - if (!enabled) { - if (!removed) { - // We are disabling the input method but it is already - // disabled. Nothing to do. The previous state was - // disabled. - return false; - } - // Update the setting with the new list of input methods. - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); - // We the disabled input method is currently selected, switch - // to another one. - String selId = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); - if (id.equals(selId)) { - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - firstId != null ? firstId : ""); - } - // Previous state was enabled. - return true; - } - - // Add in the newly enabled input method. - if (enabledStr == null || enabledStr.length() == 0) { - enabledStr = id; - } else { - enabledStr = enabledStr + ':' + id; - } - - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, enabledStr); - - // Previous state was disabled. - return false; - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - // ---------------------------------------------------------------------- - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - - pw.println("Permission Denial: can't dump InputMethodManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - IInputMethod method; - ClientState client; - - final Printer p = new PrintWriterPrinter(pw); - - synchronized (mMethodMap) { - p.println("Current Input Method Manager state:"); - int N = mMethodList.size(); - p.println(" Input Methods:"); - for (int i=0; i<N; i++) { - InputMethodInfo info = mMethodList.get(i); - p.println(" InputMethod #" + i + ":"); - info.dump(p, " "); - } - p.println(" Clients:"); - for (ClientState ci : mClients.values()) { - p.println(" Client " + ci + ":"); - p.println(" client=" + ci.client); - p.println(" inputContext=" + ci.inputContext); - p.println(" sessionRequested=" + ci.sessionRequested); - p.println(" curSession=" + ci.curSession); - } - p.println(" mInputMethodIcon=" + mInputMethodIcon); - p.println(" mInputMethodData=" + mInputMethodData); - p.println(" mCurrentMethod=" + mCurMethodId); - 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/Installer.java b/services/java/com/android/server/Installer.java deleted file mode 100644 index fe3ad15..0000000 --- a/services/java/com/android/server/Installer.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 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.pm.PackageStats; -import android.net.LocalSocketAddress; -import android.net.LocalSocket; -import android.util.Config; -import android.util.Log; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - - -class Installer { - private static final String TAG = "Installer"; - InputStream mIn; - OutputStream mOut; - LocalSocket mSocket; - - byte buf[] = new byte[1024]; - int buflen = 0; - - private boolean connect() { - if (mSocket != null) { - return true; - } - Log.i(TAG, "connecting..."); - try { - mSocket = new LocalSocket(); - - LocalSocketAddress address = new LocalSocketAddress( - "installd", LocalSocketAddress.Namespace.RESERVED); - - mSocket.connect(address); - - mIn = mSocket.getInputStream(); - mOut = mSocket.getOutputStream(); - } catch (IOException ex) { - disconnect(); - return false; - } - return true; - } - - private void disconnect() { - Log.i(TAG,"disconnecting..."); - try { - if (mSocket != null) mSocket.close(); - } catch (IOException ex) { } - try { - if (mIn != null) mIn.close(); - } catch (IOException ex) { } - try { - if (mOut != null) mOut.close(); - } catch (IOException ex) { } - mSocket = null; - mIn = null; - mOut = null; - } - - private boolean readBytes(byte buffer[], int len) { - int off = 0, count; - if (len < 0) return false; - while (off != len) { - try { - count = mIn.read(buffer, off, len - off); - if (count <= 0) { - Log.e(TAG, "read error " + count); - break; - } - off += count; - } catch (IOException ex) { - Log.e(TAG,"read exception"); - break; - } - } -// Log.i(TAG, "read "+len+" bytes"); - if (off == len) return true; - disconnect(); - return false; - } - - private boolean readReply() { - int len; - buflen = 0; - if (!readBytes(buf, 2)) return false; - len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); - if ((len < 1) || (len > 1024)) { - Log.e(TAG,"invalid reply length ("+len+")"); - disconnect(); - return false; - } - if (!readBytes(buf, len)) return false; - buflen = len; - return true; - } - - private boolean writeCommand(String _cmd) { - byte[] cmd = _cmd.getBytes(); - int len = cmd.length; - if ((len < 1) || (len > 1024)) return false; - buf[0] = (byte) (len & 0xff); - buf[1] = (byte) ((len >> 8) & 0xff); - try { - mOut.write(buf, 0, 2); - mOut.write(cmd, 0, len); - } catch (IOException ex) { - Log.e(TAG,"write error"); - disconnect(); - return false; - } - return true; - } - - private synchronized String transaction(String cmd) { - if (!connect()) { - Log.e(TAG, "connection failed"); - return "-1"; - } - - if (!writeCommand(cmd)) { - /* If installd died and restarted in the background - * (unlikely but possible) we'll fail on the next - * write (this one). Try to reconnect and write - * the command one more time before giving up. - */ - Log.e(TAG, "write command failed? reconnect!"); - if (!connect() || !writeCommand(cmd)) { - return "-1"; - } - } -// Log.i(TAG,"send: '"+cmd+"'"); - if (readReply()) { - String s = new String(buf, 0, buflen); -// Log.i(TAG,"recv: '"+s+"'"); - return s; - } else { -// Log.i(TAG,"fail"); - return "-1"; - } - } - - private int execute(String cmd) { - String res = transaction(cmd); - try { - return Integer.parseInt(res); - } catch (NumberFormatException ex) { - return -1; - } - } - - public int install(String name, int uid, int gid) { - StringBuilder builder = new StringBuilder("install"); - builder.append(' '); - builder.append(name); - builder.append(' '); - builder.append(uid); - builder.append(' '); - builder.append(gid); - return execute(builder.toString()); - } - - public int dexopt(String apkPath, int uid, boolean isPublic) { - StringBuilder builder = new StringBuilder("dexopt"); - builder.append(' '); - builder.append(apkPath); - builder.append(' '); - builder.append(uid); - builder.append(isPublic ? " 1" : " 0"); - return execute(builder.toString()); - } - - public int movedex(String srcPath, String dstPath) { - StringBuilder builder = new StringBuilder("movedex"); - builder.append(' '); - builder.append(srcPath); - builder.append(' '); - builder.append(dstPath); - return execute(builder.toString()); - } - - public int rmdex(String codePath) { - StringBuilder builder = new StringBuilder("rmdex"); - builder.append(' '); - builder.append(codePath); - return execute(builder.toString()); - } - - public int remove(String name) { - StringBuilder builder = new StringBuilder("remove"); - builder.append(' '); - builder.append(name); - return execute(builder.toString()); - } - - public int deleteCacheFiles(String name) { - StringBuilder builder = new StringBuilder("rmcache"); - builder.append(' '); - builder.append(name); - return execute(builder.toString()); - } - - public int clearUserData(String name) { - StringBuilder builder = new StringBuilder("rmuserdata"); - builder.append(' '); - builder.append(name); - return execute(builder.toString()); - } - - public boolean ping() { - if (execute("ping") < 0) { - return false; - } else { - return true; - } - } - - public int freeCache(long freeStorageSize) { - StringBuilder builder = new StringBuilder("freecache"); - builder.append(' '); - builder.append(String.valueOf(freeStorageSize)); - return execute(builder.toString()); - } - - public int setForwardLockPerm(String packageName, int gid) { - StringBuilder builder = new StringBuilder("protect"); - builder.append(' '); - builder.append(packageName); - builder.append(' '); - builder.append(gid); - return execute(builder.toString()); - } - - public int getSizeInfo(String pkgName, String apkPath, - String fwdLockApkPath, PackageStats pStats) { - StringBuilder builder = new StringBuilder("getsize"); - builder.append(' '); - builder.append(pkgName); - builder.append(' '); - builder.append(apkPath); - builder.append(' '); - builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); - - String s = transaction(builder.toString()); - String res[] = s.split(" "); - - if((res == null) || (res.length != 4)) { - return -1; - } - try { - pStats.codeSize = Long.parseLong(res[1]); - pStats.dataSize = Long.parseLong(res[2]); - pStats.cacheSize = Long.parseLong(res[3]); - return Integer.parseInt(res[0]); - } catch (NumberFormatException e) { - return -1; - } - } -} diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java deleted file mode 100644 index b534ef1..0000000 --- a/services/java/com/android/server/IntentResolver.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (C) 2006 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 java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import android.util.Log; -import android.util.LogPrinter; -import android.util.Printer; - -import android.util.Config; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.IntentFilter; - -/** - * {@hide} - */ -public class IntentResolver<F extends IntentFilter, R extends Object> { - final private static String TAG = "IntentResolver"; - final private static boolean DEBUG = false; - final private static boolean localLOGV = DEBUG || Config.LOGV; - - public void addFilter(F f) { - if (localLOGV) { - Log.v(TAG, "Adding filter: " + f); - f.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - Log.v(TAG, " Building Lookup Maps:"); - } - - mFilters.add(f); - int numS = register_intent_filter(f, f.schemesIterator(), - mSchemeToFilter, " Scheme: "); - int numT = register_mime_types(f, " Type: "); - if (numS == 0 && numT == 0) { - register_intent_filter(f, f.actionsIterator(), - mActionToFilter, " Action: "); - } - if (numT != 0) { - register_intent_filter(f, f.actionsIterator(), - mTypedActionToFilter, " TypedAction: "); - } - } - - public void removeFilter(F f) { - removeFilterInternal(f); - mFilters.remove(f); - } - - void removeFilterInternal(F f) { - if (localLOGV) { - Log.v(TAG, "Removing filter: " + f); - f.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - Log.v(TAG, " Cleaning Lookup Maps:"); - } - - int numS = unregister_intent_filter(f, f.schemesIterator(), - mSchemeToFilter, " Scheme: "); - int numT = unregister_mime_types(f, " Type: "); - if (numS == 0 && numT == 0) { - unregister_intent_filter(f, f.actionsIterator(), - mActionToFilter, " Action: "); - } - if (numT != 0) { - unregister_intent_filter(f, f.actionsIterator(), - mTypedActionToFilter, " TypedAction: "); - } - } - - void dumpMap(Printer out, String prefix, Map<String, ArrayList<F>> map) { - String eprefix = prefix + " "; - String fprefix = prefix + " "; - for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) { - out.println(eprefix + e.getKey() + ":"); - ArrayList<F> a = e.getValue(); - final int N = a.size(); - for (int i=0; i<N; i++) { - dumpFilter(out, fprefix, a.get(i)); - } - } - } - - public void dump(Printer out, String prefix) { - out.println(prefix + "Full MIME Types:"); - dumpMap(out, prefix+" ", mTypeToFilter); - out.println(prefix); - out.println(prefix + "Base MIME Types:"); - dumpMap(out, prefix+" ", mBaseTypeToFilter); - out.println(prefix); - out.println(prefix + "Wild MIME Types:"); - dumpMap(out, prefix+" ", mWildTypeToFilter); - out.println(prefix); - out.println(prefix + "Schemes:"); - dumpMap(out, prefix+" ", mSchemeToFilter); - out.println(prefix); - out.println(prefix + "Non-Data Actions:"); - dumpMap(out, prefix+" ", mActionToFilter); - out.println(prefix); - out.println(prefix + "MIME Typed Actions:"); - dumpMap(out, prefix+" ", mTypedActionToFilter); - } - - private class IteratorWrapper implements Iterator<F> { - private final Iterator<F> mI; - private F mCur; - - IteratorWrapper(Iterator<F> it) { - mI = it; - } - - public boolean hasNext() { - return mI.hasNext(); - } - - public F next() { - return (mCur = mI.next()); - } - - public void remove() { - if (mCur != null) { - removeFilterInternal(mCur); - } - mI.remove(); - } - - } - - /** - * Returns an iterator allowing filters to be removed. - */ - public Iterator<F> filterIterator() { - return new IteratorWrapper(mFilters.iterator()); - } - - /** - * Returns a read-only set of the filters. - */ - public Set<F> filterSet() { - return Collections.unmodifiableSet(mFilters); - } - - public List<R> queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { - String scheme = intent.getScheme(); - - ArrayList<R> finalList = new ArrayList<R>(); - - final boolean debug = localLOGV || - ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); - - if (debug) Log.v( - TAG, "Resolving type " + resolvedType + " scheme " + scheme - + " of intent " + intent); - - ArrayList<F> firstTypeCut = null; - ArrayList<F> secondTypeCut = null; - ArrayList<F> thirdTypeCut = null; - ArrayList<F> schemeCut = null; - - // If the intent includes a MIME type, then we want to collect all of - // the filters that match that MIME type. - if (resolvedType != null) { - int slashpos = resolvedType.indexOf('/'); - if (slashpos > 0) { - final String baseType = resolvedType.substring(0, slashpos); - if (!baseType.equals("*")) { - if (resolvedType.length() != slashpos+2 - || resolvedType.charAt(slashpos+1) != '*') { - // Not a wild card, so we can just look for all filters that - // completely match or wildcards whose base type matches. - firstTypeCut = mTypeToFilter.get(resolvedType); - if (debug) Log.v(TAG, "First type cut: " + firstTypeCut); - secondTypeCut = mWildTypeToFilter.get(baseType); - if (debug) Log.v(TAG, "Second type cut: " + secondTypeCut); - } else { - // We can match anything with our base type. - firstTypeCut = mBaseTypeToFilter.get(baseType); - if (debug) Log.v(TAG, "First type cut: " + firstTypeCut); - secondTypeCut = mWildTypeToFilter.get(baseType); - if (debug) Log.v(TAG, "Second type cut: " + secondTypeCut); - } - // Any */* types always apply, but we only need to do this - // if the intent type was not already */*. - thirdTypeCut = mWildTypeToFilter.get("*"); - if (debug) Log.v(TAG, "Third type cut: " + thirdTypeCut); - } else if (intent.getAction() != null) { - // The intent specified any type ({@literal *}/*). This - // can be a whole heck of a lot of things, so as a first - // cut let's use the action instead. - firstTypeCut = mTypedActionToFilter.get(intent.getAction()); - if (debug) Log.v(TAG, "Typed Action list: " + firstTypeCut); - } - } - } - - // If the intent includes a data URI, then we want to collect all of - // the filters that match its scheme (we will further refine matches - // on the authority and path by directly matching each resulting filter). - if (scheme != null) { - schemeCut = mSchemeToFilter.get(scheme); - if (debug) Log.v(TAG, "Scheme list: " + schemeCut); - } - - // If the intent does not specify any data -- either a MIME type or - // a URI -- then we will only be looking for matches against empty - // data. - if (resolvedType == null && scheme == null && intent.getAction() != null) { - firstTypeCut = mActionToFilter.get(intent.getAction()); - if (debug) Log.v(TAG, "Action list: " + firstTypeCut); - } - - if (firstTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, - resolvedType, scheme, firstTypeCut, finalList); - } - if (secondTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, - resolvedType, scheme, secondTypeCut, finalList); - } - if (thirdTypeCut != null) { - buildResolveList(intent, debug, defaultOnly, - resolvedType, scheme, thirdTypeCut, finalList); - } - if (schemeCut != null) { - buildResolveList(intent, debug, defaultOnly, - resolvedType, scheme, schemeCut, finalList); - } - sortResults(finalList); - - if (debug) { - Log.v(TAG, "Final result list:"); - for (R r : finalList) { - Log.v(TAG, " " + r); - } - } - return finalList; - } - - /** - * Control whether the given filter is allowed to go into the result - * list. Mainly intended to prevent adding multiple filters for the - * same target object. - */ - protected boolean allowFilterResult(F filter, List<R> dest) { - return true; - } - - protected R newResult(F filter, int match) { - return (R)filter; - } - - protected void sortResults(List<R> results) { - Collections.sort(results, mResolvePrioritySorter); - } - - protected void dumpFilter(Printer out, String prefix, F filter) { - out.println(prefix + filter); - } - - private final int register_mime_types(F filter, String prefix) { - final Iterator<String> i = filter.typesIterator(); - if (i == null) { - return 0; - } - - int num = 0; - while (i.hasNext()) { - String name = (String)i.next(); - num++; - if (localLOGV) Log.v(TAG, prefix + name); - String baseName = name; - final int slashpos = name.indexOf('/'); - if (slashpos > 0) { - baseName = name.substring(0, slashpos).intern(); - } else { - name = name + "/*"; - } - - ArrayList<F> array = mTypeToFilter.get(name); - if (array == null) { - //Log.v(TAG, "Creating new array for " + name); - array = new ArrayList<F>(); - mTypeToFilter.put(name, array); - } - array.add(filter); - - if (slashpos > 0) { - array = mBaseTypeToFilter.get(baseName); - if (array == null) { - //Log.v(TAG, "Creating new array for " + name); - array = new ArrayList<F>(); - mBaseTypeToFilter.put(baseName, array); - } - array.add(filter); - } else { - array = mWildTypeToFilter.get(baseName); - if (array == null) { - //Log.v(TAG, "Creating new array for " + name); - array = new ArrayList<F>(); - mWildTypeToFilter.put(baseName, array); - } - array.add(filter); - } - } - - return num; - } - - private final int unregister_mime_types(F filter, String prefix) { - final Iterator<String> i = filter.typesIterator(); - if (i == null) { - return 0; - } - - int num = 0; - while (i.hasNext()) { - String name = (String)i.next(); - num++; - if (localLOGV) Log.v(TAG, prefix + name); - String baseName = name; - final int slashpos = name.indexOf('/'); - if (slashpos > 0) { - baseName = name.substring(0, slashpos).intern(); - } else { - name = name + "/*"; - } - - if (!remove_all_objects(mTypeToFilter.get(name), filter)) { - mTypeToFilter.remove(name); - } - - if (slashpos > 0) { - if (!remove_all_objects(mBaseTypeToFilter.get(baseName), filter)) { - mBaseTypeToFilter.remove(baseName); - } - } else { - if (!remove_all_objects(mWildTypeToFilter.get(baseName), filter)) { - mWildTypeToFilter.remove(baseName); - } - } - } - return num; - } - - private final int register_intent_filter(F filter, Iterator<String> i, - HashMap<String, ArrayList<F>> dest, String prefix) { - if (i == null) { - return 0; - } - - int num = 0; - while (i.hasNext()) { - String name = i.next(); - num++; - if (localLOGV) Log.v(TAG, prefix + name); - ArrayList<F> array = dest.get(name); - if (array == null) { - //Log.v(TAG, "Creating new array for " + name); - array = new ArrayList<F>(); - dest.put(name, array); - } - array.add(filter); - } - return num; - } - - private final int unregister_intent_filter(F filter, Iterator<String> i, - HashMap<String, ArrayList<F>> dest, String prefix) { - if (i == null) { - return 0; - } - - int num = 0; - while (i.hasNext()) { - String name = i.next(); - num++; - if (localLOGV) Log.v(TAG, prefix + name); - if (!remove_all_objects(dest.get(name), filter)) { - dest.remove(name); - } - } - return num; - } - - private final boolean remove_all_objects(List<F> list, Object object) { - if (list != null) { - int N = list.size(); - for (int idx=0; idx<N; idx++) { - if (list.get(idx) == object) { - list.remove(idx); - idx--; - N--; - } - } - return N > 0; - } - return false; - } - - private void buildResolveList(Intent intent, boolean debug, boolean defaultOnly, - String resolvedType, String scheme, List<F> src, List<R> dest) { - Set<String> categories = intent.getCategories(); - - final int N = src != null ? src.size() : 0; - boolean hasNonDefaults = false; - int i; - for (i=0; i<N; i++) { - F filter = src.get(i); - int match; - if (debug) Log.v(TAG, "Matching against filter " + filter); - - // Do we already have this one? - if (!allowFilterResult(filter, dest)) { - if (debug) { - Log.v(TAG, " Filter's target already added"); - } - continue; - } - - match = filter.match( - intent.getAction(), resolvedType, scheme, intent.getData(), categories, TAG); - if (match >= 0) { - if (debug) Log.v(TAG, " Filter matched! match=0x" + - Integer.toHexString(match)); - if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) { - final R oneResult = newResult(filter, match); - if (oneResult != null) { - dest.add(oneResult); - } - } else { - hasNonDefaults = true; - } - } else { - if (debug) { - String reason; - switch (match) { - case IntentFilter.NO_MATCH_ACTION: reason = "action"; break; - case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break; - case IntentFilter.NO_MATCH_DATA: reason = "data"; break; - case IntentFilter.NO_MATCH_TYPE: reason = "type"; break; - default: reason = "unknown reason"; break; - } - Log.v(TAG, " Filter did not match: " + reason); - } - } - } - - if (dest.size() == 0 && hasNonDefaults) { - Log.w(TAG, "resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT"); - } - } - - // Sorts a List of IntentFilter objects into descending priority order. - private static final Comparator mResolvePrioritySorter = new Comparator() { - public int compare(Object o1, Object o2) { - float q1 = ((IntentFilter)o1).getPriority(); - float q2 = ((IntentFilter)o2).getPriority(); - return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0); - } - }; - - /** - * All filters that have been registered. - */ - private final HashSet<F> mFilters = new HashSet<F>(); - - /** - * All of the MIME types that have been registered, such as "image/jpeg", - * "image/*", or "{@literal *}/*". - */ - private final HashMap<String, ArrayList<F>> mTypeToFilter - = new HashMap<String, ArrayList<F>>(); - - /** - * The base names of all of all fully qualified MIME types that have been - * registered, such as "image" or "*". Wild card MIME types such as - * "image/*" will not be here. - */ - private final HashMap<String, ArrayList<F>> mBaseTypeToFilter - = new HashMap<String, ArrayList<F>>(); - - /** - * The base names of all of the MIME types with a sub-type wildcard that - * have been registered. For example, a filter with "image/*" will be - * included here as "image" but one with "image/jpeg" will not be - * included here. This also includes the "*" for the "{@literal *}/*" - * MIME type. - */ - private final HashMap<String, ArrayList<F>> mWildTypeToFilter - = new HashMap<String, ArrayList<F>>(); - - /** - * All of the URI schemes (such as http) that have been registered. - */ - private final HashMap<String, ArrayList<F>> mSchemeToFilter - = new HashMap<String, ArrayList<F>>(); - - /** - * All of the actions that have been registered, but only those that did - * not specify data. - */ - private final HashMap<String, ArrayList<F>> mActionToFilter - = new HashMap<String, ArrayList<F>>(); - - /** - * All of the actions that have been registered and specified a MIME type. - */ - private final HashMap<String, ArrayList<F>> mTypedActionToFilter - = new HashMap<String, ArrayList<F>>(); -} - diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java deleted file mode 100644 index 63b486c..0000000 --- a/services/java/com/android/server/KeyInputQueue.java +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Copyright (C) 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; - -import android.content.Context; -import android.content.res.Configuration; -import android.os.SystemClock; -import android.os.PowerManager; -import android.util.Log; -import android.util.SparseArray; -import android.view.Display; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.RawInputEvent; -import android.view.Surface; -import android.view.WindowManagerPolicy; - -public abstract class KeyInputQueue { - static final String TAG = "KeyInputQueue"; - - SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); - - int mGlobalMetaState = 0; - boolean mHaveGlobalMetaState = false; - - final QueuedEvent mFirst; - final QueuedEvent mLast; - QueuedEvent mCache; - int mCacheCount; - - Display mDisplay = null; - - int mOrientation = Surface.ROTATION_0; - int[] mKeyRotationMap = null; - - PowerManager.WakeLock mWakeLock; - - static final int[] KEY_90_MAP = new int[] { - KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT, - KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP, - KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT, - KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN, - }; - - static final int[] KEY_180_MAP = new int[] { - KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP, - KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT, - KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, - KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, - }; - - static final int[] KEY_270_MAP = new int[] { - KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT, - KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP, - KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT, - KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN, - }; - - public static final int FILTER_REMOVE = 0; - public static final int FILTER_KEEP = 1; - public static final int FILTER_ABORT = -1; - - public interface FilterCallback { - int filterEvent(QueuedEvent ev); - } - - static class QueuedEvent { - InputDevice inputDevice; - long when; - int flags; // From the raw event - int classType; // One of the class constants in InputEvent - Object event; - boolean inQueue; - - void copyFrom(QueuedEvent that) { - this.inputDevice = that.inputDevice; - this.when = that.when; - this.flags = that.flags; - this.classType = that.classType; - this.event = that.event; - } - - @Override - public String toString() { - return "QueuedEvent{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + event + "}"; - } - - // not copied - QueuedEvent prev; - QueuedEvent next; - } - - KeyInputQueue(Context context) { - PowerManager pm = (PowerManager)context.getSystemService( - Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, - "KeyInputQueue"); - mWakeLock.setReferenceCounted(false); - - mFirst = new QueuedEvent(); - mLast = new QueuedEvent(); - mFirst.next = mLast; - mLast.prev = mFirst; - - mThread.start(); - } - - public void setDisplay(Display display) { - mDisplay = display; - } - - public void getInputConfiguration(Configuration config) { - synchronized (mFirst) { - config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; - config.keyboard = Configuration.KEYBOARD_NOKEYS; - config.navigation = Configuration.NAVIGATION_NONAV; - - final int N = mDevices.size(); - for (int i=0; i<N; i++) { - InputDevice d = mDevices.valueAt(i); - if (d != null) { - if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { - config.touchscreen - = Configuration.TOUCHSCREEN_FINGER; - //Log.i("foo", "***** HAVE TOUCHSCREEN!"); - } - if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) { - config.keyboard - = Configuration.KEYBOARD_QWERTY; - //Log.i("foo", "***** HAVE QWERTY!"); - } - if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) { - config.navigation - = Configuration.NAVIGATION_TRACKBALL; - //Log.i("foo", "***** HAVE TRACKBALL!"); - } - } - } - } - } - - public static native String getDeviceName(int deviceId); - public static native int getDeviceClasses(int deviceId); - public static native boolean getAbsoluteInfo(int deviceId, int axis, - InputDevice.AbsoluteInfo outInfo); - public static native int getSwitchState(int sw); - public static native int getSwitchState(int deviceId, int sw); - public static native int getScancodeState(int sw); - 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, - int scancode, int flags) { - return new KeyEvent( - downTime, eventTime, - down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, - keycode, repeatCount, - device != null ? device.mMetaKeysState : 0, - device != null ? device.id : -1, scancode, - flags); - } - - Thread mThread = new Thread("InputDeviceReader") { - public void run() { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); - - try { - RawInputEvent ev = new RawInputEvent(); - while (true) { - InputDevice di; - - // block, doesn't release the monitor - readEvent(ev); - - boolean send = false; - boolean configChanged = false; - - if (false) { - Log.i(TAG, "Input event: dev=0x" - + Integer.toHexString(ev.deviceId) - + " type=0x" + Integer.toHexString(ev.type) - + " scancode=" + ev.scancode - + " keycode=" + ev.keycode - + " value=" + ev.value); - } - - if (ev.type == RawInputEvent.EV_DEVICE_ADDED) { - synchronized (mFirst) { - di = newInputDevice(ev.deviceId); - mDevices.put(ev.deviceId, di); - configChanged = true; - } - } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) { - synchronized (mFirst) { - Log.i(TAG, "Device removed: id=0x" - + Integer.toHexString(ev.deviceId)); - di = mDevices.get(ev.deviceId); - if (di != null) { - mDevices.delete(ev.deviceId); - configChanged = true; - } else { - Log.w(TAG, "Bad device id: " + ev.deviceId); - } - } - } else { - di = getInputDevice(ev.deviceId); - - // first crack at it - send = preprocessEvent(di, ev); - - if (ev.type == RawInputEvent.EV_KEY) { - di.mMetaKeysState = makeMetaState(ev.keycode, - ev.value != 0, di.mMetaKeysState); - mHaveGlobalMetaState = false; - } - } - - if (di == null) { - continue; - } - - if (configChanged) { - synchronized (mFirst) { - addLocked(di, SystemClock.uptimeMillis(), 0, - RawInputEvent.CLASS_CONFIGURATION_CHANGED, - null); - } - } - - if (!send) { - continue; - } - - synchronized (mFirst) { - // NOTE: The event timebase absolutely must be the same - // timebase as SystemClock.uptimeMillis(). - //curTime = gotOne ? ev.when : SystemClock.uptimeMillis(); - final long curTime = SystemClock.uptimeMillis(); - //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis()); - - final int classes = di.classes; - final int type = ev.type; - final int scancode = ev.scancode; - send = false; - - // Is it a key event? - if (type == RawInputEvent.EV_KEY && - (classes&RawInputEvent.CLASS_KEYBOARD) != 0 && - (scancode < RawInputEvent.BTN_FIRST || - scancode > RawInputEvent.BTN_LAST)) { - boolean down; - if (ev.value != 0) { - down = true; - di.mDownTime = curTime; - } else { - down = false; - } - int keycode = rotateKeyCodeLocked(ev.keycode); - addLocked(di, curTime, ev.flags, - RawInputEvent.CLASS_KEYBOARD, - newKeyEvent(di, di.mDownTime, curTime, down, - keycode, 0, scancode, - ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0) - ? KeyEvent.FLAG_WOKE_HERE : 0)); - } else if (ev.type == RawInputEvent.EV_KEY) { - if (ev.scancode == RawInputEvent.BTN_TOUCH && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { - di.mAbs.changed = true; - di.mAbs.down = ev.value != 0; - } - if (ev.scancode == RawInputEvent.BTN_MOUSE && - (classes&RawInputEvent.CLASS_TRACKBALL) != 0) { - di.mRel.changed = true; - di.mRel.down = ev.value != 0; - send = true; - } - - } else if (ev.type == RawInputEvent.EV_ABS && - (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { - if (ev.scancode == RawInputEvent.ABS_X) { - di.mAbs.changed = true; - di.mAbs.x = ev.value; - } else if (ev.scancode == RawInputEvent.ABS_Y) { - di.mAbs.changed = true; - di.mAbs.y = ev.value; - } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) { - di.mAbs.changed = true; - di.mAbs.pressure = ev.value; - } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) { - di.mAbs.changed = true; - di.mAbs.size = ev.value; - } - - } else if (ev.type == RawInputEvent.EV_REL && - (classes&RawInputEvent.CLASS_TRACKBALL) != 0) { - // Add this relative movement into our totals. - if (ev.scancode == RawInputEvent.REL_X) { - di.mRel.changed = true; - di.mRel.x += ev.value; - } else if (ev.scancode == RawInputEvent.REL_Y) { - di.mRel.changed = true; - di.mRel.y += ev.value; - } - } - - if (send || ev.type == RawInputEvent.EV_SYN) { - if (mDisplay != null) { - if (!mHaveGlobalMetaState) { - computeGlobalMetaStateLocked(); - } - - MotionEvent me; - me = di.mAbs.generateMotion(di, curTime, true, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x - + " y=" + di.mAbs.y + " ev=" + me); - if (me != null) { - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i(TAG, "Enqueueing: " + me); - } - addLocked(di, curTime, ev.flags, - RawInputEvent.CLASS_TOUCHSCREEN, me); - } - me = di.mRel.generateMotion(di, curTime, false, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Relative: x=" + di.mRel.x - + " y=" + di.mRel.y + " ev=" + me); - if (me != null) { - addLocked(di, curTime, ev.flags, - RawInputEvent.CLASS_TRACKBALL, me); - } - } - } - } - } - } - catch (RuntimeException exc) { - Log.e(TAG, "InputReaderThread uncaught exception", exc); - } - } - }; - - /** - * Returns a new meta state for the given keys and old state. - */ - private static final int makeMetaState(int keycode, boolean down, int old) { - int mask; - switch (keycode) { - case KeyEvent.KEYCODE_ALT_LEFT: - mask = KeyEvent.META_ALT_LEFT_ON; - break; - case KeyEvent.KEYCODE_ALT_RIGHT: - mask = KeyEvent.META_ALT_RIGHT_ON; - break; - case KeyEvent.KEYCODE_SHIFT_LEFT: - mask = KeyEvent.META_SHIFT_LEFT_ON; - break; - case KeyEvent.KEYCODE_SHIFT_RIGHT: - mask = KeyEvent.META_SHIFT_RIGHT_ON; - break; - case KeyEvent.KEYCODE_SYM: - mask = KeyEvent.META_SYM_ON; - break; - default: - return old; - } - int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON) - & (down ? (old | mask) : (old & ~mask)); - if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) { - result |= KeyEvent.META_ALT_ON; - } - if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) { - result |= KeyEvent.META_SHIFT_ON; - } - return result; - } - - private void computeGlobalMetaStateLocked() { - int i = mDevices.size(); - mGlobalMetaState = 0; - while ((--i) >= 0) { - mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState; - } - mHaveGlobalMetaState = true; - } - - /* - * Return true if you want the event to get passed on to the - * rest of the system, and false if you've handled it and want - * it dropped. - */ - abstract boolean preprocessEvent(InputDevice device, RawInputEvent event); - - InputDevice getInputDevice(int deviceId) { - synchronized (mFirst) { - return getInputDeviceLocked(deviceId); - } - } - - private InputDevice getInputDeviceLocked(int deviceId) { - return mDevices.get(deviceId); - } - - public void setOrientation(int orientation) { - synchronized(mFirst) { - mOrientation = orientation; - switch (orientation) { - case Surface.ROTATION_90: - mKeyRotationMap = KEY_90_MAP; - break; - case Surface.ROTATION_180: - mKeyRotationMap = KEY_180_MAP; - break; - case Surface.ROTATION_270: - mKeyRotationMap = KEY_270_MAP; - break; - default: - mKeyRotationMap = null; - break; - } - } - } - - public int rotateKeyCode(int keyCode) { - synchronized(mFirst) { - return rotateKeyCodeLocked(keyCode); - } - } - - private int rotateKeyCodeLocked(int keyCode) { - int[] map = mKeyRotationMap; - if (map != null) { - final int N = map.length; - for (int i=0; i<N; i+=2) { - if (map[i] == keyCode) { - return map[i+1]; - } - } - } - return keyCode; - } - - boolean hasEvents() { - synchronized (mFirst) { - return mFirst.next != mLast; - } - } - - /* - * returns true if we returned an event, and false if we timed out - */ - QueuedEvent getEvent(long timeoutMS) { - long begin = SystemClock.uptimeMillis(); - final long end = begin+timeoutMS; - long now = begin; - synchronized (mFirst) { - while (mFirst.next == mLast && end > now) { - try { - mWakeLock.release(); - mFirst.wait(end-now); - } - catch (InterruptedException e) { - } - now = SystemClock.uptimeMillis(); - if (begin > now) { - begin = now; - } - } - if (mFirst.next == mLast) { - return null; - } - QueuedEvent p = mFirst.next; - mFirst.next = p.next; - mFirst.next.prev = mFirst; - p.inQueue = false; - return p; - } - } - - void recycleEvent(QueuedEvent ev) { - synchronized (mFirst) { - //Log.i(TAG, "Recycle event: " + ev); - if (ev.event == ev.inputDevice.mAbs.currentMove) { - ev.inputDevice.mAbs.currentMove = null; - } - if (ev.event == ev.inputDevice.mRel.currentMove) { - if (false) Log.i(TAG, "Detach rel " + ev.event); - ev.inputDevice.mRel.currentMove = null; - ev.inputDevice.mRel.x = 0; - ev.inputDevice.mRel.y = 0; - } - recycleLocked(ev); - } - } - - void filterQueue(FilterCallback cb) { - synchronized (mFirst) { - QueuedEvent cur = mLast.prev; - while (cur.prev != null) { - switch (cb.filterEvent(cur)) { - case FILTER_REMOVE: - cur.prev.next = cur.next; - cur.next.prev = cur.prev; - break; - case FILTER_ABORT: - return; - } - cur = cur.prev; - } - } - } - - private QueuedEvent obtainLocked(InputDevice device, long when, - int flags, int classType, Object event) { - QueuedEvent ev; - if (mCacheCount == 0) { - ev = new QueuedEvent(); - } else { - ev = mCache; - ev.inQueue = false; - mCache = ev.next; - mCacheCount--; - } - ev.inputDevice = device; - ev.when = when; - ev.flags = flags; - ev.classType = classType; - ev.event = event; - return ev; - } - - private void recycleLocked(QueuedEvent ev) { - if (ev.inQueue) { - throw new RuntimeException("Event already in queue!"); - } - if (mCacheCount < 10) { - mCacheCount++; - ev.next = mCache; - mCache = ev; - ev.inQueue = true; - } - } - - private void addLocked(InputDevice device, long when, int flags, - int classType, Object event) { - boolean poke = mFirst.next == mLast; - - QueuedEvent ev = obtainLocked(device, when, flags, classType, event); - QueuedEvent p = mLast.prev; - while (p != mFirst && ev.when < p.when) { - p = p.prev; - } - - ev.next = p.next; - ev.prev = p; - p.next = ev; - ev.next.prev = ev; - ev.inQueue = true; - - if (poke) { - mFirst.notify(); - mWakeLock.acquire(); - } - } - - private InputDevice newInputDevice(int deviceId) { - int classes = getDeviceClasses(deviceId); - String name = getDeviceName(deviceId); - Log.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId) - + ", name=" + name - + ", classes=" + Integer.toHexString(classes)); - InputDevice.AbsoluteInfo absX; - InputDevice.AbsoluteInfo absY; - InputDevice.AbsoluteInfo absPressure; - InputDevice.AbsoluteInfo absSize; - if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { - absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X"); - absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y"); - absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure"); - absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size"); - } else { - absX = null; - absY = null; - absPressure = null; - absSize = null; - } - - return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize); - } - - private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel, - String name) { - InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo(); - if (getAbsoluteInfo(id, channel, info) - && info.minValue != info.maxValue) { - Log.i(TAG, " " + name + ": min=" + info.minValue - + " max=" + info.maxValue - + " flat=" + info.flat - + " fuzz=" + info.fuzz); - info.range = info.maxValue-info.minValue; - return info; - } - Log.i(TAG, " " + name + ": unknown values"); - return null; - } - private static native boolean readEvent(RawInputEvent outEvent); -} diff --git a/services/java/com/android/server/LoadAverageService.java b/services/java/com/android/server/LoadAverageService.java deleted file mode 100644 index 0d86429..0000000 --- a/services/java/com/android/server/LoadAverageService.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 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; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.view.Gravity; -import android.view.View; -import android.view.WindowManager; -import android.view.WindowManagerImpl; - -public class LoadAverageService extends Service { - private View mView; - - private static final class Stats extends ProcessStats { - String mLoadText; - int mLoadWidth; - - private final Paint mPaint; - - Stats(Paint paint) { - super(false); - mPaint = paint; - } - - @Override - public void onLoadChanged(float load1, float load5, float load15) { - mLoadText = load1 + " / " + load5 + " / " + load15; - mLoadWidth = (int)mPaint.measureText(mLoadText); - } - - @Override - public int onMeasureProcessName(String name) { - return (int)mPaint.measureText(name); - } - } - - private class LoadView extends View { - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == 1) { - mStats.update(); - updateDisplay(); - Message m = obtainMessage(1); - sendMessageDelayed(m, 2000); - } - } - }; - - private final Stats mStats; - - private Paint mLoadPaint; - private Paint mAddedPaint; - private Paint mRemovedPaint; - private Paint mShadowPaint; - private Paint mShadow2Paint; - private Paint mIrqPaint; - private Paint mSystemPaint; - private Paint mUserPaint; - private float mAscent; - private int mFH; - - private int mNeededWidth; - private int mNeededHeight; - - LoadView(Context c) { - super(c); - - setPadding(4, 4, 4, 4); - //setBackgroundResource(com.android.internal.R.drawable.load_average_background); - - mLoadPaint = new Paint(); - mLoadPaint.setAntiAlias(true); - mLoadPaint.setTextSize(10); - mLoadPaint.setARGB(255, 255, 255, 255); - - mAddedPaint = new Paint(); - mAddedPaint.setAntiAlias(true); - mAddedPaint.setTextSize(10); - mAddedPaint.setARGB(255, 128, 255, 128); - - mRemovedPaint = new Paint(); - mRemovedPaint.setAntiAlias(true); - mRemovedPaint.setStrikeThruText(true); - mRemovedPaint.setTextSize(10); - mRemovedPaint.setARGB(255, 255, 128, 128); - - mShadowPaint = new Paint(); - mShadowPaint.setAntiAlias(true); - mShadowPaint.setTextSize(10); - //mShadowPaint.setFakeBoldText(true); - mShadowPaint.setARGB(192, 0, 0, 0); - mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000); - - mShadow2Paint = new Paint(); - mShadow2Paint.setAntiAlias(true); - mShadow2Paint.setTextSize(10); - //mShadow2Paint.setFakeBoldText(true); - mShadow2Paint.setARGB(192, 0, 0, 0); - mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000); - - mIrqPaint = new Paint(); - mIrqPaint.setARGB(0x80, 0, 0, 0xff); - mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000); - mSystemPaint = new Paint(); - mSystemPaint.setARGB(0x80, 0xff, 0, 0); - mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); - mUserPaint = new Paint(); - mUserPaint.setARGB(0x80, 0, 0xff, 0); - mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); - - mAscent = mLoadPaint.ascent(); - float descent = mLoadPaint.descent(); - mFH = (int)(descent - mAscent + .5f); - - mStats = new Stats(mLoadPaint); - mStats.init(); - updateDisplay(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mHandler.sendEmptyMessage(1); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mHandler.removeMessages(1); - } - - @Override - protected void onMeasure(int widthMeasureSpect, int heightMeasureSpec) { - setMeasuredDimension(mNeededWidth, mNeededHeight); - } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - final int W = getWidth(); - - final Stats stats = mStats; - final int userTime = stats.getLastUserTime(); - final int systemTime = stats.getLastSystemTime(); - final int iowaitTime = stats.getLastIoWaitTime(); - final int irqTime = stats.getLastIrqTime(); - final int softIrqTime = stats.getLastSoftIrqTime(); - final int idleTime = stats.getLastIdleTime(); - - final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime; - if (totalTime == 0) { - return; - } - int userW = (userTime*W)/totalTime; - int systemW = (systemTime*W)/totalTime; - int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime; - - int x = W - mPaddingRight; - int top = mPaddingTop + 2; - int bottom = mPaddingTop + mFH - 2; - - if (irqW > 0) { - canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint); - x -= irqW; - } - if (systemW > 0) { - canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); - x -= systemW; - } - if (userW > 0) { - canvas.drawRect(x-userW, top, x, bottom, mUserPaint); - x -= userW; - } - - int y = mPaddingTop - (int)mAscent; - canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1, - y-1, mShadowPaint); - canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1, - y+1, mShadowPaint); - canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1, - y-1, mShadow2Paint); - canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1, - y+1, mShadow2Paint); - canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth, - y, mLoadPaint); - - int N = stats.countWorkingStats(); - for (int i=0; i<N; i++) { - Stats.Stats st = stats.getWorkingStats(i); - y += mFH; - top += mFH; - bottom += mFH; - - userW = (st.rel_utime*W)/totalTime; - systemW = (st.rel_stime*W)/totalTime; - x = W - mPaddingRight; - if (systemW > 0) { - canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); - x -= systemW; - } - if (userW > 0) { - canvas.drawRect(x-userW, top, x, bottom, mUserPaint); - x -= userW; - } - - canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1, - y-1, mShadowPaint); - canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1, - y+1, mShadowPaint); - canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1, - y-1, mShadow2Paint); - canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1, - y+1, mShadow2Paint); - Paint p = mLoadPaint; - if (st.added) p = mAddedPaint; - if (st.removed) p = mRemovedPaint; - canvas.drawText(st.name, W-mPaddingRight-st.nameWidth, y, p); - } - } - - void updateDisplay() { - final Stats stats = mStats; - final int NW = stats.countWorkingStats(); - - int maxWidth = stats.mLoadWidth; - for (int i=0; i<NW; i++) { - Stats.Stats st = stats.getWorkingStats(i); - if (st.nameWidth > maxWidth) { - maxWidth = st.nameWidth; - } - } - - int neededWidth = mPaddingLeft + mPaddingRight + maxWidth; - int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW)); - if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) { - mNeededWidth = neededWidth; - mNeededHeight = neededHeight; - requestLayout(); - } else { - invalidate(); - } - } - } - - @Override - public void onCreate() { - super.onCreate(); - mView = new LoadView(this); - WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, - PixelFormat.TRANSLUCENT); - params.gravity = Gravity.RIGHT | Gravity.TOP; - params.setTitle("Load Average"); - WindowManagerImpl wm = (WindowManagerImpl)getSystemService(WINDOW_SERVICE); - wm.addView(mView, params); - } - - @Override - public void onDestroy() { - super.onDestroy(); - ((WindowManagerImpl)getSystemService(WINDOW_SERVICE)).removeView(mView); - mView = null; - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - -} diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java deleted file mode 100644 index bc8da93..0000000 --- a/services/java/com/android/server/LocationManagerService.java +++ /dev/null @@ -1,2691 +0,0 @@ -/* - * Copyright (C) 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; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.location.Address; -import android.location.IGpsStatusListener; -import android.location.ILocationListener; -import android.location.ILocationManager; -import android.location.Location; -import android.location.LocationManager; -import android.location.LocationProvider; -import android.location.LocationProviderImpl; -import android.net.ConnectivityManager; -import android.net.Uri; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.provider.Settings; -import android.telephony.CellLocation; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; -import android.util.Config; -import android.util.Log; -import android.util.PrintWriterPrinter; -import android.util.SparseIntArray; - -import com.android.internal.app.IBatteryStats; -import com.android.internal.location.CellState; -import com.android.internal.location.GpsLocationProvider; -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 - * updates and alerts. - * - * {@hide} - */ -public class LocationManagerService extends ILocationManager.Stub - implements INetworkLocationManager { - private static final String TAG = "LocationManagerService"; - - // Minimum time interval between last known location writes, in milliseconds. - private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L; - - // Max time to hold wake lock for, in milliseconds. - private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; - - // Time to wait after releasing a wake lock for clients to process location update, - // in milliseconds. - private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L; - - // The last time a location was written, by provider name. - private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); - - private static final Pattern PATTERN_COMMA = Pattern.compile(","); - - private static final String ACCESS_FINE_LOCATION = - android.Manifest.permission.ACCESS_FINE_LOCATION; - private static final String ACCESS_COARSE_LOCATION = - android.Manifest.permission.ACCESS_COARSE_LOCATION; - private static final String ACCESS_MOCK_LOCATION = - android.Manifest.permission.ACCESS_MOCK_LOCATION; - private static final String ACCESS_LOCATION_EXTRA_COMMANDS = - android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; - - // Set of providers that are explicitly enabled - private final Set<String> mEnabledProviders = new HashSet<String>(); - - // Set of providers that are explicitly disabled - private final Set<String> mDisabledProviders = new HashSet<String>(); - - // Locations, status values, and extras for mock providers - HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>(); - private final HashMap<String,Location> mMockProviderLocation = new HashMap<String,Location>(); - private final HashMap<String,Integer> mMockProviderStatus = new HashMap<String,Integer>(); - private final HashMap<String,Bundle> mMockProviderStatusExtras = new HashMap<String,Bundle>(); - private final HashMap<String,Long> mMockProviderStatusUpdateTime = new HashMap<String,Long>(); - - private static boolean sProvidersLoaded = false; - - private final Context mContext; - private GpsLocationProvider mGpsLocationProvider; - private boolean mGpsNavigating; - 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_INSTALL_NETWORK_LOCATION_PROVIDER = 4; - - // Alarm manager and wakelock variables - private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; - private final static String WAKELOCK_KEY = "LocationManagerService"; - private final static String WIFILOCK_KEY = "LocationManagerService"; - private AlarmManager mAlarmManager; - private long mAlarmInterval = 0; - private boolean mScreenOn = true; - private PowerManager.WakeLock mWakeLock = null; - private WifiManager.WifiLock mWifiLock = null; - private long mWakeLockAcquireTime = 0; - private boolean mWakeLockGpsReceived = true; - private boolean mWakeLockNetworkReceived = true; - private boolean mWifiWakeLockAcquired = false; - private boolean mCellWakeLockAcquired = false; - - private final IBatteryStats mBatteryStats; - - /** - * Mapping from listener IBinder/PendingIntent to local Listener wrappers. - */ - private final ArrayList<Receiver> mListeners = new ArrayList<Receiver>(); - - /** - * Used for reporting which UIDs are causing the GPS to run. - */ - private final SparseIntArray mReportedGpsUids = new SparseIntArray(); - private int mReportedGpsSeq = 0; - - /** - * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord. - * This also serves as the lock for our state. - */ - private final HashMap<Receiver,HashMap<String,UpdateRecord>> mLocationListeners = - new HashMap<Receiver,HashMap<String,UpdateRecord>>(); - - /** - * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast - * location. - */ - private final HashMap<Receiver,HashMap<String,Location>> mLastFixBroadcast = - new HashMap<Receiver,HashMap<String,Location>>(); - private final HashMap<Receiver,HashMap<String,Long>> mLastStatusBroadcast = - new HashMap<Receiver,HashMap<String,Long>>(); - - /** - * Mapping from provider name to all its UpdateRecords - */ - private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = - new HashMap<String,ArrayList<UpdateRecord>>(); - - /** - * Mappings from provider name to object to use for current location. Locations - * contained in this list may not always be valid. - */ - private final HashMap<String,Location> mLocationsByProvider = - new HashMap<String,Location>(); - - // Proximity listeners - private Receiver mProximityListener = null; - private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = - new HashMap<PendingIntent,ProximityAlert>(); - private HashSet<ProximityAlert> mProximitiesEntered = - new HashSet<ProximityAlert>(); - - // Last known location for each provider - private HashMap<String,Location> mLastKnownLocation = - new HashMap<String,Location>(); - - // Battery status extras (from com.android.server.BatteryService) - private static final String BATTERY_EXTRA_SCALE = "scale"; - private static final String BATTERY_EXTRA_LEVEL = "level"; - private static final String BATTERY_EXTRA_PLUGGED = "plugged"; - - // Last known cell service state - private TelephonyManager mTelephonyManager; - private int mSignalStrength = -1; - - // Location collector - private ILocationCollector mCollector; - - // Wifi Manager - private WifiManager mWifiManager; - - /** - * A wrapper class holding either an ILocationListener or a PendingIntent to receive - * location updates. - */ - private final class Receiver implements IBinder.DeathRecipient { - final ILocationListener mListener; - final PendingIntent mPendingIntent; - final int mUid; - final Object mKey; - - Receiver(ILocationListener listener, int uid) { - mListener = listener; - mPendingIntent = null; - mUid = uid; - mKey = listener.asBinder(); - } - - Receiver(PendingIntent intent, int uid) { - mPendingIntent = intent; - mListener = null; - mUid = uid; - mKey = intent; - } - - @Override - public boolean equals(Object otherObj) { - if (otherObj instanceof Receiver) { - return mKey.equals( - ((Receiver)otherObj).mKey); - } - return false; - } - - @Override - public int hashCode() { - return mKey.hashCode(); - } - - - @Override - public String toString() { - if (mListener != null) { - return "Receiver{" - + Integer.toHexString(System.identityHashCode(this)) - + " uid " + mUid + " Listener " + mKey + "}"; - } else { - return "Receiver{" - + Integer.toHexString(System.identityHashCode(this)) - + " uid " + mUid + " Intent " + mKey + "}"; - } - } - - public boolean isListener() { - return mListener != null; - } - - public boolean isPendingIntent() { - return mPendingIntent != null; - } - - public ILocationListener getListener() { - if (mListener != null) { - return mListener; - } - throw new IllegalStateException("Request for non-existent listener"); - } - - public PendingIntent getPendingIntent() { - if (mPendingIntent != null) { - return mPendingIntent; - } - throw new IllegalStateException("Request for non-existent intent"); - } - - public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { - if (mListener != null) { - try { - mListener.onStatusChanged(provider, status, extras); - } catch (RemoteException e) { - return false; - } - } else { - Intent statusChanged = new Intent(); - statusChanged.putExtras(extras); - statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); - try { - mPendingIntent.send(mContext, 0, statusChanged, null, null); - } catch (PendingIntent.CanceledException e) { - return false; - } - } - return true; - } - - public boolean callLocationChangedLocked(Location location) { - if (mListener != null) { - try { - mListener.onLocationChanged(location); - } catch (RemoteException e) { - return false; - } - } else { - Intent locationChanged = new Intent(); - locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); - try { - mPendingIntent.send(mContext, 0, locationChanged, null, null); - } catch (PendingIntent.CanceledException e) { - return false; - } - } - return true; - } - - public void binderDied() { - if (Config.LOGD) { - Log.d(TAG, "Location listener died"); - } - synchronized (mLocationListeners) { - removeUpdatesLocked(this); - } - } - } - - private Location readLastKnownLocationLocked(String provider) { - Location location = null; - String s = null; - try { - File f = new File(LocationManager.SYSTEM_DIR + "/location." - + provider); - if (!f.exists()) { - return null; - } - BufferedReader reader = new BufferedReader(new FileReader(f), 256); - s = reader.readLine(); - } catch (IOException e) { - Log.w(TAG, "Unable to read last known location", e); - } - - if (s == null) { - return null; - } - try { - String[] tokens = PATTERN_COMMA.split(s); - int idx = 0; - long time = Long.parseLong(tokens[idx++]); - double latitude = Double.parseDouble(tokens[idx++]); - double longitude = Double.parseDouble(tokens[idx++]); - double altitude = Double.parseDouble(tokens[idx++]); - float bearing = Float.parseFloat(tokens[idx++]); - float speed = Float.parseFloat(tokens[idx++]); - - location = new Location(provider); - location.setTime(time); - location.setLatitude(latitude); - location.setLongitude(longitude); - location.setAltitude(altitude); - location.setBearing(bearing); - location.setSpeed(speed); - } catch (NumberFormatException nfe) { - Log.e(TAG, "NumberFormatException reading last known location", nfe); - return null; - } - - return location; - } - - private void writeLastKnownLocationLocked(String provider, - Location location) { - long now = SystemClock.elapsedRealtime(); - Long last = mLastWriteTime.get(provider); - if ((last != null) - && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) { - return; - } - mLastWriteTime.put(provider, now); - - StringBuilder sb = new StringBuilder(100); - sb.append(location.getTime()); - sb.append(','); - sb.append(location.getLatitude()); - sb.append(','); - sb.append(location.getLongitude()); - sb.append(','); - sb.append(location.getAltitude()); - sb.append(','); - sb.append(location.getBearing()); - sb.append(','); - sb.append(location.getSpeed()); - - FileWriter writer = null; - try { - File d = new File(LocationManager.SYSTEM_DIR); - if (!d.exists()) { - if (!d.mkdirs()) { - Log.w(TAG, "Unable to create directory to write location"); - return; - } - } - File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider); - writer = new FileWriter(f); - writer.write(sb.toString()); - } catch (IOException e) { - Log.w(TAG, "Unable to write location", e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - Log.w(TAG, "Exception closing file", e); - } - } - } - } - - /** - * Load providers from /data/location/<provider_name>/ - * class - * kml - * nmea - * track - * location - * properties - */ - private void loadProviders() { - synchronized (mLocationListeners) { - if (sProvidersLoaded) { - return; - } - - // Load providers - loadProvidersLocked(); - sProvidersLoaded = true; - } - } - - private void loadProvidersLocked() { - try { - _loadProvidersLocked(); - } catch (Exception e) { - Log.e(TAG, "Exception loading providers:", e); - } - } - - private void _loadProvidersLocked() { - // Attempt to load "real" providers first - if (GpsLocationProvider.isSupported()) { - // Create a gps location provider - mGpsLocationProvider = new GpsLocationProvider(mContext); - LocationProviderImpl.addProvider(mGpsLocationProvider); - } - - // Load fake providers if real providers are not available - File f = new File(LocationManager.PROVIDER_DIR); - if (f.isDirectory()) { - File[] subdirs = f.listFiles(); - for (int i = 0; i < subdirs.length; i++) { - if (!subdirs[i].isDirectory()) { - continue; - } - - String name = subdirs[i].getName(); - - if (Config.LOGD) { - Log.d(TAG, "Found dir " + subdirs[i].getAbsolutePath()); - Log.d(TAG, "name = " + name); - } - - // Don't create a fake provider if a real provider exists - if (LocationProviderImpl.getProvider(name) == null) { - LocationProviderImpl provider = null; - try { - File classFile = new File(subdirs[i], "class"); - // Look for a 'class' file - provider = LocationProviderImpl.loadFromClass(classFile); - - // Look for an 'kml', 'nmea', or 'track' file - if (provider == null) { - // Load properties from 'properties' file, if present - File propertiesFile = new File(subdirs[i], "properties"); - - if (propertiesFile.exists()) { - provider = new TrackProvider(name); - ((TrackProvider)provider).readProperties(propertiesFile); - - File kmlFile = new File(subdirs[i], "kml"); - if (kmlFile.exists()) { - ((TrackProvider) provider).readKml(kmlFile); - } else { - File nmeaFile = new File(subdirs[i], "nmea"); - if (nmeaFile.exists()) { - ((TrackProvider) provider).readNmea(name, nmeaFile); - } else { - File trackFile = new File(subdirs[i], "track"); - if (trackFile.exists()) { - ((TrackProvider) provider).readTrack(trackFile); - } - } - } - } - } - if (provider != null) { - LocationProviderImpl.addProvider(provider); - } - // Grab the initial location of a TrackProvider and - // store it as the last known location for that provider - if (provider instanceof TrackProvider) { - TrackProvider tp = (TrackProvider) provider; - mLastKnownLocation.put(tp.getName(), tp.getInitialLocation()); - } - } catch (Exception e) { - Log.e(TAG, "Exception loading provder " + name, e); - } - } - } - } - - updateProvidersLocked(); - } - - /** - * @param context the context that the LocationManagerService runs in - */ - public LocationManagerService(Context context) { - super(); - mContext = context; - mLocationHandler = new LocationWorkerHandler(); - - if (Config.LOGD) { - Log.d(TAG, "Constructed LocationManager Service"); - } - - // 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(); - - // Listen for Radio changes - mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - mTelephonyManager.listen(mPhoneStateListener, - PhoneStateListener.LISTEN_CELL_LOCATION | - PhoneStateListener.LISTEN_SIGNAL_STRENGTH | - PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); - - // Register for Network (Wifi or Mobile) updates - NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver(); - IntentFilter networkIntentFilter = new IntentFilter(); - networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); - context.registerReceiver(networkReceiver, networkIntentFilter); - - // Register for power updates - PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver(); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ALARM_INTENT); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); - intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - context.registerReceiver(powerStateReceiver, intentFilter); - - // Get the wifi manager - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - - // Create a wifi lock for future use - mWifiLock = getWifiWakelockLocked(); - - // There might be an existing wifi scan available - if (mWifiManager != null) { - List<ScanResult> wifiScanResults = mWifiManager.getScanResults(); - if (wifiScanResults != null && wifiScanResults.size() != 0) { - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); - } - } - } - } - - public void setInstallCallback(InstallCallback callback) { - synchronized (mLocationListeners) { - mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER); - Message m = Message.obtain(mLocationHandler, - MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback); - mLocationHandler.sendMessageAtFrontOfQueue(m); - } - } - - public void setNetworkLocationProvider(INetworkLocationProvider provider) { - synchronized (mLocationListeners) { - mNetworkLocationInterface = provider; - provider.addListener(getPackageNames()); - mNetworkLocationProvider = (LocationProviderImpl)provider; - LocationProviderImpl.addProvider(mNetworkLocationProvider); - updateProvidersLocked(); - } - } - - public void setLocationCollector(ILocationCollector collector) { - synchronized (mLocationListeners) { - mCollector = collector; - if (mGpsLocationProvider != null) { - mGpsLocationProvider.setLocationCollector(mCollector); - } - } - } - - private WifiManager.WifiLock getWifiWakelockLocked() { - if (mWifiLock == null && mWifiManager != null) { - mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY); - mWifiLock.setReferenceCounted(false); - } - return mWifiLock; - } - - private boolean isAllowedBySettingsLocked(String provider) { - if (mEnabledProviders.contains(provider)) { - return true; - } - if (mDisabledProviders.contains(provider)) { - return false; - } - // Use system settings - ContentResolver resolver = mContext.getContentResolver(); - String allowedProviders = Settings.Secure.getString(resolver, - Settings.Secure.LOCATION_PROVIDERS_ALLOWED); - - return ((allowedProviders != null) && (allowedProviders.contains(provider))); - } - - private void checkPermissionsSafe(String provider) { - if (LocationManager.GPS_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED)) { - throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); - } - if (LocationManager.NETWORK_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) - && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) - != PackageManager.PERMISSION_GRANTED)) { - throw new SecurityException( - "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); - } - } - - private boolean isAllowedProviderSafe(String provider) { - if (LocationManager.GPS_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED)) { - return false; - } - if (LocationManager.NETWORK_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) - && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) - != PackageManager.PERMISSION_GRANTED)) { - return false; - } - - return true; - } - - private String[] getPackageNames() { - // Since a single UID may correspond to multiple packages, this can only be used as an - // approximation for tracking - return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); - } - - public List<String> getAllProviders() { - try { - synchronized (mLocationListeners) { - return _getAllProvidersLocked(); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "getAllProviders got exception:", e); - return null; - } - } - - private List<String> _getAllProvidersLocked() { - if (Config.LOGD) { - Log.d(TAG, "getAllProviders"); - } - List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); - ArrayList<String> out = new ArrayList<String>(providers.size()); - - for (LocationProviderImpl p : providers) { - out.add(p.getName()); - } - return out; - } - - public List<String> getProviders(boolean enabledOnly) { - try { - synchronized (mLocationListeners) { - return _getProvidersLocked(enabledOnly); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "getProviders gotString exception:", e); - return null; - } - } - - private List<String> _getProvidersLocked(boolean enabledOnly) { - if (Config.LOGD) { - Log.d(TAG, "getProviders"); - } - List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); - ArrayList<String> out = new ArrayList<String>(); - - for (LocationProviderImpl p : providers) { - String name = p.getName(); - if (isAllowedProviderSafe(name)) { - if (enabledOnly && !isAllowedBySettingsLocked(name)) { - continue; - } - out.add(name); - } - } - return out; - } - - public void updateProviders() { - synchronized (mLocationListeners) { - updateProvidersLocked(); - } - } - - private void updateProvidersLocked() { - for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { - boolean isEnabled = p.isEnabled(); - String name = p.getName(); - boolean shouldBeEnabled = isAllowedBySettingsLocked(name); - - // Collection is only allowed when network provider is being used - if (mCollector != null && - p.getName().equals(LocationManager.NETWORK_PROVIDER)) { - mCollector.updateNetworkProviderStatus(shouldBeEnabled); - } - - if (isEnabled && !shouldBeEnabled) { - updateProviderListenersLocked(name, false); - } else if (!isEnabled && shouldBeEnabled) { - updateProviderListenersLocked(name, true); - } - - } - } - - private void updateProviderListenersLocked(String provider, boolean enabled) { - int listeners = 0; - - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - return; - } - - ArrayList<Receiver> deadReceivers = null; - - ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); - if (records != null) { - final int N = records.size(); - for (int i=0; i<N; i++) { - UpdateRecord record = records.get(i); - // Sends a notification message to the receiver - try { - Receiver receiver = record.mReceiver; - if (receiver.isListener()) { - if (enabled) { - receiver.getListener().onProviderEnabled(provider); - } else { - receiver.getListener().onProviderDisabled(provider); - } - } else { - Intent providerIntent = new Intent(); - providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); - try { - receiver.getPendingIntent().send(mContext, 0, - providerIntent, null, null); - } catch (PendingIntent.CanceledException e) { - if (deadReceivers == null) { - deadReceivers = new ArrayList<Receiver>(); - deadReceivers.add(receiver); - } - } - } - } catch (RemoteException e) { - // The death link will clean this up. - } - listeners++; - } - } - - if (deadReceivers != null) { - for (int i=deadReceivers.size()-1; i>=0; i--) { - removeUpdatesLocked(deadReceivers.get(i)); - } - } - - if (enabled) { - p.enable(); - if (listeners > 0) { - p.setMinTime(getMinTimeLocked(provider)); - p.enableLocationTracking(true); - updateWakelockStatusLocked(mScreenOn); - } - } else { - p.enableLocationTracking(false); - if (p == mGpsLocationProvider) { - mGpsNavigating = false; - reportStopGpsLocked(); - } - p.disable(); - updateWakelockStatusLocked(mScreenOn); - } - - if (enabled && listeners > 0) { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); - Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); - mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); - } else { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); - } - } - - private long getMinTimeLocked(String provider) { - long minTime = Long.MAX_VALUE; - ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); - if (records != null) { - for (int i=records.size()-1; i>=0; i--) { - minTime = Math.min(minTime, records.get(i).mMinTime); - } - } - return minTime; - } - - private class UpdateRecord { - final String mProvider; - final Receiver mReceiver; - final long mMinTime; - final float mMinDistance; - final int mUid; - final String[] mPackages; - - /** - * Note: must be constructed with lock held. - */ - UpdateRecord(String provider, long minTime, float minDistance, - Receiver receiver, int uid, String[] packages) { - mProvider = provider; - mReceiver = receiver; - mMinTime = minTime; - mMinDistance = minDistance; - mUid = uid; - mPackages = packages; - - ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); - if (records == null) { - records = new ArrayList<UpdateRecord>(); - mRecordsByProvider.put(provider, records); - } - if (!records.contains(this)) { - records.add(this); - } - } - - /** - * Method to be called when a record will no longer be used. Calling this multiple times - * must have the same effect as calling it once. - */ - void disposeLocked() { - ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); - records.remove(this); - } - - @Override - public String toString() { - return "UpdateRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + mProvider + " " + mReceiver + "}"; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); - pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); - StringBuilder sb = new StringBuilder(); - if (mPackages != null) { - for (int i=0; i<mPackages.length; i++) { - if (i > 0) sb.append(", "); - sb.append(mPackages[i]); - } - } - pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb); - } - - /** - * Calls dispose(). - */ - @Override protected void finalize() { - synchronized (mLocationListeners) { - disposeLocked(); - } - } - } - - public void requestLocationUpdates(String provider, - long minTime, float minDistance, ILocationListener listener) { - - try { - synchronized (mLocationListeners) { - requestLocationUpdatesLocked(provider, minTime, minDistance, - new Receiver(listener, Binder.getCallingUid())); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "requestUpdates got exception:", e); - } - } - - public void requestLocationUpdatesPI(String provider, - long minTime, float minDistance, PendingIntent intent) { - try { - synchronized (mLocationListeners) { - requestLocationUpdatesLocked(provider, minTime, minDistance, - new Receiver(intent, Binder.getCallingUid())); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "requestUpdates got exception:", e); - } - } - - private void requestLocationUpdatesLocked(String provider, - long minTime, float minDistance, Receiver receiver) { - if (Config.LOGD) { - Log.d(TAG, "_requestLocationUpdates: listener = " + receiver); - } - - LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); - if (impl == null) { - throw new IllegalArgumentException("provider=" + provider); - } - - checkPermissionsSafe(provider); - - String[] packages = getPackageNames(); - - // so wakelock calls will succeed - final int callingUid = Binder.getCallingUid(); - long identity = Binder.clearCallingIdentity(); - try { - UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, - receiver, callingUid, packages); - if (!mListeners.contains(receiver)) { - try { - if (receiver.isListener()) { - receiver.getListener().asBinder().linkToDeath(receiver, 0); - } - mListeners.add(receiver); - } catch (RemoteException e) { - return; - } - } - - HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver); - if (records == null) { - records = new HashMap<String,UpdateRecord>(); - mLocationListeners.put(receiver, records); - } - UpdateRecord oldRecord = records.put(provider, r); - if (oldRecord != null) { - oldRecord.disposeLocked(); - } - - boolean isProviderEnabled = isAllowedBySettingsLocked(provider); - if (isProviderEnabled) { - long minTimeForProvider = getMinTimeLocked(provider); - impl.setMinTime(minTimeForProvider); - impl.enableLocationTracking(true); - updateWakelockStatusLocked(mScreenOn); - - if (provider.equals(LocationManager.GPS_PROVIDER)) { - if (mGpsNavigating) { - updateReportedGpsLocked(); - } - } - - // Clear heartbeats if any before starting a new one - 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 - if (receiver.isListener()) { - receiver.getListener().onProviderDisabled(provider); - } - } catch(RemoteException e) { - Log.w(TAG, "RemoteException calling onProviderDisabled on " + - receiver.getListener()); - } - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - public void removeUpdates(ILocationListener listener) { - try { - synchronized (mLocationListeners) { - removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid())); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "removeUpdates got exception:", e); - } - } - - public void removeUpdatesPI(PendingIntent intent) { - try { - synchronized (mLocationListeners) { - removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid())); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "removeUpdates got exception:", e); - } - } - - private void removeUpdatesLocked(Receiver receiver) { - if (Config.LOGD) { - Log.d(TAG, "_removeUpdates: listener = " + receiver); - } - - // so wakelock calls will succeed - final int callingUid = Binder.getCallingUid(); - long identity = Binder.clearCallingIdentity(); - try { - int idx = mListeners.indexOf(receiver); - if (idx >= 0) { - Receiver myReceiver = mListeners.remove(idx); - if (myReceiver.isListener()) { - myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0); - } - } - - // Record which providers were associated with this listener - HashSet<String> providers = new HashSet<String>(); - HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver); - if (oldRecords != null) { - // Call dispose() on the obsolete update records. - for (UpdateRecord record : oldRecords.values()) { - if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) { - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.removeListener(record.mPackages); - } - } - record.disposeLocked(); - } - // Accumulate providers - providers.addAll(oldRecords.keySet()); - } - - mLocationListeners.remove(receiver); - mLastFixBroadcast.remove(receiver); - mLastStatusBroadcast.remove(receiver); - - // See if the providers associated with this listener have any - // other listeners; if one does, inform it of the new smallest minTime - // value; if one does not, disable location tracking for it - for (String provider : providers) { - // If provider is already disabled, don't need to do anything - if (!isAllowedBySettingsLocked(provider)) { - continue; - } - - boolean hasOtherListener = false; - ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); - if (recordsForProvider != null && recordsForProvider.size() > 0) { - hasOtherListener = true; - } - - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p != null) { - if (hasOtherListener) { - p.setMinTime(getMinTimeLocked(provider)); - } else { - mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); - p.enableLocationTracking(false); - } - - if (p == mGpsLocationProvider && mGpsNavigating) { - updateReportedGpsLocked(); - } - } - } - - updateWakelockStatusLocked(mScreenOn); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - public boolean addGpsStatusListener(IGpsStatusListener listener) { - if (mGpsLocationProvider == null) { - return false; - } - if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); - } - - try { - mGpsLocationProvider.addGpsStatusListener(listener); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException in addGpsStatusListener"); - return false; - } - return true; - } - - public void removeGpsStatusListener(IGpsStatusListener listener) { - synchronized (mLocationListeners) { - mGpsLocationProvider.removeGpsStatusListener(listener); - } - } - - public boolean sendExtraCommand(String provider, String command, Bundle extras) { - // first check for permission to the provider - checkPermissionsSafe(provider); - // and check for ACCESS_LOCATION_EXTRA_COMMANDS - if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS) - != PackageManager.PERMISSION_GRANTED)) { - throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); - } - - synchronized (mLocationListeners) { - LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); - if (provider == null) { - return false; - } - - return impl.sendExtraCommand(command, extras); - } - } - - class ProximityAlert { - final int mUid; - final double mLatitude; - final double mLongitude; - final float mRadius; - final long mExpiration; - final PendingIntent mIntent; - final Location mLocation; - - public ProximityAlert(int uid, double latitude, double longitude, - float radius, long expiration, PendingIntent intent) { - mUid = uid; - mLatitude = latitude; - mLongitude = longitude; - mRadius = radius; - mExpiration = expiration; - mIntent = intent; - - mLocation = new Location(""); - mLocation.setLatitude(latitude); - mLocation.setLongitude(longitude); - } - - long getExpiration() { - return mExpiration; - } - - PendingIntent getIntent() { - return mIntent; - } - - boolean isInProximity(double latitude, double longitude) { - Location loc = new Location(""); - loc.setLatitude(latitude); - loc.setLongitude(longitude); - - double radius = loc.distanceTo(mLocation); - return radius <= mRadius; - } - - @Override - public String toString() { - return "ProximityAlert{" - + Integer.toHexString(System.identityHashCode(this)) - + " uid " + mUid + mIntent + "}"; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); - pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); - pw.println(prefix + "mIntent=" + mIntent); - pw.println(prefix + "mLocation:"); - mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); - } - } - - // Listener for receiving locations to trigger proximity alerts - class ProximityListener extends ILocationListener.Stub { - - boolean isGpsAvailable = false; - - // Note: this is called with the lock held. - public void onLocationChanged(Location loc) { - - // If Gps is available, then ignore updates from NetworkLocationProvider - if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { - isGpsAvailable = true; - } - if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { - return; - } - - // Process proximity alerts - long now = System.currentTimeMillis(); - double latitude = loc.getLatitude(); - double longitude = loc.getLongitude(); - ArrayList<PendingIntent> intentsToRemove = null; - - for (ProximityAlert alert : mProximityAlerts.values()) { - PendingIntent intent = alert.getIntent(); - long expiration = alert.getExpiration(); - - if ((expiration == -1) || (now <= expiration)) { - boolean entered = mProximitiesEntered.contains(alert); - boolean inProximity = - alert.isInProximity(latitude, longitude); - if (!entered && inProximity) { - if (Config.LOGD) { - Log.i(TAG, "Entered alert"); - } - mProximitiesEntered.add(alert); - Intent enteredIntent = new Intent(); - enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); - try { - intent.send(mContext, 0, enteredIntent, null, null); - } catch (PendingIntent.CanceledException e) { - if (Config.LOGD) { - Log.i(TAG, "Canceled proximity alert: " + alert, e); - } - if (intentsToRemove == null) { - intentsToRemove = new ArrayList<PendingIntent>(); - } - intentsToRemove.add(intent); - } - } else if (entered && !inProximity) { - if (Config.LOGD) { - Log.i(TAG, "Exited alert"); - } - mProximitiesEntered.remove(alert); - Intent exitedIntent = new Intent(); - exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); - try { - intent.send(mContext, 0, exitedIntent, null, null); - } catch (PendingIntent.CanceledException e) { - if (Config.LOGD) { - Log.i(TAG, "Canceled proximity alert: " + alert, e); - } - if (intentsToRemove == null) { - intentsToRemove = new ArrayList<PendingIntent>(); - } - intentsToRemove.add(intent); - } - } - } else { - // Mark alert for expiration - if (Config.LOGD) { - Log.i(TAG, "Expiring proximity alert: " + alert); - } - if (intentsToRemove == null) { - intentsToRemove = new ArrayList<PendingIntent>(); - } - intentsToRemove.add(alert.getIntent()); - } - } - - // Remove expired alerts - if (intentsToRemove != null) { - for (PendingIntent i : intentsToRemove) { - mProximityAlerts.remove(i); - ProximityAlert alert = mProximityAlerts.get(i); - mProximitiesEntered.remove(alert); - } - } - - } - - // Note: this is called with the lock held. - public void onProviderDisabled(String provider) { - if (provider.equals(LocationManager.GPS_PROVIDER)) { - isGpsAvailable = false; - } - } - - // Note: this is called with the lock held. - public void onProviderEnabled(String provider) { - // ignore - } - - // Note: this is called with the lock held. - public void onStatusChanged(String provider, int status, Bundle extras) { - if ((provider.equals(LocationManager.GPS_PROVIDER)) && - (status != LocationProvider.AVAILABLE)) { - isGpsAvailable = false; - } - } - } - - public void addProximityAlert(double latitude, double longitude, - float radius, long expiration, PendingIntent intent) { - try { - synchronized (mLocationListeners) { - addProximityAlertLocked(latitude, longitude, radius, expiration, intent); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "addProximityAlert got exception:", e); - } - } - - private void addProximityAlertLocked(double latitude, double longitude, - float radius, long expiration, PendingIntent intent) { - if (Config.LOGD) { - Log.d(TAG, "addProximityAlert: latitude = " + latitude + - ", longitude = " + longitude + - ", expiration = " + expiration + - ", intent = " + intent); - } - - // Require ability to access all providers for now - if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || - !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { - throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); - } - - if (expiration != -1) { - expiration += System.currentTimeMillis(); - } - ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), - latitude, longitude, radius, expiration, intent); - mProximityAlerts.put(intent, alert); - - if (mProximityListener == null) { - mProximityListener = new Receiver(new ProximityListener(), -1); - - LocationProvider provider = LocationProviderImpl.getProvider( - LocationManager.GPS_PROVIDER); - if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); - } - - provider = - LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); - if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); - } - } else if (mGpsNavigating) { - updateReportedGpsLocked(); - } - } - - public void removeProximityAlert(PendingIntent intent) { - try { - synchronized (mLocationListeners) { - removeProximityAlertLocked(intent); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "removeProximityAlert got exception:", e); - } - } - - private void removeProximityAlertLocked(PendingIntent intent) { - if (Config.LOGD) { - Log.d(TAG, "removeProximityAlert: intent = " + intent); - } - - mProximityAlerts.remove(intent); - if (mProximityAlerts.size() == 0) { - removeUpdatesLocked(mProximityListener); - mProximityListener = null; - } else if (mGpsNavigating) { - updateReportedGpsLocked(); - } - } - - /** - * @return null if the provider does not exits - * @throw SecurityException if the provider is not allowed to be - * accessed by the caller - */ - public Bundle getProviderInfo(String provider) { - try { - synchronized (mLocationListeners) { - return _getProviderInfoLocked(provider); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "_getProviderInfo got exception:", e); - return null; - } - } - - private Bundle _getProviderInfoLocked(String provider) { - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - return null; - } - - checkPermissionsSafe(provider); - - Bundle b = new Bundle(); - b.putBoolean("network", p.requiresNetwork()); - b.putBoolean("satellite", p.requiresSatellite()); - b.putBoolean("cell", p.requiresCell()); - b.putBoolean("cost", p.hasMonetaryCost()); - b.putBoolean("altitude", p.supportsAltitude()); - b.putBoolean("speed", p.supportsSpeed()); - b.putBoolean("bearing", p.supportsBearing()); - b.putInt("power", p.getPowerRequirement()); - b.putInt("accuracy", p.getAccuracy()); - - return b; - } - - public boolean isProviderEnabled(String provider) { - try { - synchronized (mLocationListeners) { - return _isProviderEnabledLocked(provider); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "isProviderEnabled got exception:", e); - return false; - } - } - - private boolean _isProviderEnabledLocked(String provider) { - checkPermissionsSafe(provider); - - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - throw new IllegalArgumentException("provider=" + provider); - } - return isAllowedBySettingsLocked(provider); - } - - public Location getLastKnownLocation(String provider) { - try { - synchronized (mLocationListeners) { - return _getLastKnownLocationLocked(provider); - } - } catch (SecurityException se) { - throw se; - } catch (Exception e) { - Log.e(TAG, "getLastKnownLocation got exception:", e); - return null; - } - } - - private Location _getLastKnownLocationLocked(String provider) { - checkPermissionsSafe(provider); - - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - throw new IllegalArgumentException("provider=" + provider); - } - - if (!isAllowedBySettingsLocked(provider)) { - return null; - } - - Location location = mLastKnownLocation.get(provider); - if (location == null) { - // Get the persistent last known location for the provider - location = readLastKnownLocationLocked(provider); - if (location != null) { - mLastKnownLocation.put(provider, location); - } - } - - return location; - } - - private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { - // Always broadcast the first update - if (lastLoc == null) { - return true; - } - - // Don't broadcast same location again regardless of condition - // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 - if (loc.getTime() == lastLoc.getTime()) { - return false; - } - - // Check whether sufficient distance has been traveled - double minDistance = record.mMinDistance; - if (minDistance > 0.0) { - if (loc.distanceTo(lastLoc) <= minDistance) { - return false; - } - } - - return true; - } - - private void handleLocationChangedLocked(String provider) { - ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); - if (records == null || records.size() == 0) { - return; - } - - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - return; - } - - // Get location object - Location loc = mLocationsByProvider.get(provider); - if (loc == null) { - loc = new Location(provider); - mLocationsByProvider.put(provider, loc); - } else { - loc.reset(); - } - - // Use the mock location if available - Location mockLoc = mMockProviderLocation.get(provider); - boolean locationValid; - if (mockLoc != null) { - locationValid = true; - loc.set(mockLoc); - } else { - locationValid = p.getLocation(loc); - } - - // Update last known location for provider - if (locationValid) { - Location location = mLastKnownLocation.get(provider); - if (location == null) { - mLastKnownLocation.put(provider, new Location(loc)); - } else { - location.set(loc); - } - writeLastKnownLocationLocked(provider, loc); - - if (p instanceof INetworkLocationProvider) { - mWakeLockNetworkReceived = true; - } else if (p instanceof GpsLocationProvider) { - // Gps location received signal is in NetworkStateBroadcastReceiver - } - } - - // Fetch latest status update time - long newStatusUpdateTime = p.getStatusUpdateTime(); - - // Override real time with mock time if present - Long mockStatusUpdateTime = mMockProviderStatusUpdateTime.get(provider); - if (mockStatusUpdateTime != null) { - newStatusUpdateTime = mockStatusUpdateTime.longValue(); - } - - // Get latest status - Bundle extras = new Bundle(); - int status = p.getStatus(extras); - - // Override status with mock status if present - Integer mockStatus = mMockProviderStatus.get(provider); - if (mockStatus != null) { - status = mockStatus.intValue(); - } - - // Override extras with mock extras if present - Bundle mockExtras = mMockProviderStatusExtras.get(provider); - if (mockExtras != null) { - extras.clear(); - extras.putAll(mockExtras); - } - - ArrayList<Receiver> deadReceivers = null; - - // Broadcast location or status to all listeners - final int N = records.size(); - for (int i=0; i<N; i++) { - UpdateRecord r = records.get(i); - Receiver receiver = r.mReceiver; - - // Broadcast location only if it is valid - if (locationValid) { - HashMap<String,Location> map = mLastFixBroadcast.get(receiver); - if (map == null) { - map = new HashMap<String,Location>(); - mLastFixBroadcast.put(receiver, map); - } - Location lastLoc = map.get(provider); - if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) { - if (lastLoc == null) { - lastLoc = new Location(loc); - map.put(provider, lastLoc); - } else { - lastLoc.set(loc); - } - if (!receiver.callLocationChangedLocked(loc)) { - Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); - if (deadReceivers == null) { - deadReceivers = new ArrayList<Receiver>(); - } - deadReceivers.add(receiver); - } - } - } - - // Broadcast status message - HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver); - if (statusMap == null) { - statusMap = new HashMap<String,Long>(); - mLastStatusBroadcast.put(receiver, statusMap); - } - long prevStatusUpdateTime = - (statusMap.get(provider) != null) ? statusMap.get(provider) : 0; - - if ((newStatusUpdateTime > prevStatusUpdateTime) && - (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { - - statusMap.put(provider, newStatusUpdateTime); - if (!receiver.callStatusChangedLocked(provider, status, extras)) { - Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); - if (deadReceivers == null) { - deadReceivers = new ArrayList<Receiver>(); - } - if (!deadReceivers.contains(receiver)) { - deadReceivers.add(receiver); - } - } - } - } - - if (deadReceivers != null) { - for (int i=deadReceivers.size()-1; i>=0; i--) { - removeUpdatesLocked(deadReceivers.get(i)); - } - } - } - - private class LocationWorkerHandler extends Handler { - - @Override - public void handleMessage(Message msg) { - try { - if (msg.what == MESSAGE_HEARTBEAT) { - // log("LocationWorkerHandler: Heartbeat!"); - - synchronized (mLocationListeners) { - String provider = (String) msg.obj; - if (!isAllowedBySettingsLocked(provider)) { - return; - } - - // Process the location fix if the screen is on or we're holding a wakelock - if (mScreenOn || (mWakeLockAcquireTime != 0)) { - handleLocationChangedLocked(provider); - } - - // If it continues to have listeners - ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); - if (records != null && records.size() > 0) { - Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider); - sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); - } - - if ((mWakeLockAcquireTime != 0) && - (SystemClock.elapsedRealtime() - mWakeLockAcquireTime - > MAX_TIME_FOR_WAKE_LOCK)) { - - removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Exceeded max time for wake lock"); - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageAtFrontOfQueue(m); - - } else if (mWakeLockAcquireTime != 0 && - mWakeLockGpsReceived && mWakeLockNetworkReceived) { - - removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Locations received."); - mWakeLockAcquireTime = 0; - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); - } - } - - } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) { - log("LocationWorkerHandler: Acquire"); - synchronized (mLocationListeners) { - acquireWakeLockLocked(); - } - } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { - log("LocationWorkerHandler: Release"); - - // Update wakelock status so the next alarm is set before releasing wakelock - synchronized (mLocationListeners) { - updateWakelockStatusLocked(mScreenOn); - releaseWakeLockLocked(); - } - } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) { - synchronized (mLocationListeners) { - Log.d(TAG, "installing network location provider"); - INetworkLocationManager.InstallCallback callback = - (INetworkLocationManager.InstallCallback)msg.obj; - callback.installNetworkLocationProvider(mContext, LocationManagerService.this); - } - } - } catch (Exception e) { - // Log, don't crash! - Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); - } - } - } - - PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - - private CellState mLastCellState = null; - @Override - public void onCellLocationChanged(CellLocation cellLocation) { - try { - synchronized (mLocationListeners) { - int asu = mSignalStrength; - - // Gets cell state - mLastCellState = new CellState(mTelephonyManager, cellLocation, asu); - - // Notify collector - if (mCollector != null) { - mCollector.updateCellState(mLastCellState); - } - - // Updates providers - List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); - for (LocationProviderImpl provider : providers) { - if (provider.requiresCell()) { - provider.updateCellState(mLastCellState); - } - } - } - } catch (Exception e) { - Log.e(TAG, "Exception in PhoneStateListener.onCellLocationCahnged:", e); - } - } - - @Override - public void onSignalStrengthChanged(int asu) { - synchronized (mLocationListeners) { - mSignalStrength = asu; - - if (mLastCellState != null) { - mLastCellState.updateSignalStrength(asu); - } - } - } - - @Override - public void onDataConnectionStateChanged(int state) { - synchronized (mLocationListeners) { - if (mLastCellState != null) { - mLastCellState.updateRadioType(mTelephonyManager); - } - } - } - }; - - private class PowerStateBroadcastReceiver extends BroadcastReceiver { - @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(ALARM_INTENT)) { - synchronized (mLocationListeners) { - log("PowerStateBroadcastReceiver: Alarm received"); - mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - // Have to do this immediately, rather than posting a - // message, so we execute our code while the system - // is holding a wake lock until the alarm broadcast - // is finished. - acquireWakeLockLocked(); - } - - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - log("PowerStateBroadcastReceiver: Screen off"); - synchronized (mLocationListeners) { - updateWakelockStatusLocked(false); - } - - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { - log("PowerStateBroadcastReceiver: Screen on"); - synchronized (mLocationListeners) { - updateWakelockStatusLocked(true); - } - - } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - log("PowerStateBroadcastReceiver: Battery changed"); - synchronized (mLocationListeners) { - int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100); - int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0); - boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0; - - // Notify collector battery state - if (mCollector != null) { - mCollector.updateBatteryState(scale, level, plugged); - } - } - } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) - || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { - synchronized (mLocationListeners) { - int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); - if (uid >= 0) { - ArrayList<Receiver> removedRecs = null; - for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { - for (int j=i.size()-1; j>=0; j--) { - UpdateRecord ur = i.get(j); - if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { - if (removedRecs == null) { - removedRecs = new ArrayList<Receiver>(); - } - if (!removedRecs.contains(ur.mReceiver)) { - removedRecs.add(ur.mReceiver); - } - } - } - } - ArrayList<ProximityAlert> removedAlerts = null; - for (ProximityAlert i : mProximityAlerts.values()) { - if (i.mUid == uid) { - if (removedAlerts == null) { - removedAlerts = new ArrayList<ProximityAlert>(); - } - if (!removedAlerts.contains(i)) { - removedAlerts.add(i); - } - } - } - if (removedRecs != null) { - for (int i=removedRecs.size()-1; i>=0; i--) { - removeUpdatesLocked(removedRecs.get(i)); - } - } - if (removedAlerts != null) { - for (int i=removedAlerts.size()-1; i>=0; i--) { - removeProximityAlertLocked(removedAlerts.get(i).mIntent); - } - } - } - } - } - } - } - - private class NetworkStateBroadcastReceiver extends BroadcastReceiver { - @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - - List<ScanResult> wifiScanResults = mWifiManager.getScanResults(); - - if (wifiScanResults == null) { - return; - } - - // Notify provider and collector of Wifi scan results - synchronized (mLocationListeners) { - if (mCollector != null) { - mCollector.updateWifiScanResults(wifiScanResults); - } - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); - } - } - - } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - int networkState = LocationProvider.TEMPORARILY_UNAVAILABLE; - - boolean noConnectivity = - intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - if (!noConnectivity) { - networkState = LocationProvider.AVAILABLE; - } - - // Notify location providers of current network state - synchronized (mLocationListeners) { - List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); - for (LocationProviderImpl provider : providers) { - if (provider.requiresNetwork()) { - provider.updateNetworkState(networkState); - } - } - } - - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN); - - boolean enabled; - if (state == WifiManager.WIFI_STATE_ENABLED) { - enabled = true; - } else if (state == WifiManager.WIFI_STATE_DISABLED) { - enabled = false; - } else { - return; - } - - // Notify network provider of current wifi enabled state - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateWifiEnabledState(enabled); - } - } - - } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { - - final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, - false); - - synchronized (mLocationListeners) { - if (enabled) { - updateReportedGpsLocked(); - mGpsNavigating = true; - } else { - reportStopGpsLocked(); - mGpsNavigating = false; - // When GPS is disabled, we are OK to release wake-lock - mWakeLockGpsReceived = true; - } - } - } - - } - } - - // Wake locks - - private void updateWakelockStatusLocked(boolean screenOn) { - log("updateWakelockStatus(): " + screenOn); - - boolean needsLock = false; - long minTime = Integer.MAX_VALUE; - - if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { - needsLock = true; - minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime); - } - - if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) { - needsLock = true; - minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime); - if (screenOn) { - startGpsLocked(); - } else if (mScreenOn && !screenOn) { - // We just turned the screen off so stop navigating - stopGpsLocked(); - } - } - - mScreenOn = screenOn; - - PendingIntent sender = - PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0); - - // Cancel existing alarm - log("Cancelling existing alarm"); - mAlarmManager.cancel(sender); - - if (needsLock && !mScreenOn) { - long now = SystemClock.elapsedRealtime(); - mAlarmManager.set( - AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender); - mAlarmInterval = minTime; - log("Creating a new wakelock alarm with minTime = " + minTime); - } else { - log("No need for alarm"); - mAlarmInterval = -1; - - // Clear out existing wakelocks - mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); - mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - releaseWakeLockLocked(); - } - } - - private void acquireWakeLockLocked() { - try { - acquireWakeLockXLocked(); - } catch (Exception e) { - // This is to catch a runtime exception thrown when we try to release an - // already released lock. - Log.e(TAG, "exception in acquireWakeLock()", e); - } - } - - private void acquireWakeLockXLocked() { - if (mWakeLock.isHeld()) { - log("Must release wakelock before acquiring"); - mWakeLockAcquireTime = 0; - mWakeLock.release(); - } - - boolean networkActive = (mNetworkLocationProvider != null) - && mNetworkLocationProvider.isLocationTracking(); - boolean gpsActive = (mGpsLocationProvider != null) - && mGpsLocationProvider.isLocationTracking(); - - boolean needsLock = networkActive || gpsActive; - if (!needsLock) { - log("No need for Lock!"); - return; - } - - mWakeLockGpsReceived = !gpsActive; - mWakeLockNetworkReceived = !networkActive; - - // Acquire wake lock - mWakeLock.acquire(); - mWakeLockAcquireTime = SystemClock.elapsedRealtime(); - log("Acquired wakelock"); - - // Start the gps provider - startGpsLocked(); - - // Acquire cell lock - if (mCellWakeLockAcquired) { - // Lock is already acquired - } else if (!mWakeLockNetworkReceived) { - mTelephonyManager.enableLocationUpdates(); - mCellWakeLockAcquired = true; - } else { - mCellWakeLockAcquired = false; - } - - // Notify NetworkLocationProvider - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); - } - - // Acquire wifi lock - WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); - if (wifiLock != null) { - if (mWifiWakeLockAcquired) { - // Lock is already acquired - } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) { - wifiLock.acquire(); - mWifiWakeLockAcquired = true; - } else { - mWifiWakeLockAcquired = false; - Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock"); - } - } - } - - private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) { - int seq = mReportedGpsUids.get(uid, -1); - if (seq == curSeq) { - // Already reported; propagate to next sequence. - mReportedGpsUids.put(uid, nextSeq); - return true; - } else if (seq != nextSeq) { - try { - // New UID; report it. - mBatteryStats.noteStartGps(uid); - mReportedGpsUids.put(uid, nextSeq); - return true; - } catch (RemoteException e) { - } - } - return false; - } - - private void updateReportedGpsLocked() { - if (mGpsLocationProvider == null) { - return; - } - - final String name = mGpsLocationProvider.getName(); - final int curSeq = mReportedGpsSeq; - final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0; - mReportedGpsSeq = nextSeq; - - ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name); - int num = 0; - final int N = urs.size(); - for (int i=0; i<N; i++) { - UpdateRecord ur = urs.get(i); - if (ur.mReceiver == mProximityListener) { - // We don't want the system to take the blame for this one. - continue; - } - if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) { - num++; - } - } - - for (ProximityAlert pe : mProximityAlerts.values()) { - if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) { - num++; - } - } - - if (num != mReportedGpsUids.size()) { - // The number of uids is processed is different than the - // array; report any that are no longer active. - for (int i=mReportedGpsUids.size()-1; i>=0; i--) { - if (mReportedGpsUids.valueAt(i) != nextSeq) { - try { - mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); - } catch (RemoteException e) { - } - mReportedGpsUids.removeAt(i); - } - } - } - } - - private void reportStopGpsLocked() { - int curSeq = mReportedGpsSeq; - for (int i=mReportedGpsUids.size()-1; i>=0; i--) { - if (mReportedGpsUids.valueAt(i) == curSeq) { - try { - mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i)); - } catch (RemoteException e) { - } - } - } - curSeq++; - if (curSeq < 0) curSeq = 0; - mReportedGpsSeq = curSeq; - mReportedGpsUids.clear(); - } - - private void startGpsLocked() { - boolean gpsActive = (mGpsLocationProvider != null) - && mGpsLocationProvider.isLocationTracking(); - if (gpsActive) { - mGpsLocationProvider.startNavigating(); - } - } - - private void stopGpsLocked() { - boolean gpsActive = mGpsLocationProvider != null - && mGpsLocationProvider.isLocationTracking(); - if (gpsActive) { - mGpsLocationProvider.stopNavigating(); - } - } - - private void releaseWakeLockLocked() { - try { - releaseWakeLockXLocked(); - } catch (Exception e) { - // This is to catch a runtime exception thrown when we try to release an - // already released lock. - Log.e(TAG, "exception in releaseWakeLock()", e); - } - } - - private void releaseWakeLockXLocked() { - // Release wifi lock - WifiManager.WifiLock wifiLock = getWifiWakelockLocked(); - if (wifiLock != null) { - if (mWifiWakeLockAcquired) { - wifiLock.release(); - mWifiWakeLockAcquired = false; - } - } - - if (!mScreenOn) { - // Stop the gps - stopGpsLocked(); - } - - // Release cell lock - if (mCellWakeLockAcquired) { - mTelephonyManager.disableLocationUpdates(); - mCellWakeLockAcquired = false; - } - - // Notify NetworkLocationProvider - if (mNetworkLocationInterface != null) { - mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); - } - - // Release wake lock - mWakeLockAcquireTime = 0; - if (mWakeLock.isHeld()) { - log("Released wakelock"); - mWakeLock.release(); - } else { - log("Can't release wakelock again!"); - } - } - - // Geocoder - - public String getFromLocation(double latitude, double longitude, int maxResults, - String language, String country, String variant, String appName, List<Address> addrs) { - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults, - language, country, variant, appName, addrs); - } else { - return null; - } - } - } - - public String getFromLocationName(String locationName, - double lowerLeftLatitude, double lowerLeftLongitude, - double upperRightLatitude, double upperRightLongitude, int maxResults, - String language, String country, String variant, String appName, List<Address> addrs) { - synchronized (mLocationListeners) { - if (mNetworkLocationInterface != null) { - return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, - lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults, - language, country, variant, appName, addrs); - } else { - return null; - } - } - } - - // Mock Providers - - class MockProvider extends LocationProviderImpl { - boolean mRequiresNetwork; - boolean mRequiresSatellite; - boolean mRequiresCell; - boolean mHasMonetaryCost; - boolean mSupportsAltitude; - boolean mSupportsSpeed; - boolean mSupportsBearing; - int mPowerRequirement; - int mAccuracy; - - public MockProvider(String name, boolean requiresNetwork, boolean requiresSatellite, - boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, - boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { - super(name); - - mRequiresNetwork = requiresNetwork; - mRequiresSatellite = requiresSatellite; - mRequiresCell = requiresCell; - mHasMonetaryCost = hasMonetaryCost; - mSupportsAltitude = supportsAltitude; - mSupportsBearing = supportsBearing; - mSupportsSpeed = supportsSpeed; - mPowerRequirement = powerRequirement; - mAccuracy = accuracy; - } - - @Override - public void disable() { - String name = getName(); - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - mEnabledProviders.remove(name); - mDisabledProviders.add(name); - } - } - - @Override - public void enable() { - String name = getName(); - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - mEnabledProviders.add(name); - mDisabledProviders.remove(name); - } - } - - @Override - public boolean getLocation(Location l) { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - Location loc = mMockProviderLocation.get(getName()); - if (loc == null) { - return false; - } - l.set(loc); - return true; - } - } - - @Override - public int getStatus(Bundle extras) { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - String name = getName(); - Integer s = mMockProviderStatus.get(name); - int status = (s == null) ? AVAILABLE : s.intValue(); - Bundle newExtras = mMockProviderStatusExtras.get(name); - if (newExtras != null) { - extras.clear(); - extras.putAll(newExtras); - } - return status; - } - } - - @Override - public boolean isEnabled() { - // We shouldn't normally need to lock, since this should only be called - // by the service with the lock held, but let's be paranid. - synchronized (mLocationListeners) { - return mEnabledProviders.contains(getName()); - } - } - - @Override - public int getAccuracy() { - return mAccuracy; - } - - @Override - public int getPowerRequirement() { - return mPowerRequirement; - } - - @Override - public boolean hasMonetaryCost() { - return mHasMonetaryCost; - } - - @Override - public boolean requiresCell() { - return mRequiresCell; - } - - @Override - public boolean requiresNetwork() { - return mRequiresNetwork; - } - - @Override - public boolean requiresSatellite() { - return mRequiresSatellite; - } - - @Override - public boolean supportsAltitude() { - return mSupportsAltitude; - } - - @Override - public boolean supportsBearing() { - return mSupportsBearing; - } - - @Override - public boolean supportsSpeed() { - return mSupportsSpeed; - } - } - - private void checkMockPermissionsSafe() { - boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; - if (!allowMocks) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); - } - - if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); - } - } - - public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, - boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, - boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { - checkMockPermissionsSafe(); - - synchronized (mLocationListeners) { - MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite, - requiresCell, hasMonetaryCost, supportsAltitude, - supportsSpeed, supportsBearing, powerRequirement, accuracy); - if (LocationProviderImpl.getProvider(name) != null) { - throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); - } - LocationProviderImpl.addProvider(provider); - updateProvidersLocked(); - } - } - - public void removeTestProvider(String provider) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - LocationProviderImpl p = LocationProviderImpl.getProvider(provider); - if (p == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - LocationProviderImpl.removeProvider(p); - updateProvidersLocked(); - } - } - - public void setTestProviderLocation(String provider, Location loc) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mMockProviderLocation.put(provider, loc); - } - } - - public void clearTestProviderLocation(String provider) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mMockProviderLocation.remove(provider); - } - } - - public void setTestProviderEnabled(String provider, boolean enabled) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - if (enabled) { - mEnabledProviders.add(provider); - mDisabledProviders.remove(provider); - } else { - mEnabledProviders.remove(provider); - mDisabledProviders.add(provider); - } - updateProvidersLocked(); - } - } - - public void clearTestProviderEnabled(String provider) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mEnabledProviders.remove(provider); - mDisabledProviders.remove(provider); - updateProvidersLocked(); - } - } - - public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mMockProviderStatus.put(provider, new Integer(status)); - mMockProviderStatusExtras.put(provider, extras); - mMockProviderStatusUpdateTime.put(provider, new Long(updateTime)); - } - } - - public void clearTestProviderStatus(String provider) { - checkMockPermissionsSafe(); - synchronized (mLocationListeners) { - if (LocationProviderImpl.getProvider(provider) == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); - } - mMockProviderStatus.remove(provider); - mMockProviderStatusExtras.remove(provider); - mMockProviderStatusUpdateTime.remove(provider); - } - } - - private void log(String log) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, log); - } - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump AlarmManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mLocationListeners) { - pw.println("Current Location Manager state:"); - pw.println(" sProvidersLoaded=" + sProvidersLoaded); - pw.println(" mGpsLocationProvider=" + mGpsLocationProvider); - pw.println(" mGpsNavigating=" + mGpsNavigating); - pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider); - pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface); - pw.println(" mCollector=" + mCollector); - pw.println(" mSignalStrength=" + mSignalStrength); - pw.println(" mAlarmInterval=" + mAlarmInterval - + " mScreenOn=" + mScreenOn - + " mWakeLockAcquireTime=" + mWakeLockAcquireTime); - pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived - + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived); - pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired - + " mCellWakeLockAcquired=" + mCellWakeLockAcquired); - pw.println(" Listeners:"); - int N = mListeners.size(); - for (int i=0; i<N; i++) { - pw.println(" " + mListeners.get(i)); - } - pw.println(" Location Listeners:"); - for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i - : mLocationListeners.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) { - pw.println(" " + j.getKey() + ":"); - j.getValue().dump(pw, " "); - } - } - pw.println(" Last Fix Broadcasts:"); - for (Map.Entry<Receiver, HashMap<String,Location>> i - : mLastFixBroadcast.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry<String,Location> j : i.getValue().entrySet()) { - pw.println(" " + j.getKey() + ":"); - j.getValue().dump(new PrintWriterPrinter(pw), " "); - } - } - pw.println(" Last Status Broadcasts:"); - for (Map.Entry<Receiver, HashMap<String,Long>> i - : mLastStatusBroadcast.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (Map.Entry<String,Long> j : i.getValue().entrySet()) { - pw.println(" " + j.getKey() + " -> 0x" - + Long.toHexString(j.getValue())); - } - } - pw.println(" Records by Provider:"); - for (Map.Entry<String, ArrayList<UpdateRecord>> i - : mRecordsByProvider.entrySet()) { - pw.println(" " + i.getKey() + ":"); - for (UpdateRecord j : i.getValue()) { - pw.println(" " + j + ":"); - j.dump(pw, " "); - } - } - pw.println(" Locations by Provider:"); - for (Map.Entry<String, Location> i - : mLocationsByProvider.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(new PrintWriterPrinter(pw), " "); - } - pw.println(" Last Known Locations:"); - for (Map.Entry<String, Location> i - : mLastKnownLocation.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(new PrintWriterPrinter(pw), " "); - } - if (mProximityAlerts.size() > 0) { - pw.println(" Proximity Alerts:"); - for (Map.Entry<PendingIntent, ProximityAlert> i - : mProximityAlerts.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(pw, " "); - } - } - if (mProximitiesEntered.size() > 0) { - pw.println(" Proximities Entered:"); - for (ProximityAlert i : mProximitiesEntered) { - pw.println(" " + i + ":"); - i.dump(pw, " "); - } - } - pw.println(" mProximityListener=" + mProximityListener); - if (mEnabledProviders.size() > 0) { - pw.println(" Enabled Providers:"); - for (String i : mEnabledProviders) { - pw.println(" " + i); - } - - } - if (mDisabledProviders.size() > 0) { - pw.println(" Disabled Providers:"); - for (String i : mDisabledProviders) { - pw.println(" " + i); - } - - } - if (mMockProviders.size() > 0) { - pw.println(" Mock Providers:"); - for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); - } - } - if (mMockProviderLocation.size() > 0) { - pw.println(" Mock Provider Location:"); - for (Map.Entry<String, Location> i : mMockProviderLocation.entrySet()) { - pw.println(" " + i.getKey() + ":"); - i.getValue().dump(new PrintWriterPrinter(pw), " "); - } - } - if (mMockProviderStatus.size() > 0) { - pw.println(" Mock Provider Status:"); - for (Map.Entry<String, Integer> i : mMockProviderStatus.entrySet()) { - pw.println(" " + i.getKey() + " -> 0x" - + Integer.toHexString(i.getValue())); - } - } - if (mMockProviderStatusExtras.size() > 0) { - pw.println(" Mock Provider Status Extras:"); - for (Map.Entry<String, Bundle> i : mMockProviderStatusExtras.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); - } - } - if (mMockProviderStatusUpdateTime.size() > 0) { - pw.println(" Mock Provider Status Update Time:"); - for (Map.Entry<String, Long> i : mMockProviderStatusUpdateTime.entrySet()) { - pw.println(" " + i.getKey() + " -> " + i.getValue()); - } - } - pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":"); - N = mReportedGpsUids.size(); - for (int i=0; i<N; i++) { - pw.println(" UID " + mReportedGpsUids.keyAt(i) - + " seq=" + mReportedGpsUids.valueAt(i)); - } - } - } -} - diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java deleted file mode 100644 index 5a42e76..0000000 --- a/services/java/com/android/server/MasterClearReceiver.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.Intent; -import android.content.BroadcastReceiver; -import android.os.RemoteException; -import android.os.ICheckinService; -import android.os.ServiceManager; -import android.util.Log; - -public class MasterClearReceiver extends BroadcastReceiver { - - private static final String TAG = "MasterClear"; - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) { - if (!intent.getBooleanExtra("from_trusted_server", false)) { - Log.w(TAG, "Ignoring master clear request -- not from trusted server."); - return; - } - } - Log.w(TAG, "!!! FACTORY RESETTING DEVICE !!!"); - ICheckinService service = - ICheckinService.Stub.asInterface( - ServiceManager.getService("checkin")); - if (service != null) { - try { - // This RPC should never return. - service.masterClear(); - } catch (RemoteException e) { - Log.w("MasterClear", - "Unable to invoke ICheckinService.masterClear()"); - } - } - } -} diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java deleted file mode 100644 index 2e430c8..0000000 --- a/services/java/com/android/server/MountListener.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 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; - -import android.net.LocalSocketAddress; -import android.net.LocalSocket; -import android.os.Environment; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.util.Config; -import android.util.Log; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.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. - */ -final class MountListener implements Runnable { - - private static final String TAG = "MountListener"; - - // ** THE FOLLOWING STRING CONSTANTS MUST MATCH VALUES IN system/vold/ - - // socket name for connecting to vold - private static final String VOLD_SOCKET = "vold"; - - // 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:"; - - // 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 vol service daemon - */ - private MountService mService; - - /** - * Stream for sending commands to the vol service daemon. - */ - private OutputStream mOutputStream; - - /** - * Cached value indicating whether or not USB mass storage is enabled. - */ - private boolean mUmsEnabled; - - /** - * Cached value indicating whether or not USB mass storage is connected. - */ - private boolean mUmsConnected; - - /** - * Constructor for MountListener - * - * @param service The MountListener we are handling communication with USB - * daemon for. - */ - MountListener(MountService service) { - mService = service; - } - - /** - * Process and dispatches events received from the vol 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); - - int colonIndex = event.indexOf(':'); - String path = (colonIndex > 0 ? event.substring(colonIndex + 1) : null); - - if (event.equals(VOLD_EVT_UMS_ENABLED)) { - mUmsEnabled = true; - } else if (event.equals(VOLD_EVT_UMS_DISABLED)) { - mUmsEnabled = false; - } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) { - mUmsConnected = true; - mService.notifyUmsConnected(); - } else if (event.equals(VOLD_EVT_UMS_DISCONNECTED)) { - mUmsConnected = false; - mService.notifyUmsDisconnected(); - } else if (event.startsWith(VOLD_EVT_NOMEDIA)) { - mService.notifyMediaRemoved(path); - } else if (event.startsWith(VOLD_EVT_UNMOUNTED)) { - mService.notifyMediaUnmounted(path); - } 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(VOLD_EVT_MOUNTED_RO)) { - mService.notifyMediaMounted(path, true); - } else if (event.startsWith(VOLD_EVT_UMS)) { - mService.notifyMediaShared(path); - } 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(VOLD_EVT_DAMAGED)) { - mService.notifyMediaUnmountable(path); - } else if (event.startsWith(VOLD_EVT_EJECTING)) { - mService.notifyMediaEject(path); - } - } - - /** - * Sends a command to the mount service daemon via a local socket - * - * @param command The command to send to the mount service daemon - */ - private void writeCommand(String command) { - writeCommand2(command, null); - } - - /** - * Sends a command to the mount service daemon via a local socket - * with a single argument - * - * @param command The command to send to the mount service daemon - * @param argument The argument to send with the command (or null) - */ - private void writeCommand2(String command, String argument) { - synchronized (this) { - if (mOutputStream == null) { - Log.e(TAG, "No connection to vold", new IllegalStateException()); - } else { - StringBuilder builder = new StringBuilder(command); - if (argument != null) { - builder.append(argument); - } - builder.append('\0'); - - try { - mOutputStream.write(builder.toString().getBytes()); - } catch (IOException ex) { - Log.e(TAG, "IOException in writeCommand", ex); - } - } - } - } - - /** - * Opens a socket to communicate with the mount service daemon and listens - * for events from the daemon. - * - */ - private void listenToSocket() { - LocalSocket socket = null; - - try { - socket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET, - LocalSocketAddress.Namespace.RESERVED); - - socket.connect(address); - - InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); - - byte[] buffer = new byte[100]; - - writeCommand(VOLD_CMD_SEND_UMS_STATUS); - - while (true) { - int count = inputStream.read(buffer); - if (count < 0) break; - - int start = 0; - for (int i = 0; i < count; i++) { - if (buffer[i] == 0) { - String event = new String(buffer, start, i - start); - handleEvent(event); - start = i + 1; - } - } - } - } catch (IOException ex) { - // This exception is normal when running in desktop simulator - // where there is no mount daemon to talk to - - // log("IOException in listenToSocket"); - } - - synchronized (this) { - if (mOutputStream != null) { - try { - mOutputStream.close(); - } catch (IOException e) { - Log.w(TAG, "IOException closing output stream"); - } - - mOutputStream = null; - } - } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - Log.w(TAG, "IOException closing socket"); - } - - /* - * Sleep before trying again. - * This should not happen except while debugging. - * Without this sleep, the emulator will spin and - * create tons of throwaway LocalSockets, making - * system_server GC constantly. - */ - Log.e(TAG, "Failed to connect to vold", new IllegalStateException()); - SystemClock.sleep(2000); - } - - /** - * Main loop for MountListener thread. - */ - public void run() { - // ugly hack for the simulator. - if ("simulator".equals(SystemProperties.get("ro.product.device"))) { - SystemProperties.set("EXTERNAL_STORAGE_STATE", Environment.MEDIA_MOUNTED); - // usbd does not run in the simulator, so send a fake device mounted event to trigger the Media Scanner - mService.notifyMediaMounted(Environment.getExternalStorageDirectory().getPath(), false); - - // no usbd in the simulator, so no point in hanging around. - return; - } - - try { - while (true) { - listenToSocket(); - } - } catch (Throwable t) { - // catch all Throwables so we don't bring down the system process - Log.e(TAG, "Fatal error " + t + " in MountListener thread!"); - } - } - - /** - * @return true if USB mass storage is enabled - */ - boolean getMassStorageEnabled() { - return mUmsEnabled; - } - - /** - * Enables or disables USB mass storage support. - * - * @param enable true to enable USB mass storage support - */ - void setMassStorageEnabled(boolean enable) { - writeCommand(enable ? VOLD_CMD_ENABLE_UMS : VOLD_CMD_DISABLE_UMS); - } - - /** - * @return true if USB mass storage is connected - */ - boolean getMassStorageConnected() { - return mUmsConnected; - } - - /** - * Mount media at given mount point. - */ - public void mountMedia(String mountPoint) { - writeCommand2(VOLD_CMD_MOUNT_VOLUME, mountPoint); - } - - /** - * Unmount media at given mount point. - */ - public void ejectMedia(String 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 deleted file mode 100644 index 0feb1da..0000000 --- a/services/java/com/android/server/MountService.java +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright (C) 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; - -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; -import java.io.FileReader; - -/** - * MountService implements an to the mount service daemon - * @hide - */ -class MountService extends IMountService.Stub { - - private static final String TAG = "MountService"; - - /** - * Binder context for this service - */ - private Context mContext; - - /** - * listener object for communicating with the mount service daemon - */ - private MountListener mListener; - - /** - * The notification that is shown when a USB mass storage host - * is connected. - * <p> - * This is lazily created, so use {@link #setUsbStorageNotification()}. - */ - private Notification mUsbStorageNotification; - - - /** - * 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 - * <p> - * 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 - * - * @param context Binder context for this service - */ - 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); - 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. - */ - public boolean getMassStorageEnabled() throws RemoteException { - return mListener.getMassStorageEnabled(); - } - - /** - * Enables or disables USB mass storage support. - * - * @param enable true to enable USB mass storage support - */ - public void setMassStorageEnabled(boolean enable) throws RemoteException { - mListener.setMassStorageEnabled(enable); - } - - /** - * @return true if USB mass storage is connected. - */ - public boolean getMassStorageConnected() throws RemoteException { - return mListener.getMassStorageConnected(); - } - - /** - * Attempt to mount external media - */ - public void mountMedia(String mountPath) throws RemoteException { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission"); - } - mListener.mountMedia(mountPath); - } - - /** - * Attempt to unmount external media to prepare for eject - */ - public void unmountMedia(String mountPath) throws RemoteException { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) - != PackageManager.PERMISSION_GRANTED) { - 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) && - !storageState.equals(Environment.MEDIA_CHECKING)) { - - updateUsbMassStorageNotification(false, true); - } - - Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED); - mContext.sendBroadcast(intent); - } - - /** - * Broadcasts the USB mass storage disconnected event to all clients. - */ - void notifyUmsDisconnected() { - updateUsbMassStorageNotification(false, false); - Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); - mContext.sendBroadcast(intent); - } - - /** - * 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); - } - - /** - * 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); - } - - /** - * Broadcasts the media shared event to all clients. - */ - void notifyMediaShared(String path) { - 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); - } - - /** - * 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.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); - } - - /** - * Broadcasts the media eject event to all clients. - */ - void notifyMediaEject(String path) { - Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT, - Uri.parse("file://" + path)); - mContext.sendBroadcast(intent); - } - - /** - * Sets the USB storage notification. - */ - 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; - } - - if (visible) { - 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; - } - - /** - * Sets the media storage notification. - */ - private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible, - boolean dismissable, PendingIntent pi) { - - if (!visible && mMediaStorageNotification == null) { - return; - } - - NotificationManager notificationManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - - 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); - } - - 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 deleted file mode 100644 index 1ea0bac..0000000 --- a/services/java/com/android/server/NetStatService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.os.INetStatService; -import android.os.NetStat; - -public class NetStatService extends INetStatService.Stub { - - public NetStatService(Context context) { - - } - - public long getMobileTxPackets() { - return NetStat.getMobileTxPkts(); - } - - public long getMobileRxPackets() { - return NetStat.getMobileRxPkts(); - } - - public long getMobileTxBytes() { - return NetStat.getMobileTxBytes(); - } - - 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 deleted file mode 100644 index e5de7f9..0000000 --- a/services/java/com/android/server/NotificationManagerService.java +++ /dev/null @@ -1,916 +0,0 @@ -/* - * Copyright (C) 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; - -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.INotificationManager; -import android.app.ITransientNotification; -import android.app.Notification; -import android.app.PendingIntent; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.media.AudioManager; -import android.media.AsyncPlayer; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.BatteryManager; -import android.os.Binder; -import android.os.RemoteException; -import android.os.Handler; -import android.os.Hardware; -import android.os.IBinder; -import android.os.Message; -import android.os.Power; -import android.os.Vibrator; -import android.provider.Settings; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.widget.Toast; - -import com.android.server.status.IconData; -import com.android.server.status.NotificationData; -import com.android.server.status.StatusBarService; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.io.IOException; - -class NotificationManagerService extends INotificationManager.Stub -{ - private static final String TAG = "NotificationService"; - private static final boolean DBG = false; - - // message codes - private static final int MESSAGE_TIMEOUT = 2; - - private static final int LONG_DELAY = 3500; // 3.5 seconds - private static final int SHORT_DELAY = 2000; // 2 seconds - - private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; - - private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; - - final Context mContext; - final IActivityManager mAm; - final IBinder mForegroundToken = new Binder(); - - private WorkerHandler mHandler; - private StatusBarService mStatusBarService; - - private NotificationRecord mSoundNotification; - private AsyncPlayer mSound; - private int mDisabledNotifications; - - private NotificationRecord mVibrateNotification; - private Vibrator mVibrator = new Vibrator(); - - private ArrayList<NotificationRecord> mNotificationList; - - private ArrayList<ToastRecord> mToastQueue; - - private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>(); - - private boolean mBatteryCharging; - private boolean mBatteryLow; - private boolean mBatteryFull; - private NotificationRecord mLedNotification; - - // Low battery - red, blinking on 0.125s every 3 seconds - private static final int BATTERY_LOW_ARGB = 0xFFFF0000; - private static final int BATTERY_LOW_ON = 125; - private static final int BATTERY_LOW_OFF = 2875; - - // Charging Low - red solid on - private static final int CHARGING_LOW_ARGB = 0xFFFF0000; - private static final int CHARGING_LOW_ON = 0; - private static final int CHARGING_LOW_OFF = 0; - - // Charging - orange solid on - private static final int CHARGING_ARGB = 0xFFFFFF00; - private static final int CHARGING_ON = 0; - private static final int CHARGING_OFF = 0; - - // Charging Full - green solid on - private static final int CHARGING_FULL_ARGB = 0xFF00FF00; - private static final int CHARGING_FULL_ON = 0; - private static final int CHARGING_FULL_OFF = 0; - - // Tag IDs for EventLog. - private static final int EVENT_LOG_ENQUEUE = 2750; - private static final int EVENT_LOG_CANCEL = 2751; - private static final int EVENT_LOG_CANCEL_ALL = 2752; - - private static String idDebugString(Context baseContext, String packageName, int id) { - Context c = null; - - if (packageName != null) { - try { - c = baseContext.createPackageContext(packageName, 0); - } catch (NameNotFoundException e) { - c = baseContext; - } - } else { - c = baseContext; - } - - String pkg; - String type; - String name; - - Resources r = c.getResources(); - try { - return r.getResourceName(id); - } catch (Resources.NotFoundException e) { - return "<name unknown>"; - } - } - - private static final class NotificationRecord - { - String pkg; - int id; - ITransientNotification callback; - int duration; - Notification notification; - IBinder statusBarKey; - - NotificationRecord(String pkg, int id, Notification notification) - { - this.pkg = pkg; - this.id = id; - this.notification = notification; - } - - void dump(PrintWriter pw, String prefix, Context baseContext) { - pw.println(prefix + this); - pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon) - + " / " + idDebugString(baseContext, this.pkg, notification.icon)); - pw.println(prefix + " contentIntent=" + notification.contentIntent); - pw.println(prefix + " deleteIntent=" + notification.deleteIntent); - pw.println(prefix + " tickerText=" + notification.tickerText); - pw.println(prefix + " contentView=" + notification.contentView); - pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults)); - pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags)); - pw.println(prefix + " sound=" + notification.sound); - pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate)); - pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB) - + " ledOnMS=" + notification.ledOnMS - + " ledOffMS=" + notification.ledOffMS); - } - - @Override - public final String toString() - { - return "NotificationRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " pkg=" + pkg - + " id=" + Integer.toHexString(id) + "}"; - } - } - - private static final class ToastRecord - { - final int pid; - final String pkg; - final ITransientNotification callback; - int duration; - - ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) - { - this.pid = pid; - this.pkg = pkg; - this.callback = callback; - this.duration = duration; - } - - void update(int duration) { - this.duration = duration; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - } - - @Override - public final String toString() - { - return "ToastRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " pkg=" + pkg - + " callback=" + callback - + " duration=" + duration; - } - } - - private StatusBarService.NotificationCallbacks mNotificationCallbacks - = new StatusBarService.NotificationCallbacks() { - - public void onSetDisabled(int status) { - synchronized (mNotificationList) { - mDisabledNotifications = status; - if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { - // cancel whatever's going on - long identity = Binder.clearCallingIdentity(); - try { - mSound.stop(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - - identity = Binder.clearCallingIdentity(); - try { - mVibrator.cancel(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - } - } - - public void onClearAll() { - cancelAll(); - } - - public void onNotificationClick(String pkg, int id) { - cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL); - } - - public void onPanelRevealed() { - synchronized (mNotificationList) { - // sound - mSoundNotification = null; - long identity = Binder.clearCallingIdentity(); - try { - mSound.stop(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - - // vibrate - mVibrateNotification = null; - identity = Binder.clearCallingIdentity(); - try { - mVibrator.cancel(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - - // light - mLights.clear(); - mLedNotification = null; - updateLightsLocked(); - } - } - }; - - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0); - int level = intent.getIntExtra("level", -1); - boolean batteryLow = (level >= 0 && level <= Power.LOW_BATTERY_THRESHOLD); - int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN); - boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90); - - if (batteryCharging != mBatteryCharging || - batteryLow != mBatteryLow || - batteryFull != mBatteryFull) { - mBatteryCharging = batteryCharging; - mBatteryLow = batteryLow; - mBatteryFull = batteryFull; - updateLights(); - } - } - } - }; - - NotificationManagerService(Context context, StatusBarService statusBar) - { - super(); - mContext = context; - mAm = ActivityManagerNative.getDefault(); - mSound = new AsyncPlayer(TAG); - mSound.setUsesWakeLock(context); - mToastQueue = new ArrayList<ToastRecord>(); - mNotificationList = new ArrayList<NotificationRecord>(); - mHandler = new WorkerHandler(); - mStatusBarService = statusBar; - statusBar.setNotificationCallbacks(mNotificationCallbacks); - - // register for battery changed notifications - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - mContext.registerReceiver(mIntentReceiver, filter); - } - - // Toasts - // ============================================================================ - public void enqueueToast(String pkg, ITransientNotification callback, int duration) - { - Log.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration); - - if (pkg == null || callback == null) { - Log.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); - return ; - } - - synchronized (mToastQueue) { - int callingPid = Binder.getCallingPid(); - long callingId = Binder.clearCallingIdentity(); - try { - ToastRecord record; - int index = indexOfToastLocked(pkg, callback); - // If it's already in the queue, we update it in place, we don't - // move it to the end of the queue. - if (index >= 0) { - record = mToastQueue.get(index); - record.update(duration); - } else { - record = new ToastRecord(callingPid, pkg, callback, duration); - mToastQueue.add(record); - index = mToastQueue.size() - 1; - keepProcessAliveLocked(callingPid); - } - // If it's at index 0, it's the current toast. It doesn't matter if it's - // new or just been updated. Call back and tell it to show itself. - // If the callback fails, this will remove it from the list, so don't - // assume that it's valid after this. - if (index == 0) { - showNextToastLocked(); - } - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - } - - public void cancelToast(String pkg, ITransientNotification callback) { - Log.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); - - if (pkg == null || callback == null) { - Log.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); - return ; - } - - synchronized (mToastQueue) { - long callingId = Binder.clearCallingIdentity(); - try { - int index = indexOfToastLocked(pkg, callback); - if (index >= 0) { - cancelToastLocked(index); - } else { - Log.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback); - } - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - } - - private void showNextToastLocked() { - ToastRecord record = mToastQueue.get(0); - while (record != null) { - if (DBG) Log.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); - try { - record.callback.show(); - scheduleTimeoutLocked(record, false); - return; - } catch (RemoteException e) { - Log.w(TAG, "Object died trying to show notification " + record.callback - + " in package " + record.pkg); - // remove it from the list and let the process die - int index = mToastQueue.indexOf(record); - if (index >= 0) { - mToastQueue.remove(index); - } - keepProcessAliveLocked(record.pid); - if (mToastQueue.size() > 0) { - record = mToastQueue.get(0); - } else { - record = null; - } - } - } - } - - private void cancelToastLocked(int index) { - ToastRecord record = mToastQueue.get(index); - try { - record.callback.hide(); - } catch (RemoteException e) { - Log.w(TAG, "Object died trying to hide notification " + record.callback - + " in package " + record.pkg); - // don't worry about this, we're about to remove it from - // the list anyway - } - mToastQueue.remove(index); - keepProcessAliveLocked(record.pid); - if (mToastQueue.size() > 0) { - // Show the next one. If the callback fails, this will remove - // it from the list, so don't assume that the list hasn't changed - // after this point. - showNextToastLocked(); - } - } - - private void scheduleTimeoutLocked(ToastRecord r, boolean immediate) - { - Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); - long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY); - mHandler.removeCallbacksAndMessages(r); - mHandler.sendMessageDelayed(m, delay); - } - - private void handleTimeout(ToastRecord record) - { - if (DBG) Log.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); - synchronized (mToastQueue) { - int index = indexOfToastLocked(record.pkg, record.callback); - if (index >= 0) { - cancelToastLocked(index); - } - } - } - - // lock on mToastQueue - private int indexOfToastLocked(String pkg, ITransientNotification callback) - { - IBinder cbak = callback.asBinder(); - ArrayList<ToastRecord> list = mToastQueue; - int len = list.size(); - for (int i=0; i<len; i++) { - ToastRecord r = list.get(i); - if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { - return i; - } - } - return -1; - } - - // lock on mToastQueue - private void keepProcessAliveLocked(int pid) - { - int toastCount = 0; // toasts from this pid - ArrayList<ToastRecord> list = mToastQueue; - int N = list.size(); - for (int i=0; i<N; i++) { - ToastRecord r = list.get(i); - if (r.pid == pid) { - toastCount++; - } - } - try { - mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); - } catch (RemoteException e) { - // Shouldn't happen. - } - } - - private final class WorkerHandler extends Handler - { - @Override - public void handleMessage(Message msg) - { - switch (msg.what) - { - case MESSAGE_TIMEOUT: - handleTimeout((ToastRecord)msg.obj); - break; - } - } - } - - - // Notifications - // ============================================================================ - public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut) - { - // This conditional is a dirty hack to limit the logging done on - // behalf of the download manager without affecting other apps. - if (!pkg.equals("com.android.providers.downloads") - || Log.isLoggable("DownloadManager", Log.VERBOSE)) { - EventLog.writeEvent(EVENT_LOG_ENQUEUE, pkg, id, notification.toString()); - } - - if (pkg == null || notification == null) { - throw new IllegalArgumentException("null not allowed: pkg=" + pkg - + " id=" + id + " notification=" + notification); - } - if (notification.icon != 0) { - if (notification.contentView == null) { - throw new IllegalArgumentException("contentView required: pkg=" + pkg - + " id=" + id + " notification=" + notification); - } - if (notification.contentIntent == null) { - throw new IllegalArgumentException("contentIntent required: pkg=" + pkg - + " id=" + id + " notification=" + notification); - } - } - - synchronized (mNotificationList) { - NotificationRecord r = new NotificationRecord(pkg, id, notification); - NotificationRecord old = null; - - int index = indexOfNotificationLocked(pkg, id); - if (index < 0) { - mNotificationList.add(r); - } else { - old = mNotificationList.remove(index); - mNotificationList.add(index, r); - } - if (notification.icon != 0) { - IconData icon = IconData.makeIcon(null, pkg, notification.icon, - notification.iconLevel, - notification.number); - CharSequence truncatedTicker = notification.tickerText; - - // TODO: make this restriction do something smarter like never fill - // more than two screens. "Why would anyone need more than 80 characters." :-/ - final int maxTickerLen = 80; - if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) { - truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen); - } - - NotificationData n = new NotificationData(); - n.id = id; - n.pkg = pkg; - n.when = notification.when; - n.tickerText = truncatedTicker; - n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0; - if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) { - n.clearable = true; - } - n.contentView = notification.contentView; - n.contentIntent = notification.contentIntent; - n.deleteIntent = notification.deleteIntent; - if (old != null && old.statusBarKey != null) { - r.statusBarKey = old.statusBarKey; - long identity = Binder.clearCallingIdentity(); - try { - mStatusBarService.updateIcon(r.statusBarKey, icon, n); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } else { - long identity = Binder.clearCallingIdentity(); - try { - r.statusBarKey = mStatusBarService.addIcon(icon, n); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - } else { - if (old != null && old.statusBarKey != null) { - long identity = Binder.clearCallingIdentity(); - try { - mStatusBarService.removeIcon(old.statusBarKey); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - } - - // If we're not supposed to beep, vibrate, etc. then don't. - if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) - && (!(old != null - && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))) { - // sound - final boolean useDefaultSound = - (notification.defaults & Notification.DEFAULT_SOUND) != 0; - if (useDefaultSound || notification.sound != null) { - Uri uri; - if (useDefaultSound) { - uri = Settings.System.DEFAULT_NOTIFICATION_URI; - } else { - uri = notification.sound; - } - boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0; - int audioStreamType; - if (notification.audioStreamType >= 0) { - audioStreamType = notification.audioStreamType; - } else { - audioStreamType = DEFAULT_STREAM_TYPE; - } - mSoundNotification = r; - long identity = Binder.clearCallingIdentity(); - try { - mSound.play(mContext, uri, looping, audioStreamType); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - // vibrate - final AudioManager audioManager = (AudioManager) mContext - .getSystemService(Context.AUDIO_SERVICE); - final boolean useDefaultVibrate = - (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; - if ((useDefaultVibrate || notification.vibrate != null) - && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) { - mVibrateNotification = r; - - mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN - : notification.vibrate, - ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1); - } - } - - // this option doesn't shut off the lights - - // light - // the most recent thing gets the light - mLights.remove(old); - if (mLedNotification == old) { - mLedNotification = null; - } - //Log.i(TAG, "notification.lights=" - // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0)); - if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) { - mLights.add(r); - updateLightsLocked(); - } else { - if (old != null - && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) { - updateLightsLocked(); - } - } - } - - idOut[0] = id; - } - - private void cancelNotificationLocked(NotificationRecord r) { - // status bar - if (r.notification.icon != 0) { - long identity = Binder.clearCallingIdentity(); - try { - mStatusBarService.removeIcon(r.statusBarKey); - } - finally { - Binder.restoreCallingIdentity(identity); - } - r.statusBarKey = null; - } - - // sound - if (mSoundNotification == r) { - mSoundNotification = null; - long identity = Binder.clearCallingIdentity(); - try { - mSound.stop(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - // vibrate - if (mVibrateNotification == r) { - mVibrateNotification = null; - long identity = Binder.clearCallingIdentity(); - try { - mVibrator.cancel(); - } - finally { - Binder.restoreCallingIdentity(identity); - } - } - - // light - mLights.remove(r); - if (mLedNotification == r) { - mLedNotification = null; - } - } - - /** - * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}. - */ - private void cancelNotification(String pkg, int id, int mustHaveFlags) { - EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags); - - synchronized (mNotificationList) { - NotificationRecord r = null; - - int index = indexOfNotificationLocked(pkg, id); - if (index >= 0) { - r = mNotificationList.get(index); - - if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) { - return; - } - - mNotificationList.remove(index); - - cancelNotificationLocked(r); - updateLightsLocked(); - } - } - } - - /** - * Cancels all notifications from a given package that have all of the - * {@code mustHaveFlags}. - */ - private void cancelAllNotificationsInt(String pkg, int mustHaveFlags) { - EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags); - - synchronized (mNotificationList) { - final int N = mNotificationList.size(); - boolean canceledSomething = false; - for (int i = N-1; i >= 0; --i) { - NotificationRecord r = mNotificationList.get(i); - if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) { - continue; - } - if (!r.pkg.equals(pkg)) { - continue; - } - mNotificationList.remove(i); - cancelNotificationLocked(r); - canceledSomething = true; - } - if (canceledSomething) { - updateLightsLocked(); - } - } - } - - - public void cancelNotification(String pkg, int id) - { - cancelNotification(pkg, id, 0); - } - - public void cancelAllNotifications(String pkg) - { - cancelAllNotificationsInt(pkg, 0); - } - - public void cancelAll() { - synchronized (mNotificationList) { - final int N = mNotificationList.size(); - for (int i=N-1; i>=0; i--) { - NotificationRecord r = mNotificationList.get(i); - - if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT - | Notification.FLAG_NO_CLEAR)) == 0) { - if (r.notification.deleteIntent != null) { - try { - r.notification.deleteIntent.send(); - } catch (PendingIntent.CanceledException ex) { - // do nothing - there's no relevant way to recover, and - // no reason to let this propagate - Log.w(TAG, "canceled PendingIntent for " + r.pkg, ex); - } - } - mNotificationList.remove(i); - cancelNotificationLocked(r); - } - } - - updateLightsLocked(); - } - } - - private void updateLights() { - synchronized (mNotificationList) { - updateLightsLocked(); - } - } - - // lock on mNotificationList - private void updateLightsLocked() - { - // battery low has highest priority, then charging - if (mBatteryLow && !mBatteryCharging) { - Hardware.setLedState(BATTERY_LOW_ARGB, BATTERY_LOW_ON, BATTERY_LOW_OFF); - } else if (mBatteryCharging) { - if (mBatteryLow) { - Hardware.setLedState(CHARGING_LOW_ARGB, CHARGING_LOW_ON, CHARGING_LOW_OFF); - } else if (mBatteryFull) { - Hardware.setLedState(CHARGING_FULL_ARGB, CHARGING_FULL_ON, CHARGING_FULL_OFF); - } else { - Hardware.setLedState(CHARGING_ARGB, CHARGING_ON, CHARGING_OFF); - } - } else { - // handle notification lights - if (mLedNotification == null) { - // get next notification, if any - int n = mLights.size(); - if (n > 0) { - mLedNotification = mLights.get(n-1); - } - } - - if (mLedNotification == null) { - Hardware.setLedState(0, 0, 0); - } else { - Hardware.setLedState(mLedNotification.notification.ledARGB, - mLedNotification.notification.ledOnMS, - mLedNotification.notification.ledOffMS); - } - } - } - - // lock on mNotificationList - private int indexOfNotificationLocked(String pkg, int id) - { - ArrayList<NotificationRecord> list = mNotificationList; - final int len = list.size(); - for (int i=0; i<len; i++) { - NotificationRecord r = list.get(i); - if (r.id == id && r.pkg.equals(pkg)) { - return i; - } - } - return -1; - } - - // ====================================================================== - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump NotificationManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("Current Notification Manager state:"); - - int N; - - synchronized (mToastQueue) { - N = mToastQueue.size(); - if (N > 0) { - pw.println(" Toast Queue:"); - for (int i=0; i<N; i++) { - mToastQueue.get(i).dump(pw, " "); - } - pw.println(" "); - } - - } - - synchronized (mNotificationList) { - N = mNotificationList.size(); - if (N > 0) { - pw.println(" Notification List:"); - for (int i=0; i<N; i++) { - mNotificationList.get(i).dump(pw, " ", mContext); - } - pw.println(" "); - } - - N = mLights.size(); - if (N > 0) { - pw.println(" Lights List:"); - for (int i=0; i<N; i++) { - mLights.get(i).dump(pw, " ", mContext); - } - pw.println(" "); - } - - pw.println(" mSoundNotification=" + mSoundNotification); - pw.println(" mSound=" + mSound); - pw.println(" mVibrateNotification=" + mVibrateNotification); - } - } -} diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java deleted file mode 100644 index c490e42..0000000 --- a/services/java/com/android/server/PackageManagerService.java +++ /dev/null @@ -1,6566 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import com.android.internal.app.ResolverActivity; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.app.PendingIntent; -import android.app.PendingIntent.CanceledException; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallObserver; -import android.content.pm.IPackageManager; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.InstrumentationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageStats; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.PKG_INSTALL_COMPLETE; -import static android.content.pm.PackageManager.PKG_INSTALL_INCOMPLETE; -import android.content.pm.PackageParser; -import android.content.pm.PermissionInfo; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.content.pm.Signature; -import android.content.pm.PackageParser.Package; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.HandlerThread; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.Environment; -import android.os.FileObserver; -import android.os.FileUtils; -import android.os.Handler; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.util.*; -import android.view.Display; -import android.view.WindowManager; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashMap; -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; - -class PackageManagerService extends IPackageManager.Stub { - private static final String TAG = "PackageManager"; - private static final boolean DEBUG_SETTINGS = false; - private static final boolean DEBUG_PREFERRED = false; - - private static final boolean MULTIPLE_APPLICATION_UIDS = true; - private static final int RADIO_UID = Process.PHONE_UID; - private static final int FIRST_APPLICATION_UID = - Process.FIRST_APPLICATION_UID; - private static final int MAX_APPLICATION_UIDS = 1000; - - private static final boolean SHOW_INFO = false; - - private static final boolean GET_CERTIFICATES = true; - - private static final int REMOVE_EVENTS = - FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM; - private static final int ADD_EVENTS = - FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO; - - private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS; - - static final int SCAN_MONITOR = 1<<0; - static final int SCAN_NO_DEX = 1<<1; - static final int SCAN_FORCE_DEX = 1<<2; - static final int SCAN_UPDATE_SIGNATURE = 1<<3; - static final int SCAN_FORWARD_LOCKED = 1<<4; - - static final int LOG_BOOT_PROGRESS_PMS_START = 3060; - static final int LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START = 3070; - static final int LOG_BOOT_PROGRESS_PMS_DATA_SCAN_START = 3080; - static final int LOG_BOOT_PROGRESS_PMS_SCAN_END = 3090; - static final int LOG_BOOT_PROGRESS_PMS_READY = 3100; - - final HandlerThread mHandlerThread = new HandlerThread("PackageManager", - Process.THREAD_PRIORITY_BACKGROUND); - final Handler mHandler; - - final int mSdkVersion = SystemProperties.getInt( - "ro.build.version.sdk", 0); - - final Context mContext; - final boolean mFactoryTest; - final DisplayMetrics mMetrics; - final int mDefParseFlags; - final String[] mSeparateProcesses; - - // This is where all application persistent data goes. - final File mAppDataDir; - - // This is the object monitoring the framework dir. - final FileObserver mFrameworkInstallObserver; - - // This is the object monitoring the system app dir. - final FileObserver mSystemInstallObserver; - - // This is the object monitoring mAppInstallDir. - final FileObserver mAppInstallObserver; - - // This is the object monitoring mDrmAppPrivateInstallDir. - final FileObserver mDrmAppInstallObserver; - - // Used for priviledge escalation. MUST NOT BE CALLED WITH mPackages - // LOCK HELD. Can be called with mInstallLock held. - final Installer mInstaller; - - final File mFrameworkDir; - final File mSystemAppDir; - final File mAppInstallDir; - - // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked - // apps. - final File mDrmAppPrivateInstallDir; - - // ---------------------------------------------------------------- - - // Lock for state used when installing and doing other long running - // operations. Methods that must be called with this lock held have - // the prefix "LI". - final Object mInstallLock = new Object(); - - // These are the directories in the 3rd party applications installed dir - // that we have currently loaded packages from. Keys are the application's - // installed zip file (absolute codePath), and values are Package. - final HashMap<String, PackageParser.Package> mAppDirs = - new HashMap<String, PackageParser.Package>(); - - // Information for the parser to write more useful error messages. - File mScanningPath; - int mLastScanError; - - final int[] mOutPermissions = new int[3]; - - // ---------------------------------------------------------------- - - // Keys are String (package name), values are Package. This also serves - // as the lock for the global state. Methods that must be called with - // this lock held have the prefix "LP". - final HashMap<String, PackageParser.Package> mPackages = - new HashMap<String, PackageParser.Package>(); - - final Settings mSettings; - boolean mRestoredSettings; - boolean mReportedUidError; - - // Group-ids that are given to all packages as read from etc/permissions/*.xml. - int[] mGlobalGids; - - // These are the built-in uid -> permission mappings that were read from the - // etc/permissions.xml file. - final SparseArray<HashSet<String>> mSystemPermissions = - new SparseArray<HashSet<String>>(); - - // These are the built-in shared libraries that were read from the - // etc/permissions.xml file. - final HashMap<String, String> mSharedLibraries = new HashMap<String, String>(); - - // All available activities, for your resolving pleasure. - final ActivityIntentResolver mActivities = - new ActivityIntentResolver(); - - // All available receivers, for your resolving pleasure. - final ActivityIntentResolver mReceivers = - new ActivityIntentResolver(); - - // All available services, for your resolving pleasure. - final ServiceIntentResolver mServices = new ServiceIntentResolver(); - - // Keys are String (provider class name), values are Provider. - final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent = - new HashMap<ComponentName, PackageParser.Provider>(); - - // Mapping from provider base names (first directory in content URI codePath) - // to the provider information. - final HashMap<String, PackageParser.Provider> mProviders = - new HashMap<String, PackageParser.Provider>(); - - // Mapping from instrumentation class names to info about them. - final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = - new HashMap<ComponentName, PackageParser.Instrumentation>(); - - // Mapping from permission names to info about them. - final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups = - new HashMap<String, PackageParser.PermissionGroup>(); - - boolean mSystemReady; - boolean mSafeMode; - boolean mHasSystemUidErrors; - - ApplicationInfo mAndroidApplication; - final ActivityInfo mResolveActivity = new ActivityInfo(); - final ResolveInfo mResolveInfo = new ResolveInfo(); - ComponentName mResolveComponentName; - PackageParser.Package mPlatformPackage; - - public static final IPackageManager main(Context context, boolean factoryTest) { - PackageManagerService m = new PackageManagerService(context, factoryTest); - ServiceManager.addService("package", m); - return m; - } - - static String[] splitString(String str, char sep) { - int count = 1; - int i = 0; - while ((i=str.indexOf(sep, i)) >= 0) { - count++; - i++; - } - - String[] res = new String[count]; - i=0; - count = 0; - int lastI=0; - while ((i=str.indexOf(sep, i)) >= 0) { - res[count] = str.substring(lastI, i); - count++; - i++; - lastI = i; - } - res[count] = str.substring(lastI, str.length()); - return res; - } - - public PackageManagerService(Context context, boolean factoryTest) { - EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_START, - SystemClock.uptimeMillis()); - - if (mSdkVersion <= 0) { - Log.w(TAG, "**** ro.build.version.sdk not set!"); - } - - mContext = context; - mFactoryTest = factoryTest; - mMetrics = new DisplayMetrics(); - mSettings = new Settings(); - mSettings.addSharedUserLP("android.uid.system", - Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); - mSettings.addSharedUserLP("android.uid.phone", - MULTIPLE_APPLICATION_UIDS - ? RADIO_UID : FIRST_APPLICATION_UID, - ApplicationInfo.FLAG_SYSTEM); - - String separateProcesses = SystemProperties.get("debug.separate_processes"); - if (separateProcesses != null && separateProcesses.length() > 0) { - if ("*".equals(separateProcesses)) { - mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES; - mSeparateProcesses = null; - Log.w(TAG, "Running with debug.separate_processes: * (ALL)"); - } else { - mDefParseFlags = 0; - mSeparateProcesses = separateProcesses.split(","); - Log.w(TAG, "Running with debug.separate_processes: " - + separateProcesses); - } - } else { - mDefParseFlags = 0; - mSeparateProcesses = null; - } - - Installer installer = new Installer(); - // Little hacky thing to check if installd is here, to determine - // whether we are running on the simulator and thus need to take - // care of building the /data file structure ourself. - // (apparently the sim now has a working installer) - if (installer.ping() && Process.supportsProcesses()) { - mInstaller = installer; - } else { - mInstaller = null; - } - - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - d.getMetrics(mMetrics); - - synchronized (mInstallLock) { - synchronized (mPackages) { - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); - - File dataDir = Environment.getDataDirectory(); - mAppDataDir = new File(dataDir, "data"); - mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - - if (mInstaller == null) { - // Make sure these dirs exist, when we are running in - // the simulator. - // Make a wide-open directory for random misc stuff. - File miscDir = new File(dataDir, "misc"); - miscDir.mkdirs(); - mAppDataDir.mkdirs(); - mDrmAppPrivateInstallDir.mkdirs(); - } - - readPermissions(); - - mRestoredSettings = mSettings.readLP(); - long startTime = SystemClock.uptimeMillis(); - - EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, - startTime); - - int scanMode = SCAN_MONITOR; - - final HashSet<String> libFiles = new HashSet<String>(); - - mFrameworkDir = new File(Environment.getRootDirectory(), "framework"); - - if (mInstaller != null) { - /** - * Out of paranoia, ensure that everything in the boot class - * path has been dexed. - */ - String bootClassPath = System.getProperty("java.boot.class.path"); - if (bootClassPath != null) { - String[] paths = splitString(bootClassPath, ':'); - for (int i=0; i<paths.length; i++) { - try { - if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) { - libFiles.add(paths[i]); - mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Boot class path not found: " + paths[i]); - } catch (IOException e) { - Log.w(TAG, "Exception reading boot class path: " + paths[i], e); - } - } - } else { - Log.w(TAG, "No BOOTCLASSPATH found!"); - } - - /** - * Also ensure all external libraries have had dexopt run on them. - */ - if (mSharedLibraries.size() > 0) { - Iterator<String> libs = mSharedLibraries.values().iterator(); - while (libs.hasNext()) { - String lib = libs.next(); - try { - if (dalvik.system.DexFile.isDexOptNeeded(lib)) { - libFiles.add(lib); - mInstaller.dexopt(lib, Process.SYSTEM_UID, true); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Library not found: " + lib); - } catch (IOException e) { - Log.w(TAG, "Exception reading library: " + lib, e); - } - } - } - - // Gross hack for now: we know this file doesn't contain any - // code, so don't dexopt it to avoid the resulting log spew. - libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk"); - - /** - * And there are a number of commands implemented in Java, which - * we currently need to do the dexopt on so that they can be - * run from a non-root shell. - */ - String[] frameworkFiles = mFrameworkDir.list(); - if (frameworkFiles != null && mInstaller != null) { - for (int i=0; i<frameworkFiles.length; i++) { - File libPath = new File(mFrameworkDir, frameworkFiles[i]); - String path = libPath.getPath(); - // Skip the file if we alrady did it. - if (libFiles.contains(path)) { - continue; - } - // Skip the file if it is not a type we want to dexopt. - if (!path.endsWith(".apk") && !path.endsWith(".jar")) { - continue; - } - try { - if (dalvik.system.DexFile.isDexOptNeeded(path)) { - mInstaller.dexopt(path, Process.SYSTEM_UID, true); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Jar not found: " + path); - } catch (IOException e) { - Log.w(TAG, "Exception reading jar: " + path, e); - } - } - } - } - - mFrameworkInstallObserver = new AppDirObserver( - mFrameworkDir.getPath(), OBSERVER_EVENTS, true); - mFrameworkInstallObserver.startWatching(); - scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM, - scanMode | SCAN_NO_DEX); - mSystemAppDir = new File(Environment.getRootDirectory(), "app"); - mSystemInstallObserver = new AppDirObserver( - mSystemAppDir.getPath(), OBSERVER_EVENTS, true); - mSystemInstallObserver.startWatching(); - scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode); - mAppInstallDir = new File(dataDir, "app"); - if (mInstaller == null) { - // Make sure these dirs exist, when we are running in - // the simulator. - mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists - } - //look for any incomplete package installations - ArrayList<String> deletePkgsList = mSettings.getListOfIncompleteInstallPackages(); - //clean up list - for(int i = 0; i < deletePkgsList.size(); i++) { - //clean up here - cleanupInstallFailedPackage(deletePkgsList.get(i)); - } - //delete tmp files - deleteTempPackageFiles(); - - EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_DATA_SCAN_START, - SystemClock.uptimeMillis()); - mAppInstallObserver = new AppDirObserver( - mAppInstallDir.getPath(), OBSERVER_EVENTS, false); - mAppInstallObserver.startWatching(); - scanDirLI(mAppInstallDir, 0, scanMode); - - mDrmAppInstallObserver = new AppDirObserver( - mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); - mDrmAppInstallObserver.startWatching(); - scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode); - - EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SCAN_END, - SystemClock.uptimeMillis()); - Log.i(TAG, "Time to scan packages: " - + ((SystemClock.uptimeMillis()-startTime)/1000f) - + " seconds"); - - updatePermissionsLP(); - - mSettings.writeLP(); - - EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_READY, - SystemClock.uptimeMillis()); - - // Now after opening every single application zip, make sure they - // are all flushed. Not really needed, but keeps things nice and - // tidy. - Runtime.getRuntime().gc(); - } // synchronized (mPackages) - } // synchronized (mInstallLock) - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) { - Log.e(TAG, "Package Manager Crash", e); - } - throw e; - } - } - - void cleanupInstallFailedPackage(String packageName) { - if (mInstaller != null) { - int retCode = mInstaller.remove(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove app data directory for package: " - + packageName + ", retcode=" + retCode); - } - } else { - //for emulator - PackageParser.Package pkg = mPackages.get(packageName); - File dataDir = new File(pkg.applicationInfo.dataDir); - dataDir.delete(); - } - mSettings.removePackageLP(packageName); - } - - void readPermissions() { - // Read permissions from .../etc/permission directory. - File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions"); - if (!libraryDir.exists() || !libraryDir.isDirectory()) { - Log.w(TAG, "No directory " + libraryDir + ", skipping"); - return; - } - if (!libraryDir.canRead()) { - Log.w(TAG, "Directory " + libraryDir + " cannot be read"); - return; - } - - // Iterate over the files in the directory and scan .xml files - for (File f : libraryDir.listFiles()) { - // We'll read platform.xml last - if (f.getPath().endsWith("etc/permissions/platform.xml")) { - continue; - } - - if (!f.getPath().endsWith(".xml")) { - Log.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); - continue; - } - if (!f.canRead()) { - Log.w(TAG, "Permissions library file " + f + " cannot be read"); - continue; - } - - readPermissionsFromXml(f); - } - - // Read permissions from .../etc/permissions/platform.xml last so it will take precedence - final File permFile = new File(Environment.getRootDirectory(), - "etc/permissions/platform.xml"); - readPermissionsFromXml(permFile); - } - - private void readPermissionsFromXml(File permFile) { - FileReader permReader = null; - try { - permReader = new FileReader(permFile); - } catch (FileNotFoundException e) { - Log.w(TAG, "Couldn't find or open permissions file " + permFile); - return; - } - - try { - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(permReader); - - XmlUtils.beginDocument(parser, "permissions"); - - while (true) { - XmlUtils.nextElement(parser); - if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { - break; - } - - String name = parser.getName(); - if ("group".equals(name)) { - String gidStr = parser.getAttributeValue(null, "gid"); - if (gidStr != null) { - int gid = Integer.parseInt(gidStr); - mGlobalGids = appendInt(mGlobalGids, gid); - } else { - Log.w(TAG, "<group> without gid at " - + parser.getPositionDescription()); - } - - XmlUtils.skipCurrentTag(parser); - continue; - } else if ("permission".equals(name)) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Log.w(TAG, "<permission> without name at " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - readPermission(parser, perm); - - } else if ("assign-permission".equals(name)) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Log.w(TAG, "<assign-permission> without name at " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - String uidStr = parser.getAttributeValue(null, "uid"); - if (uidStr == null) { - Log.w(TAG, "<assign-permission> without uid at " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - int uid = Process.getUidForName(uidStr); - if (uid < 0) { - Log.w(TAG, "<assign-permission> with unknown uid \"" - + uidStr + "\" at " - + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - HashSet<String> perms = mSystemPermissions.get(uid); - if (perms == null) { - perms = new HashSet<String>(); - mSystemPermissions.put(uid, perms); - } - perms.add(perm); - XmlUtils.skipCurrentTag(parser); - - } else if ("library".equals(name)) { - String lname = parser.getAttributeValue(null, "name"); - String lfile = parser.getAttributeValue(null, "file"); - if (lname == null) { - Log.w(TAG, "<library> without name at " - + parser.getPositionDescription()); - } else if (lfile == null) { - Log.w(TAG, "<library> without file at " - + parser.getPositionDescription()); - } else { - Log.i(TAG, "Got library " + lname + " in " + lfile); - this.mSharedLibraries.put(lname, lfile); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else { - XmlUtils.skipCurrentTag(parser); - continue; - } - - } - } catch (XmlPullParserException e) { - Log.w(TAG, "Got execption parsing permissions.", e); - } catch (IOException e) { - Log.w(TAG, "Got execption parsing permissions.", e); - } - } - - void readPermission(XmlPullParser parser, String name) - throws IOException, XmlPullParserException { - - name = name.intern(); - - BasePermission bp = mSettings.mPermissions.get(name); - if (bp == null) { - bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN); - mSettings.mPermissions.put(name, bp); - } - 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 ("group".equals(tagName)) { - String gidStr = parser.getAttributeValue(null, "gid"); - if (gidStr != null) { - int gid = Process.getGidForName(gidStr); - bp.gids = appendInt(bp.gids, gid); - } else { - Log.w(TAG, "<group> without gid at " - + parser.getPositionDescription()); - } - } - XmlUtils.skipCurrentTag(parser); - } - } - - static int[] appendInt(int[] cur, int val) { - if (cur == null) { - return new int[] { val }; - } - final int N = cur.length; - for (int i=0; i<N; i++) { - if (cur[i] == val) { - return cur; - } - } - int[] ret = new int[N+1]; - System.arraycopy(cur, 0, ret, 0, N); - ret[N] = val; - return ret; - } - - static int[] appendInts(int[] cur, int[] add) { - if (add == null) return cur; - if (cur == null) return add; - final int N = add.length; - for (int i=0; i<N; i++) { - cur = appendInt(cur, add[i]); - } - return cur; - } - - PackageInfo generatePackageInfo(PackageParser.Package p, int flags) { - final PackageSetting ps = (PackageSetting)p.mExtras; - if (ps == null) { - return null; - } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - return PackageParser.generatePackageInfo(p, gp.gids, flags); - } - - public PackageInfo getPackageInfo(String packageName, int flags) { - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( - TAG, "getApplicationInfo " + packageName - + ": " + p); - if (p != null) { - return generatePackageInfo(p, flags); - } - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - return generatePackageInfoFromSettingsLP(packageName, flags); - } - } - return null; - } - - public int getPackageUid(String packageName) { - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if(p != null) { - return p.applicationInfo.uid; - } - PackageSetting ps = mSettings.mPackages.get(packageName); - if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { - return -1; - } - p = ps.pkg; - return p != null ? p.applicationInfo.uid : -1; - } - } - - public int[] getPackageGids(String packageName) { - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( - TAG, "getApplicationInfo " + packageName - + ": " + p); - if (p != null) { - final PackageSetting ps = (PackageSetting)p.mExtras; - final SharedUserSetting suid = ps.sharedUser; - return suid != null ? suid.gids : ps.gids; - } - } - // stupid thing to indicate an error. - return new int[0]; - } - - public PermissionInfo getPermissionInfo(String name, int flags) { - synchronized (mPackages) { - final BasePermission p = mSettings.mPermissions.get(name); - if (p != null && p.perm != null) { - return PackageParser.generatePermissionInfo(p.perm, flags); - } - return null; - } - } - - public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) { - synchronized (mPackages) { - ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); - for (BasePermission p : mSettings.mPermissions.values()) { - if (group == null) { - if (p.perm.info.group == null) { - out.add(PackageParser.generatePermissionInfo(p.perm, flags)); - } - } else { - if (group.equals(p.perm.info.group)) { - out.add(PackageParser.generatePermissionInfo(p.perm, flags)); - } - } - } - - if (out.size() > 0) { - return out; - } - return mPermissionGroups.containsKey(group) ? out : null; - } - } - - public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { - synchronized (mPackages) { - return PackageParser.generatePermissionGroupInfo( - mPermissionGroups.get(name), flags); - } - } - - public List<PermissionGroupInfo> getAllPermissionGroups(int flags) { - synchronized (mPackages) { - final int N = mPermissionGroups.size(); - ArrayList<PermissionGroupInfo> out - = new ArrayList<PermissionGroupInfo>(N); - for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) { - out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); - } - return out; - } - } - - private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) { - PackageSetting ps = mSettings.mPackages.get(packageName); - if(ps != null) { - if(ps.pkg == null) { - PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags); - if(pInfo != null) { - return pInfo.applicationInfo; - } - return null; - } - return PackageParser.generateApplicationInfo(ps.pkg, flags); - } - return null; - } - - private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) { - PackageSetting ps = mSettings.mPackages.get(packageName); - if(ps != null) { - if(ps.pkg == null) { - ps.pkg = new PackageParser.Package(packageName); - ps.pkg.applicationInfo.packageName = packageName; - } - return generatePackageInfo(ps.pkg, flags); - } - return null; - } - - public ApplicationInfo getApplicationInfo(String packageName, int flags) { - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if (Config.LOGV) Log.v( - TAG, "getApplicationInfo " + packageName - + ": " + p); - if (p != null) { - // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo(p, flags); - } - if ("android".equals(packageName)||"system".equals(packageName)) { - return mAndroidApplication; - } - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - return generateApplicationInfoFromSettingsLP(packageName, flags); - } - } - return null; - } - - - public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CLEAR_APP_CACHE, null); - // Queue up an async operation since clearing cache may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - int retCode = -1; - if (mInstaller != null) { - retCode = mInstaller.freeCache(freeStorageSize); - if (retCode < 0) { - Log.w(TAG, "Couldn't clear application caches"); - } - } //end if mInstaller - if (observer != null) { - try { - observer.onRemoveCompleted(null, (retCode >= 0)); - } catch (RemoteException e) { - Log.w(TAG, "RemoveException when invoking call back"); - } - } - } - }); - } - - public void freeStorage(final long freeStorageSize, final PendingIntent opFinishedIntent) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CLEAR_APP_CACHE, null); - // Queue up an async operation since clearing cache may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - int retCode = -1; - if (mInstaller != null) { - retCode = mInstaller.freeCache(freeStorageSize); - if (retCode < 0) { - Log.w(TAG, "Couldn't clear application caches"); - } - } - if(opFinishedIntent != null) { - try { - // Callback via pending intent - opFinishedIntent.send((retCode >= 0) ? 1 : 0); - } catch (CanceledException e1) { - Log.i(TAG, "Failed to send pending intent"); - } - } - } - }); - } - - public ActivityInfo getActivityInfo(ComponentName component, int flags) { - synchronized (mPackages) { - PackageParser.Activity a = mActivities.mActivities.get(component); - if (Config.LOGV) Log.v( - TAG, "getActivityInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledLP(a.info, flags)) { - return PackageParser.generateActivityInfo(a, flags); - } - if (mResolveComponentName.equals(component)) { - return mResolveActivity; - } - } - return null; - } - - public ActivityInfo getReceiverInfo(ComponentName component, int flags) { - synchronized (mPackages) { - PackageParser.Activity a = mReceivers.mActivities.get(component); - if (Config.LOGV) Log.v( - TAG, "getReceiverInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledLP(a.info, flags)) { - return PackageParser.generateActivityInfo(a, flags); - } - } - return null; - } - - public ServiceInfo getServiceInfo(ComponentName component, int flags) { - synchronized (mPackages) { - PackageParser.Service s = mServices.mServices.get(component); - if (Config.LOGV) Log.v( - TAG, "getServiceInfo " + component + ": " + s); - if (s != null && mSettings.isEnabledLP(s.info, flags)) { - return PackageParser.generateServiceInfo(s, flags); - } - } - return null; - } - - public String[] getSystemSharedLibraryNames() { - Set<String> 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) { - PackageParser.Package p = mPackages.get(pkgName); - if (p != null && p.mExtras != null) { - PackageSetting ps = (PackageSetting)p.mExtras; - if (ps.sharedUser != null) { - if (ps.sharedUser.grantedPermissions.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } else if (ps.grantedPermissions.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } - } - return PackageManager.PERMISSION_DENIED; - } - - public int checkUidPermission(String permName, int uid) { - synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); - if (obj != null) { - if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; - if (sus.grantedPermissions.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; - if (ps.grantedPermissions.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } - } else { - HashSet<String> perms = mSystemPermissions.get(uid); - if (perms != null && perms.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } - } - return PackageManager.PERMISSION_DENIED; - } - - private BasePermission findPermissionTreeLP(String permName) { - for(BasePermission bp : mSettings.mPermissionTrees.values()) { - if (permName.startsWith(bp.name) && - permName.length() > bp.name.length() && - permName.charAt(bp.name.length()) == '.') { - return bp; - } - } - return null; - } - - private BasePermission checkPermissionTreeLP(String permName) { - if (permName != null) { - BasePermission bp = findPermissionTreeLP(permName); - if (bp != null) { - if (bp.uid == Binder.getCallingUid()) { - return bp; - } - throw new SecurityException("Calling uid " - + Binder.getCallingUid() - + " is not allowed to add to permission tree " - + bp.name + " owned by uid " + bp.uid); - } - } - throw new SecurityException("No permission tree found for " + permName); - } - - public boolean addPermission(PermissionInfo info) { - synchronized (mPackages) { - if (info.labelRes == 0 && info.nonLocalizedLabel == null) { - throw new SecurityException("Label must be specified in permission"); - } - BasePermission tree = checkPermissionTreeLP(info.name); - BasePermission bp = mSettings.mPermissions.get(info.name); - boolean added = bp == null; - if (added) { - bp = new BasePermission(info.name, tree.sourcePackage, - BasePermission.TYPE_DYNAMIC); - } else if (bp.type != BasePermission.TYPE_DYNAMIC) { - throw new SecurityException( - "Not allowed to modify non-dynamic permission " - + info.name); - } - bp.perm = new PackageParser.Permission(tree.perm.owner, - new PermissionInfo(info)); - bp.perm.info.packageName = tree.perm.info.packageName; - bp.uid = tree.uid; - if (added) { - mSettings.mPermissions.put(info.name, bp); - } - mSettings.writeLP(); - return added; - } - } - - public void removePermission(String name) { - synchronized (mPackages) { - checkPermissionTreeLP(name); - BasePermission bp = mSettings.mPermissions.get(name); - if (bp != null) { - if (bp.type != BasePermission.TYPE_DYNAMIC) { - throw new SecurityException( - "Not allowed to modify non-dynamic permission " - + name); - } - mSettings.mPermissions.remove(name); - mSettings.writeLP(); - } - } - } - - public int checkSignatures(String pkg1, String pkg2) { - synchronized (mPackages) { - PackageParser.Package p1 = mPackages.get(pkg1); - PackageParser.Package p2 = mPackages.get(pkg2); - if (p1 == null || p1.mExtras == null - || p2 == null || p2.mExtras == null) { - return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; - } - return checkSignaturesLP(p1, p2); - } - } - - int checkSignaturesLP(PackageParser.Package p1, PackageParser.Package p2) { - if (p1.mSignatures == null) { - return p2.mSignatures == null - ? PackageManager.SIGNATURE_NEITHER_SIGNED - : PackageManager.SIGNATURE_FIRST_NOT_SIGNED; - } - if (p2.mSignatures == null) { - return PackageManager.SIGNATURE_SECOND_NOT_SIGNED; - } - final int N1 = p1.mSignatures.length; - final int N2 = p2.mSignatures.length; - for (int i=0; i<N1; i++) { - boolean match = false; - for (int j=0; j<N2; j++) { - if (p1.mSignatures[i].equals(p2.mSignatures[j])) { - match = true; - break; - } - } - if (!match) { - return PackageManager.SIGNATURE_NO_MATCH; - } - } - return PackageManager.SIGNATURE_MATCH; - } - - public String[] getPackagesForUid(int uid) { - synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); - if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; - final int N = sus.packages.size(); - String[] res = new String[N]; - Iterator<PackageSetting> it = sus.packages.iterator(); - int i=0; - while (it.hasNext()) { - res[i++] = it.next().name; - } - return res; - } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; - return new String[] { ps.name }; - } - } - return null; - } - - public String getNameForUid(int uid) { - synchronized (mPackages) { - Object obj = mSettings.getUserIdLP(uid); - if (obj instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting)obj; - return sus.name + ":" + sus.userId; - } else if (obj instanceof PackageSetting) { - PackageSetting ps = (PackageSetting)obj; - return ps.name; - } - } - return null; - } - - public int getUidForSharedUser(String sharedUserName) { - if(sharedUserName == null) { - return -1; - } - synchronized (mPackages) { - SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false); - if(suid == null) { - return -1; - } - return suid.userId; - } - } - - public ResolveInfo resolveIntent(Intent intent, String resolvedType, - int flags) { - List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags); - if (query != null) { - final int N = query.size(); - if (N == 1) { - return query.get(0); - } else if (N > 1) { - // If there is more than one activity with the same priority, - // then let the user decide between them. - ResolveInfo r0 = query.get(0); - ResolveInfo r1 = query.get(1); - if (false) { - System.out.println(r0.activityInfo.name + - "=" + r0.priority + " vs " + - r1.activityInfo.name + - "=" + r1.priority); - } - // If the first activity has a higher priority, or a different - // default, then it is always desireable to pick it. - if (r0.priority != r1.priority - || r0.preferredOrder != r1.preferredOrder - || r0.isDefault != r1.isDefault) { - return query.get(0); - } - // If we have saved a preference for a preferred activity for - // this Intent, use that. - ResolveInfo ri = findPreferredActivity(intent, resolvedType, - flags, query, r0.priority); - if (ri != null) { - return ri; - } - return mResolveInfo; - } - } - return null; - } - - ResolveInfo findPreferredActivity(Intent intent, String resolvedType, - int flags, List<ResolveInfo> query, int priority) { - synchronized (mPackages) { - if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); - List<PreferredActivity> prefs = - mSettings.mPreferredActivities.queryIntent(null, - intent, resolvedType, - (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); - if (prefs != null && prefs.size() > 0) { - // First figure out how good the original match set is. - // We will only allow preferred activities that came - // from the same match quality. - int match = 0; - final int N = query.size(); - if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match..."); - for (int j=0; j<N; j++) { - ResolveInfo ri = query.get(j); - if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo - + ": 0x" + Integer.toHexString(match)); - if (ri.match > match) match = ri.match; - } - if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x" - + Integer.toHexString(match)); - match &= IntentFilter.MATCH_CATEGORY_MASK; - final int M = prefs.size(); - for (int i=0; i<M; i++) { - PreferredActivity pa = prefs.get(i); - if (pa.mMatch != match) { - continue; - } - ActivityInfo ai = getActivityInfo(pa.mActivity, flags); - if (DEBUG_PREFERRED) { - Log.v(TAG, "Got preferred activity:"); - ai.dump(new LogPrinter(Log.INFO, TAG), " "); - } - if (ai != null) { - for (int j=0; j<N; j++) { - ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - - // Okay we found a previously set preferred app. - // If the result set is different from when this - // was created, we need to clear it and re-ask the - // user their preference. - if (!pa.sameSet(query, priority)) { - Log.i(TAG, "Result set changed, dropping preferred activity for " - + intent + " type " + resolvedType); - mSettings.mPreferredActivities.removeFilter(pa); - return null; - } - - // Yay! - return ri; - } - } - } - } - } - return null; - } - - public List<ResolveInfo> queryIntentActivities(Intent intent, - String resolvedType, int flags) { - ComponentName comp = intent.getComponent(); - if (comp != null) { - List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - ActivityInfo ai = getActivityInfo(comp, flags); - if (ai != null) { - ResolveInfo ri = new ResolveInfo(); - ri.activityInfo = ai; - list.add(ri); - } - return list; - } - - synchronized (mPackages) { - return (List<ResolveInfo>)mActivities. - queryIntent(null, intent, resolvedType, flags); - } - } - - public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, - Intent[] specifics, String[] specificTypes, Intent intent, - String resolvedType, int flags) { - final String resultsAction = intent.getAction(); - - List<ResolveInfo> results = queryIntentActivities( - intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER); - if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results); - - int specificsPos = 0; - int N; - - // todo: note that the algorithm used here is O(N^2). This - // isn't a problem in our current environment, but if we start running - // into situations where we have more than 5 or 10 matches then this - // should probably be changed to something smarter... - - // First we go through and resolve each of the specific items - // that were supplied, taking care of removing any corresponding - // duplicate items in the generic resolve list. - if (specifics != null) { - for (int i=0; i<specifics.length; i++) { - final Intent sintent = specifics[i]; - if (sintent == null) { - continue; - } - - if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent); - String action = sintent.getAction(); - if (resultsAction != null && resultsAction.equals(action)) { - // If this action was explicitly requested, then don't - // remove things that have it. - action = null; - } - ComponentName comp = sintent.getComponent(); - ResolveInfo ri = null; - ActivityInfo ai = null; - if (comp == null) { - ri = resolveIntent( - sintent, - specificTypes != null ? specificTypes[i] : null, - flags); - if (ri == null) { - continue; - } - if (ri == mResolveInfo) { - // ACK! Must do something better with this. - } - ai = ri.activityInfo; - comp = new ComponentName(ai.applicationInfo.packageName, - ai.name); - } else { - ai = getActivityInfo(comp, flags); - if (ai == null) { - continue; - } - } - - // Look for any generic query activities that are duplicates - // of this specific one, and remove them from the results. - if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai); - N = results.size(); - int j; - for (j=specificsPos; j<N; j++) { - ResolveInfo sri = results.get(j); - if ((sri.activityInfo.name.equals(comp.getClassName()) - && sri.activityInfo.applicationInfo.packageName.equals( - comp.getPackageName())) - || (action != null && sri.filter.matchAction(action))) { - results.remove(j); - if (Config.LOGV) Log.v( - TAG, "Removing duplicate item from " + j - + " due to specific " + specificsPos); - if (ri == null) { - ri = sri; - } - j--; - N--; - } - } - - // Add this specific item to its proper place. - if (ri == null) { - ri = new ResolveInfo(); - ri.activityInfo = ai; - } - results.add(specificsPos, ri); - ri.specificIndex = i; - specificsPos++; - } - } - - // Now we go through the remaining generic results and remove any - // duplicate actions that are found here. - N = results.size(); - for (int i=specificsPos; i<N-1; i++) { - final ResolveInfo rii = results.get(i); - if (rii.filter == null) { - continue; - } - - // Iterate over all of the actions of this result's intent - // filter... typically this should be just one. - final Iterator<String> it = rii.filter.actionsIterator(); - if (it == null) { - continue; - } - while (it.hasNext()) { - final String action = it.next(); - if (resultsAction != null && resultsAction.equals(action)) { - // If this action was explicitly requested, then don't - // remove things that have it. - continue; - } - for (int j=i+1; j<N; j++) { - final ResolveInfo rij = results.get(j); - if (rij.filter != null && rij.filter.hasAction(action)) { - results.remove(j); - if (Config.LOGV) Log.v( - TAG, "Removing duplicate item from " + j - + " due to action " + action + " at " + i); - j--; - N--; - } - } - } - - // If the caller didn't request filter information, drop it now - // so we don't have to marshall/unmarshall it. - if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) { - rii.filter = null; - } - } - - // Filter out the caller activity if so requested. - if (caller != null) { - N = results.size(); - for (int i=0; i<N; i++) { - ActivityInfo ainfo = results.get(i).activityInfo; - if (caller.getPackageName().equals(ainfo.applicationInfo.packageName) - && caller.getClassName().equals(ainfo.name)) { - results.remove(i); - break; - } - } - } - - // If the caller didn't request filter information, - // drop them now so we don't have to - // marshall/unmarshall it. - if ((flags&PackageManager.GET_RESOLVED_FILTER) == 0) { - N = results.size(); - for (int i=0; i<N; i++) { - results.get(i).filter = null; - } - } - - if (Config.LOGV) Log.v(TAG, "Result: " + results); - return results; - } - - public List<ResolveInfo> queryIntentReceivers(Intent intent, - String resolvedType, int flags) { - synchronized (mPackages) { - return (List<ResolveInfo>)mReceivers. - queryIntent(null, intent, resolvedType, flags); - } - } - - public ResolveInfo resolveService(Intent intent, String resolvedType, - int flags) { - List<ResolveInfo> query = queryIntentServices(intent, resolvedType, - flags); - if (query != null) { - if (query.size() >= 1) { - // If there is more than one service with the same priority, - // just arbitrarily pick the first one. - return query.get(0); - } - } - return null; - } - - public List<ResolveInfo> queryIntentServices(Intent intent, - String resolvedType, int flags) { - ComponentName comp = intent.getComponent(); - if (comp != null) { - List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - ServiceInfo si = getServiceInfo(comp, flags); - if (si != null) { - ResolveInfo ri = new ResolveInfo(); - ri.serviceInfo = si; - list.add(ri); - } - return list; - } - - synchronized (mPackages) { - return (List<ResolveInfo>)mServices. - queryIntent(null, intent, resolvedType, flags); - } - } - - public List<PackageInfo> getInstalledPackages(int flags) { - ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>(); - - synchronized (mPackages) { - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); - while (i.hasNext()) { - final PackageSetting ps = i.next(); - PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags); - if(psPkg != null) { - finalList.add(psPkg); - } - } - } - else { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - PackageInfo pi = generatePackageInfo(p, flags); - if(pi != null) { - finalList.add(pi); - } - } - } - } - } - return finalList; - } - - public List<ApplicationInfo> getInstalledApplications(int flags) { - ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); - synchronized(mPackages) { - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator<PackageSetting> i = mSettings.mPackages.values().iterator(); - while (i.hasNext()) { - final PackageSetting ps = i.next(); - ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags); - if(ai != null) { - finalList.add(ai); - } - } - } - else { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags); - if(ai != null) { - finalList.add(ai); - } - } - } - } - } - return finalList; - } - - public List<ApplicationInfo> getPersistentApplications(int flags) { - ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); - - synchronized (mPackages) { - Iterator<PackageParser.Package> i = mPackages.values().iterator(); - while (i.hasNext()) { - PackageParser.Package p = i.next(); - if (p.applicationInfo != null - && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 - && (!mSafeMode || (p.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { - finalList.add(p.applicationInfo); - } - } - } - - return finalList; - } - - public ProviderInfo resolveContentProvider(String name, int flags) { - synchronized (mPackages) { - final PackageParser.Provider provider = mProviders.get(name); - return provider != null - && mSettings.isEnabledLP(provider.info, flags) - && (!mSafeMode || (provider.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0) - ? PackageParser.generateProviderInfo(provider, flags) - : null; - } - } - - public void querySyncProviders(List outNames, List outInfo) { - synchronized (mPackages) { - Iterator<Map.Entry<String, PackageParser.Provider>> i - = mProviders.entrySet().iterator(); - - while (i.hasNext()) { - Map.Entry<String, PackageParser.Provider> entry = i.next(); - PackageParser.Provider p = entry.getValue(); - - if (p.syncable - && (!mSafeMode || (p.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { - outNames.add(entry.getKey()); - outInfo.add(PackageParser.generateProviderInfo(p, 0)); - } - } - } - } - - public List<ProviderInfo> queryContentProviders(String processName, - int uid, int flags) { - ArrayList<ProviderInfo> finalList = null; - - synchronized (mPackages) { - Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator(); - while (i.hasNext()) { - PackageParser.Provider p = i.next(); - if (p.info.authority != null - && (processName == null || - (p.info.processName.equals(processName) - && p.info.applicationInfo.uid == uid)) - && mSettings.isEnabledLP(p.info, flags) - && (!mSafeMode || (p.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { - if (finalList == null) { - finalList = new ArrayList<ProviderInfo>(3); - } - finalList.add(PackageParser.generateProviderInfo(p, - flags)); - } - } - } - - if (finalList != null) { - Collections.sort(finalList, mProviderInitOrderSorter); - } - - return finalList; - } - - public InstrumentationInfo getInstrumentationInfo(ComponentName name, - int flags) { - synchronized (mPackages) { - final PackageParser.Instrumentation i = mInstrumentation.get(name); - return PackageParser.generateInstrumentationInfo(i, flags); - } - } - - public List<InstrumentationInfo> queryInstrumentation(String targetPackage, - int flags) { - ArrayList<InstrumentationInfo> finalList = - new ArrayList<InstrumentationInfo>(); - - synchronized (mPackages) { - Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator(); - while (i.hasNext()) { - PackageParser.Instrumentation p = i.next(); - if (targetPackage == null - || targetPackage.equals(p.info.targetPackage)) { - finalList.add(PackageParser.generateInstrumentationInfo(p, - flags)); - } - } - } - - return finalList; - } - - private void scanDirLI(File dir, int flags, int scanMode) { - Log.d(TAG, "Scanning app dir " + dir); - - String[] files = dir.list(); - - int i; - for (i=0; i<files.length; i++) { - File file = new File(dir, files[i]); - PackageParser.Package pkg = scanPackageLI(file, file, file, - flags|PackageParser.PARSE_MUST_BE_APK, scanMode); - } - } - - private static void reportSettingsProblem(int priority, String msg) { - try { - File dataDir = Environment.getDataDirectory(); - File systemDir = new File(dataDir, "system"); - File fname = new File(systemDir, "uiderrors.txt"); - FileOutputStream out = new FileOutputStream(fname, true); - PrintWriter pw = new PrintWriter(out); - pw.println(msg); - pw.close(); - FileUtils.setPermissions( - fname.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH, - -1, -1); - } catch (java.io.IOException e) { - } - Log.println(priority, TAG, msg); - } - - private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps, - PackageParser.Package pkg, File srcFile, int parseFlags) { - if (GET_CERTIFICATES) { - if (ps == null || !ps.codePath.equals(srcFile) - || ps.getTimeStamp() != srcFile.lastModified()) { - Log.i(TAG, srcFile.toString() + " changed; collecting certs"); - if (!pp.collectCertificates(pkg, parseFlags)) { - mLastScanError = pp.getParseError(); - return false; - } - } - } - return true; - } - - /* - * Scan a package and return the newly parsed package. - * Returns null in case of errors and the error code is stored in mLastScanError - */ - private PackageParser.Package scanPackageLI(File scanFile, - File destCodeFile, File destResourceFile, int parseFlags, - int scanMode) { - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - parseFlags |= mDefParseFlags; - PackageParser pp = new PackageParser(scanFile.getPath()); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setSdkVersion(mSdkVersion); - final PackageParser.Package pkg = pp.parsePackage(scanFile, - destCodeFile.getAbsolutePath(), mMetrics, parseFlags); - if (pkg == null) { - mLastScanError = pp.getParseError(); - return null; - } - PackageSetting ps; - PackageSetting updatedPkg; - synchronized (mPackages) { - ps = mSettings.peekPackageLP(pkg.packageName, - scanFile.toString()); - updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName); - } - if (updatedPkg != null) { - // An updated system app will not have the PARSE_IS_SYSTEM flag set initially - parseFlags |= PackageParser.PARSE_IS_SYSTEM; - } - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { - // Check for updated system applications here - if ((updatedPkg != null) && (ps == null)) { - // The system package has been updated and the code path does not match - // Ignore entry. Just return - Log.w(TAG, "Package:" + pkg.packageName + - " has been updated. Ignoring the one from path:"+scanFile); - mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; - return null; - } - } - if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) { - Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName); - return null; - } - // The apk is forward locked (not public) if its code and resources - // are kept in different files. - if (ps != null && !ps.codePath.equals(ps.resourcePath)) { - scanMode |= SCAN_FORWARD_LOCKED; - } - // Note that we invoke the following method only if we are about to unpack an application - return scanPackageLI(scanFile, destCodeFile, destResourceFile, - pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); - } - - private static String fixProcessName(String defProcessName, - String processName, int uid) { - if (processName == null) { - return defProcessName; - } - return processName; - } - - private boolean verifySignaturesLP(PackageSetting pkgSetting, - PackageParser.Package pkg, int parseFlags, boolean updateSignature) { - if (pkg.mSignatures != null) { - if (!pkgSetting.signatures.updateSignatures(pkg.mSignatures, - updateSignature)) { - Log.e(TAG, "Package " + pkg.packageName - + " signatures do not match the previously installed version; ignoring!"); - mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; - return false; - } - - if (pkgSetting.sharedUser != null) { - if (!pkgSetting.sharedUser.signatures.mergeSignatures( - pkg.mSignatures, updateSignature)) { - Log.e(TAG, "Package " + pkg.packageName - + " has no signatures that match those in shared user " - + pkgSetting.sharedUser.name + "; ignoring!"); - mLastScanError = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; - return false; - } - } - } else { - pkg.mSignatures = pkgSetting.signatures.mSignatures; - } - return true; - } - - private PackageParser.Package scanPackageLI( - File scanFile, File destCodeFile, File destResourceFile, - PackageParser.Package pkg, int parseFlags, int scanMode) { - - mScanningPath = scanFile; - if (pkg == null) { - mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; - return null; - } - - final String pkgName = pkg.applicationInfo.packageName; - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - } - - if (pkgName.equals("android")) { - synchronized (mPackages) { - if (mAndroidApplication != null) { - Log.w(TAG, "*************************************************"); - Log.w(TAG, "Core android package being redefined. Skipping."); - Log.w(TAG, " file=" + mScanningPath); - Log.w(TAG, "*************************************************"); - mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; - return null; - } - - // Set up information for our fall-back user intent resolution - // activity. - mPlatformPackage = pkg; - pkg.mVersionCode = mSdkVersion; - mAndroidApplication = pkg.applicationInfo; - mResolveActivity.applicationInfo = mAndroidApplication; - mResolveActivity.name = ResolverActivity.class.getName(); - mResolveActivity.packageName = mAndroidApplication.packageName; - mResolveActivity.processName = mAndroidApplication.processName; - mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; - mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert; - mResolveActivity.exported = true; - mResolveActivity.enabled = true; - mResolveInfo.activityInfo = mResolveActivity; - mResolveInfo.priority = 0; - mResolveInfo.preferredOrder = 0; - mResolveInfo.match = 0; - mResolveComponentName = new ComponentName( - mAndroidApplication.packageName, mResolveActivity.name); - } - } - - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d( - TAG, "Scanning package " + pkgName); - if (mPackages.containsKey(pkgName) || mSharedLibraries.containsKey(pkgName)) { - Log.w(TAG, "*************************************************"); - Log.w(TAG, "Application package " + pkgName - + " already installed. Skipping duplicate."); - Log.w(TAG, "*************************************************"); - mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; - return null; - } - - SharedUserSetting suid = null; - PackageSetting pkgSetting = null; - - boolean removeExisting = false; - - synchronized (mPackages) { - // Check all shared libraries and map to their actual file path. - if (pkg.usesLibraryFiles != null) { - for (int i=0; i<pkg.usesLibraryFiles.length; i++) { - String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]); - if (file == null) { - Log.e(TAG, "Package " + pkg.packageName - + " requires unavailable shared library " - + pkg.usesLibraryFiles[i] + "; ignoring!"); - mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; - return null; - } - pkg.usesLibraryFiles[i] = file; - } - } - - if (pkg.mSharedUserId != null) { - suid = mSettings.getSharedUserLP(pkg.mSharedUserId, - pkg.applicationInfo.flags, true); - if (suid == null) { - Log.w(TAG, "Creating application package " + pkgName - + " for shared user failed"); - mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return null; - } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) { - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" - + suid.userId + "): packages=" + suid.packages); - } - } - - pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile, - destResourceFile, pkg.applicationInfo.flags, true); - if (pkgSetting == null) { - Log.w(TAG, "Creating application package " + pkgName + " failed"); - mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return null; - } - synchronized(mPackages) { - if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - } - } - - pkg.applicationInfo.uid = pkgSetting.userId; - pkg.mExtras = pkgSetting; - - if (!verifySignaturesLP(pkgSetting, pkg, parseFlags, - (scanMode&SCAN_UPDATE_SIGNATURE) != 0)) { - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) { - mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; - return null; - } - // The signature has changed, but this package is in the system - // image... let's recover! - pkg.mSignatures = pkgSetting.signatures.mSignatures; - // However... if this package is part of a shared user, but it - // doesn't match the signature of the shared user, let's fail. - // What this means is that you can't change the signatures - // associated with an overall shared user, which doesn't seem all - // that unreasonable. - if (pkgSetting.sharedUser != null) { - if (!pkgSetting.sharedUser.signatures.mergeSignatures( - pkg.mSignatures, false)) { - mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; - return null; - } - } - removeExisting = true; - } - } - - if (removeExisting) { - if (mInstaller != null) { - int ret = mInstaller.remove(pkgName); - if (ret != 0) { - String msg = "System package " + pkg.packageName - + " could not have data directory erased after signature change."; - reportSettingsProblem(Log.WARN, msg); - mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; - return null; - } - } - Log.w(TAG, "System package " + pkg.packageName - + " signature changed: existing data removed."); - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - } - - long scanFileTime = scanFile.lastModified(); - final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0; - final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp(); - - // At this point we know it is okay to accept the package, though - // errors can still happen as we try to install... - - if ((scanMode&SCAN_MONITOR) != 0) { - pkg.mPath = destCodeFile.getAbsolutePath(); - mAppDirs.put(pkg.mPath, pkg); - } - pkg.applicationInfo.processName = fixProcessName( - pkg.applicationInfo.packageName, - pkg.applicationInfo.processName, - pkg.applicationInfo.uid); - pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString; - - synchronized (mPackages) { - mPackages.put(pkg.applicationInfo.packageName, pkg); - } - - File dataPath; - if (mPlatformPackage == pkg) { - // The system package is special. - dataPath = new File (Environment.getDataDirectory(), "system"); - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { - // This is a normal package, need to make its data directory. - dataPath = new File(mAppDataDir, pkgName); - if (dataPath.exists()) { - mOutPermissions[1] = 0; - FileUtils.getPermissions(dataPath.getPath(), mOutPermissions); - if (mOutPermissions[1] == pkg.applicationInfo.uid - || !Process.supportsProcesses()) { - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { - boolean recovered = false; - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { - // If this is a system app, we can at least delete its - // current data so the application will still work. - if (mInstaller != null) { - int ret = mInstaller.remove(pkgName); - if(ret >= 0) { - // Old data gone! - String msg = "System package " + pkg.packageName - + " has changed from uid: " - + mOutPermissions[1] + " to " - + pkg.applicationInfo.uid + "; old data erased"; - reportSettingsProblem(Log.WARN, msg); - recovered = true; - - // And now re-install the app. - ret = mInstaller.install(pkgName, pkg.applicationInfo.uid, - pkg.applicationInfo.uid); - if (ret == -1) { - // Ack should not happen! - msg = "System package " + pkg.packageName - + " could not have data directory re-created after delete."; - reportSettingsProblem(Log.WARN, msg); - mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return null; - } - } - - } - if (!recovered) { - mHasSystemUidErrors = true; - } - } - if (!recovered) { - pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" - + pkg.applicationInfo.uid + "/fs_" - + mOutPermissions[1]; - String msg = "Package " + pkg.packageName - + " has mismatched uid: " - + mOutPermissions[1] + " on disk, " - + pkg.applicationInfo.uid + " in settings"; - synchronized (mPackages) { - if (!mReportedUidError) { - mReportedUidError = true; - msg = msg + "; read messages:\n" - + mSettings.getReadMessagesLP(); - } - reportSettingsProblem(Log.ERROR, msg); - } - } - } - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV) - Log.v(TAG, "Want this data dir: " + dataPath); - //invoke installer to do the actual installation - if (mInstaller != null) { - int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid, - pkg.applicationInfo.uid); - if(ret < 0) { - //error from installer - mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return null; - } - } else { - dataPath.mkdirs(); - if (dataPath.exists()) { - FileUtils.setPermissions( - dataPath.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, - pkg.applicationInfo.uid, pkg.applicationInfo.uid); - } - } - if (dataPath.exists()) { - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { - Log.w(TAG, "Unable to create data directory: " + dataPath); - pkg.applicationInfo.dataDir = null; - } - } - } - - // Perform shared library installation and dex validation and - // optimization, if this is not a system app. - if (mInstaller != null) { - String path = scanFile.getPath(); - if (scanFileNewer) { - Log.i(TAG, path + " changed; unpacking"); - try { - cachePackageSharedLibsLI(pkg, dataPath, scanFile); - } catch (IOException e) { - Log.e(TAG, "Failure extracting shared libs", e); - if(mInstaller != null) { - mInstaller.remove(pkgName); - } else { - dataPath.delete(); - } - mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return null; - } - } - - if ((scanMode&SCAN_NO_DEX) == 0 - && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - int ret = 0; - try { - if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) { - ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, - (scanMode&SCAN_FORWARD_LOCKED) == 0); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Apk not found for dexopt: " + path); - ret = -1; - } catch (IOException e) { - Log.w(TAG, "Exception reading apk: " + path, e); - ret = -1; - } - if (ret < 0) { - //error from installer - mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT; - return null; - } - } - } - - if (mFactoryTest && pkg.requestedPermissions.contains( - android.Manifest.permission.FACTORY_TEST)) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST; - } - - synchronized (mPackages) { - - int N = pkg.providers.size(); - StringBuilder r = null; - int i; - for (i=0; i<N; i++) { - PackageParser.Provider p = pkg.providers.get(i); - p.info.processName = fixProcessName(pkg.applicationInfo.processName, - p.info.processName, pkg.applicationInfo.uid); - mProvidersByComponent.put(new ComponentName(p.info.packageName, - p.info.name), p); - p.syncable = p.info.isSyncable; - String names[] = p.info.authority.split(";"); - p.info.authority = null; - for (int j = 0; j < names.length; j++) { - if (j == 1 && p.syncable) { - // We only want the first authority for a provider to possibly be - // syncable, so if we already added this provider using a different - // authority clear the syncable flag. We copy the provider before - // changing it because the mProviders object contains a reference - // to a provider that we don't want to change. - // Only do this for the second authority since the resulting provider - // object can be the same for all future authorities for this provider. - p = new PackageParser.Provider(p); - p.syncable = false; - } - if (!mProviders.containsKey(names[j])) { - mProviders.put(names[j], p); - if (p.info.authority == null) { - p.info.authority = names[j]; - } else { - p.info.authority = p.info.authority + ";" + names[j]; - } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) - Log.d(TAG, "Registered content provider: " + names[j] + - ", className = " + p.info.name + - ", isSyncable = " + p.info.isSyncable); - } else { - Log.w(TAG, "Skipping provider name " + names[j] + - " (in package " + pkg.applicationInfo.packageName + - "): name already used"); - } - } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Providers: " + r); - } - - N = pkg.services.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Service s = pkg.services.get(i); - s.info.processName = fixProcessName(pkg.applicationInfo.processName, - s.info.processName, pkg.applicationInfo.uid); - mServices.addService(s); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(s.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Services: " + r); - } - - N = pkg.receivers.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName, pkg.applicationInfo.uid); - mReceivers.addActivity(a, "receiver"); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Receivers: " + r); - } - - N = pkg.activities.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.activities.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName, pkg.applicationInfo.uid); - mActivities.addActivity(a, "activity"); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Activities: " + r); - } - - N = pkg.permissionGroups.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); - PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); - if (cur == null) { - mPermissionGroups.put(pg.info.name, pg); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(pg.info.name); - } - } else { - Log.w(TAG, "Permission group " + pg.info.name + " from package " - + pg.info.packageName + " ignored: original from " - + cur.info.packageName); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append("DUP:"); - r.append(pg.info.name); - } - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r); - } - - N = pkg.permissions.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - HashMap<String, BasePermission> permissionMap = - p.tree ? mSettings.mPermissionTrees - : mSettings.mPermissions; - p.group = mPermissionGroups.get(p.info.group); - if (p.info.group == null || p.group != null) { - BasePermission bp = permissionMap.get(p.info.name); - if (bp == null) { - bp = new BasePermission(p.info.name, p.info.packageName, - BasePermission.TYPE_NORMAL); - permissionMap.put(p.info.name, bp); - } - if (bp.perm == null) { - if (bp.sourcePackage == null - || bp.sourcePackage.equals(p.info.packageName)) { - BasePermission tree = findPermissionTreeLP(p.info.name); - if (tree == null - || tree.sourcePackage.equals(p.info.packageName)) { - bp.perm = p; - bp.uid = pkg.applicationInfo.uid; - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } else { - Log.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: base tree " - + tree.name + " is from package " - + tree.sourcePackage); - } - } else { - Log.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: original from " - + bp.sourcePackage); - } - } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append("DUP:"); - r.append(p.info.name); - } - } else { - Log.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: no group " - + p.group); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permissions: " + r); - } - - N = pkg.instrumentation.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); - a.info.packageName = pkg.applicationInfo.packageName; - a.info.sourceDir = pkg.applicationInfo.sourceDir; - a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; - a.info.dataDir = pkg.applicationInfo.dataDir; - mInstrumentation.put(a.component, a); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r); - } - - pkgSetting.setTimeStamp(scanFileTime); - } - - return pkg; - } - - private void cachePackageSharedLibsLI(PackageParser.Package pkg, - File dataPath, File scanFile) throws IOException { - File sharedLibraryDir = new File(dataPath.getPath() + "/lib"); - final String sharedLibraryABI = "armeabi"; - final String apkLibraryDirectory = "lib/" + sharedLibraryABI + "/"; - final String apkSharedLibraryPrefix = apkLibraryDirectory + "lib"; - final String sharedLibrarySuffix = ".so"; - boolean createdSharedLib = false; - try { - ZipFile zipFile = new ZipFile(scanFile); - Enumeration<ZipEntry> entries = - (Enumeration<ZipEntry>) zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - if (! (entryName.startsWith(apkSharedLibraryPrefix) - && entryName.endsWith(sharedLibrarySuffix))) { - continue; - } - String libFileName = entryName.substring( - apkLibraryDirectory.length()); - if (libFileName.contains("/") - || (!FileUtils.isFilenameSafe(new File(libFileName)))) { - continue; - } - String sharedLibraryFilePath = sharedLibraryDir.getPath() + - File.separator + libFileName; - File sharedLibraryFile = new File(sharedLibraryFilePath); - if (! sharedLibraryFile.exists() || - sharedLibraryFile.length() != entry.getSize() || - sharedLibraryFile.lastModified() != entry.getTime()) { - if (Config.LOGD) { - Log.d(TAG, "Caching shared lib " + entry.getName()); - } - if (mInstaller == null) { - sharedLibraryDir.mkdir(); - createdSharedLib = true; - } - cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir, - sharedLibraryFile); - } - } - } catch (IOException e) { - Log.e(TAG, "Failed to cache package shared libs", e); - if(createdSharedLib) { - sharedLibraryDir.delete(); - } - throw e; - } - } - - private void cacheSharedLibLI(PackageParser.Package pkg, - ZipFile zipFile, ZipEntry entry, - File sharedLibraryDir, - File sharedLibraryFile) throws IOException { - InputStream inputStream = zipFile.getInputStream(entry); - try { - File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir); - String tempFilePath = tempFile.getPath(); - // XXX package manager can't change owner, so the lib files for - // now need to be left as world readable and owned by the system. - if (! FileUtils.copyToFile(inputStream, tempFile) || - ! tempFile.setLastModified(entry.getTime()) || - FileUtils.setPermissions(tempFilePath, - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IROTH, -1, -1) != 0 || - ! tempFile.renameTo(sharedLibraryFile)) { - // Failed to properly write file. - tempFile.delete(); - throw new IOException("Couldn't create cached shared lib " - + sharedLibraryFile + " in " + sharedLibraryDir); - } - } finally { - inputStream.close(); - } - } - - void removePackageLI(PackageParser.Package pkg, boolean chatty) { - if (chatty && Config.LOGD) Log.d( - TAG, "Removing package " + pkg.applicationInfo.packageName ); - - synchronized (mPackages) { - if (pkg.mPreferredOrder > 0) { - mSettings.mPreferredPackages.remove(pkg); - pkg.mPreferredOrder = 0; - updatePreferredIndicesLP(); - } - - clearPackagePreferredActivitiesLP(pkg.packageName); - - mPackages.remove(pkg.applicationInfo.packageName); - if (pkg.mPath != null) { - mAppDirs.remove(pkg.mPath); - } - - PackageSetting ps = (PackageSetting)pkg.mExtras; - if (ps != null && ps.sharedUser != null) { - // XXX don't do this until the data is removed. - if (false) { - ps.sharedUser.packages.remove(ps); - if (ps.sharedUser.packages.size() == 0) { - // Remove. - } - } - } - - int N = pkg.providers.size(); - StringBuilder r = null; - int i; - for (i=0; i<N; i++) { - PackageParser.Provider p = pkg.providers.get(i); - mProvidersByComponent.remove(new ComponentName(p.info.packageName, - p.info.name)); - if (p.info.authority == null) { - - /* The is another ContentProvider with this authority when - * this app was installed so this authority is null, - * Ignore it as we don't have to unregister the provider. - */ - continue; - } - String names[] = p.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - if (mProviders.get(names[j]) == p) { - mProviders.remove(names[j]); - if (chatty && Config.LOGD) Log.d( - TAG, "Unregistered content provider: " + names[j] + - ", className = " + p.info.name + - ", isSyncable = " + p.info.isSyncable); - } - } - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Providers: " + r); - } - - N = pkg.services.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Service s = pkg.services.get(i); - mServices.removeService(s); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(s.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Services: " + r); - } - - N = pkg.receivers.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - mReceivers.removeActivity(a, "receiver"); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Receivers: " + r); - } - - N = pkg.activities.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Activity a = pkg.activities.get(i); - mActivities.removeActivity(a, "activity"); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Activities: " + r); - } - - N = pkg.permissions.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - boolean tree = false; - BasePermission bp = mSettings.mPermissions.get(p.info.name); - if (bp == null) { - tree = true; - bp = mSettings.mPermissionTrees.get(p.info.name); - } - if (bp != null && bp.perm == p) { - if (bp.type != BasePermission.TYPE_BUILTIN) { - if (tree) { - mSettings.mPermissionTrees.remove(p.info.name); - } else { - mSettings.mPermissions.remove(p.info.name); - } - } else { - bp.perm = null; - } - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Permissions: " + r); - } - - N = pkg.instrumentation.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); - mInstrumentation.remove(a.component); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(a.info.name); - } - } - if (r != null) { - if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r); - } - } - } - - private static final boolean isPackageFilename(String name) { - return name != null && name.endsWith(".apk"); - } - - private void updatePermissionsLP() { - // Make sure there are no dangling permission trees. - Iterator<BasePermission> it = mSettings.mPermissionTrees - .values().iterator(); - while (it.hasNext()) { - BasePermission bp = it.next(); - if (bp.perm == null) { - Log.w(TAG, "Removing dangling permission tree: " + bp.name - + " from package " + bp.sourcePackage); - it.remove(); - } - } - - // Make sure all dynamic permissions have been assigned to a package, - // and make sure there are no dangling permissions. - it = mSettings.mPermissions.values().iterator(); - while (it.hasNext()) { - BasePermission bp = it.next(); - if (bp.type == BasePermission.TYPE_DYNAMIC) { - if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" - + bp.name + " pkg=" + bp.sourcePackage - + " info=" + bp.pendingInfo); - if (bp.perm == null && bp.pendingInfo != null) { - BasePermission tree = findPermissionTreeLP(bp.name); - if (tree != null) { - bp.perm = new PackageParser.Permission(tree.perm.owner, - new PermissionInfo(bp.pendingInfo)); - bp.perm.info.packageName = tree.perm.info.packageName; - bp.perm.info.name = bp.name; - bp.uid = tree.uid; - } - } - } - if (bp.perm == null) { - Log.w(TAG, "Removing dangling permission: " + bp.name - + " from package " + bp.sourcePackage); - it.remove(); - } - } - - // Now update the permissions for all packages, in particular - // replace the granted permissions of the system packages. - for (PackageParser.Package pkg : mPackages.values()) { - grantPermissionsLP(pkg, false); - } - } - - private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) { - final PackageSetting ps = (PackageSetting)pkg.mExtras; - if (ps == null) { - return; - } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - boolean addedPermission = false; - - if (replace) { - ps.permissionsFixed = false; - if (gp == ps) { - gp.grantedPermissions.clear(); - gp.gids = mGlobalGids; - } - } - - if (gp.gids == null) { - gp.gids = mGlobalGids; - } - - final int N = pkg.requestedPermissions.size(); - for (int i=0; i<N; i++) { - String name = pkg.requestedPermissions.get(i); - BasePermission bp = mSettings.mPermissions.get(name); - PackageParser.Permission p = bp != null ? bp.perm : null; - if (false) { - if (gp != ps) { - Log.i(TAG, "Package " + pkg.packageName + " checking " + name - + ": " + p); - } - } - if (p != null) { - final String perm = p.info.name; - boolean allowed; - if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL - || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { - allowed = true; - } else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE - || p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - allowed = (checkSignaturesLP(p.owner, pkg) - == PackageManager.SIGNATURE_MATCH) - || (checkSignaturesLP(mPlatformPackage, pkg) - == PackageManager.SIGNATURE_MATCH); - if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - // 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 { - allowed = false; - } - if (false) { - if (gp != ps) { - Log.i(TAG, "Package " + pkg.packageName + " granting " + perm); - } - } - if (allowed) { - if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.permissionsFixed) { - // If this is an existing, non-system package, then - // we can't add any new permissions to it. - if (!gp.loadedPermissions.contains(perm)) { - allowed = false; - } - } - if (allowed) { - if (!gp.grantedPermissions.contains(perm)) { - addedPermission = true; - gp.grantedPermissions.add(perm); - gp.gids = appendInts(gp.gids, bp.gids); - } - } else { - Log.w(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName - + " because it was previously installed without"); - } - } else { - Log.w(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName - + " (protectionLevel=" + p.info.protectionLevel - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) - + ")"); - } - } else { - Log.w(TAG, "Unknown permission " + name - + " in package " + pkg.packageName); - } - } - - if ((addedPermission || replace) && !ps.permissionsFixed && - (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - // This is the first that we have heard about this package, so the - // permissions we have now selected are fixed until explicitly - // changed. - ps.permissionsFixed = true; - gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions); - } - } - - private final class ActivityIntentResolver - extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { - mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(resolver, intent, resolvedType, defaultOnly); - } - - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, int flags) { - mFlags = flags; - return super.queryIntent( - resolver, intent, resolvedType, - (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); - } - - public final void addActivity(PackageParser.Activity a, String type) { - mActivities.put(a.component, a); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + type + " " + - (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name); - int NI = a.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if (SHOW_INFO || Config.LOGV) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - if (!intent.debugCheck()) { - Log.w(TAG, "==> For Activity " + a.info.name); - } - addFilter(intent); - } - } - - public final void removeActivity(PackageParser.Activity a, String type) { - mActivities.remove(a.component); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + type + " " + - (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name); - int NI = a.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); - if (SHOW_INFO || Config.LOGV) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - removeFilter(intent); - } - } - - @Override - protected boolean allowFilterResult( - PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) { - ActivityInfo filterAi = filter.activity.info; - for (int i=dest.size()-1; i>=0; i--) { - ActivityInfo destAi = dest.get(i).activityInfo; - if (destAi.name == filterAi.name - && destAi.packageName == filterAi.packageName) { - return false; - } - } - return true; - } - - @Override - protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, - int match) { - if (!mSettings.isEnabledLP(info.activity.info, mFlags)) { - return null; - } - final PackageParser.Activity activity = info.activity; - if (mSafeMode && (activity.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) == 0) { - return null; - } - final ResolveInfo res = new ResolveInfo(); - res.activityInfo = PackageParser.generateActivityInfo(activity, - mFlags); - if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { - res.filter = info; - } - res.priority = info.getPriority(); - res.preferredOrder = activity.owner.mPreferredOrder; - //System.out.println("Result: " + res.activityInfo.className + - // " = " + res.priority); - res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; - return res; - } - - @Override - protected void sortResults(List<ResolveInfo> results) { - Collections.sort(results, mResolvePrioritySorter); - } - - @Override - protected void dumpFilter(Printer out, String prefix, - PackageParser.ActivityIntentInfo filter) { - out.println(prefix - + Integer.toHexString(System.identityHashCode(filter.activity)) - + " " + filter.activity.component.flattenToShortString()); - } - -// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { -// final Iterator<ResolveInfo> i = resolveInfoList.iterator(); -// final List<ResolveInfo> retList = Lists.newArrayList(); -// while (i.hasNext()) { -// final ResolveInfo resolveInfo = i.next(); -// if (isEnabledLP(resolveInfo.activityInfo)) { -// retList.add(resolveInfo); -// } -// } -// return retList; -// } - - // Keys are String (activity class name), values are Activity. - private final HashMap<ComponentName, PackageParser.Activity> mActivities - = new HashMap<ComponentName, PackageParser.Activity>(); - private int mFlags; - } - - private final class ServiceIntentResolver - extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, boolean defaultOnly) { - mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(resolver, intent, resolvedType, defaultOnly); - } - - public List queryIntent(ContentResolver resolver, Intent intent, - String resolvedType, int flags) { - mFlags = flags; - return super.queryIntent( - resolver, intent, resolvedType, - (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); - } - - public final void addService(PackageParser.Service s) { - mServices.put(s.component, s); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " Class=" + s.info.name); - int NI = s.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (SHOW_INFO || Config.LOGV) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - if (!intent.debugCheck()) { - Log.w(TAG, "==> For Service " + s.info.name); - } - addFilter(intent); - } - } - - public final void removeService(PackageParser.Service s) { - mServices.remove(s.component); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " " + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - if (SHOW_INFO || Config.LOGV) Log.v( - TAG, " Class=" + s.info.name); - int NI = s.intents.size(); - int j; - for (j=0; j<NI; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); - if (SHOW_INFO || Config.LOGV) { - Log.v(TAG, " IntentFilter:"); - intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); - } - removeFilter(intent); - } - } - - @Override - protected boolean allowFilterResult( - PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) { - ServiceInfo filterSi = filter.service.info; - for (int i=dest.size()-1; i>=0; i--) { - ServiceInfo destAi = dest.get(i).serviceInfo; - if (destAi.name == filterSi.name - && destAi.packageName == filterSi.packageName) { - return false; - } - } - return true; - } - - @Override - protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, - int match) { - final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; - if (!mSettings.isEnabledLP(info.service.info, mFlags)) { - return null; - } - final PackageParser.Service service = info.service; - if (mSafeMode && (service.info.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) == 0) { - return null; - } - final ResolveInfo res = new ResolveInfo(); - res.serviceInfo = PackageParser.generateServiceInfo(service, - mFlags); - if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { - res.filter = filter; - } - res.priority = info.getPriority(); - res.preferredOrder = service.owner.mPreferredOrder; - //System.out.println("Result: " + res.activityInfo.className + - // " = " + res.priority); - res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; - return res; - } - - @Override - protected void sortResults(List<ResolveInfo> results) { - Collections.sort(results, mResolvePrioritySorter); - } - - @Override - protected void dumpFilter(Printer out, String prefix, - PackageParser.ServiceIntentInfo filter) { - out.println(prefix - + Integer.toHexString(System.identityHashCode(filter.service)) - + " " + filter.service.component.flattenToShortString()); - } - -// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { -// final Iterator<ResolveInfo> i = resolveInfoList.iterator(); -// final List<ResolveInfo> retList = Lists.newArrayList(); -// while (i.hasNext()) { -// final ResolveInfo resolveInfo = (ResolveInfo) i; -// if (isEnabledLP(resolveInfo.serviceInfo)) { -// retList.add(resolveInfo); -// } -// } -// return retList; -// } - - // Keys are String (activity class name), values are Activity. - private final HashMap<ComponentName, PackageParser.Service> mServices - = new HashMap<ComponentName, PackageParser.Service>(); - private int mFlags; - }; - - private static final Comparator<ResolveInfo> mResolvePrioritySorter = - new Comparator<ResolveInfo>() { - public int compare(ResolveInfo r1, ResolveInfo r2) { - int v1 = r1.priority; - int v2 = r2.priority; - //System.out.println("Comparing: q1=" + q1 + " q2=" + q2); - if (v1 != v2) { - return (v1 > v2) ? -1 : 1; - } - v1 = r1.preferredOrder; - v2 = r2.preferredOrder; - if (v1 != v2) { - return (v1 > v2) ? -1 : 1; - } - if (r1.isDefault != r2.isDefault) { - return r1.isDefault ? -1 : 1; - } - v1 = r1.match; - v2 = r2.match; - //System.out.println("Comparing: m1=" + m1 + " m2=" + m2); - return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0); - } - }; - - private static final Comparator<ProviderInfo> mProviderInitOrderSorter = - new Comparator<ProviderInfo>() { - public int compare(ProviderInfo p1, ProviderInfo p2) { - final int v1 = p1.initOrder; - final int v2 = p2.initOrder; - return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0); - } - }; - - private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) { - IActivityManager am = ActivityManagerNative.getDefault(); - if (am != null) { - try { - final Intent intent = new Intent(action, - pkg != null ? Uri.fromParts("package", pkg, null) : null); - if (extras != null) { - intent.putExtras(extras); - } - am.broadcastIntent( - null, intent, - null, null, 0, null, null, null, false, false); - } catch (RemoteException ex) { - } - } - } - - private final class AppDirObserver extends FileObserver { - public AppDirObserver(String path, int mask, boolean isrom) { - super(path, mask); - mRootDir = path; - mIsRom = isrom; - } - - public void onEvent(int event, String path) { - String removedPackage = null; - int removedUid = -1; - String addedPackage = null; - int addedUid = -1; - - synchronized (mInstallLock) { - String fullPathStr = null; - File fullPath = null; - if (path != null) { - fullPath = new File(mRootDir, path); - fullPathStr = fullPath.getPath(); - } - - if (Config.LOGV) Log.v( - TAG, "File " + fullPathStr + " changed: " - + Integer.toHexString(event)); - - if (!isPackageFilename(path)) { - if (Config.LOGV) Log.v( - TAG, "Ignoring change of non-package file: " + fullPathStr); - return; - } - - if ((event&REMOVE_EVENTS) != 0) { - synchronized (mInstallLock) { - PackageParser.Package p = mAppDirs.get(fullPathStr); - if (p != null) { - removePackageLI(p, true); - removedPackage = p.applicationInfo.packageName; - removedUid = p.applicationInfo.uid; - } - } - } - - if ((event&ADD_EVENTS) != 0) { - PackageParser.Package p = mAppDirs.get(fullPathStr); - if (p == null) { - p = scanPackageLI(fullPath, fullPath, fullPath, - (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) | - PackageParser.PARSE_CHATTY | - PackageParser.PARSE_MUST_BE_APK, - SCAN_MONITOR); - if (p != null) { - synchronized (mPackages) { - grantPermissionsLP(p, false); - } - addedPackage = p.applicationInfo.packageName; - addedUid = p.applicationInfo.uid; - } - } - } - - synchronized (mPackages) { - mSettings.writeLP(); - } - } - - 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) { - Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, addedUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras); - } - } - - private final String mRootDir; - private final boolean mIsRom; - } - - /* Called when a downloaded package installation has been confirmed by the user */ - public void installPackage( - final Uri packageURI, final IPackageInstallObserver observer, final int flags) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.INSTALL_PACKAGES, null); - - // Queue up an async operation since the package installation may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - PackageInstalledInfo res; - synchronized (mInstallLock) { - res = installPackageLI(packageURI, flags); - } - if (observer != null) { - try { - observer.packageInstalled(res.name, res.returnCode); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } - // 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(false, true); - Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, res.uid); - if (res.removedInfo.removedPackage != null) { - extras.putBoolean(Intent.EXTRA_REPLACING, true); - } - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, - res.pkg.applicationInfo.packageName, - extras); - } - Runtime.getRuntime().gc(); - } - }); - } - - class PackageInstalledInfo { - String name; - int uid; - PackageParser.Package pkg; - int returnCode; - PackageRemovedInfo removedInfo; - } - - /* - * Install a non-existing package. - */ - private void installNewPackageLI(String pkgName, int parseFlags, - File tmpPackageFile, - String destFilePath, File destPackageFile, File destResourceFile, - PackageParser.Package pkg, boolean forwardLocked, - PackageInstalledInfo res) { - // Remember this for later, in case we need to rollback this install - boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists(); - res.name = pkgName; - synchronized(mPackages) { - if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) { - // Don't allow installation over an existing package with the same name. - Log.w(TAG, "Attempt to re-install " + pkgName - + " without first uninstalling."); - res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; - return; - } - } - if (destPackageFile.exists()) { - // It's safe to do this because we know (from the above check) that the file - // isn't currently used for an installed package. - destPackageFile.delete(); - } - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile, - destResourceFile, pkg, parseFlags, - SCAN_MONITOR | SCAN_FORCE_DEX - | SCAN_UPDATE_SIGNATURE - | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); - if (newPackage == null) { - Log.w(TAG, "Package couldn't be installed in " + destPackageFile); - if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; - } - } else { - updateSettingsLI(pkgName, tmpPackageFile, - destFilePath, destPackageFile, - destResourceFile, pkg, - newPackage, - true, - forwardLocked, - res); - // delete the partially installed application. the data directory will have to be - // restored if it was already existing - if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { - // remove package from internal structures. Note that we want deletePackageX to - // delete the package data and cache directories that it created in - // scanPackageLocked, unless those directories existed before we even tried to - // install. - deletePackageLI( - pkgName, true, - dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, - res.removedInfo); - } - } - } - - private void replacePackageLI(String pkgName, int parseFlags, - File tmpPackageFile, - String destFilePath, File destPackageFile, File destResourceFile, - PackageParser.Package pkg, boolean forwardLocked, - PackageInstalledInfo res) { - PackageParser.Package deletedPackage; - // First find the old package info and check signatures - synchronized(mPackages) { - deletedPackage = mPackages.get(pkgName); - if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) { - res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; - return; - } - } - boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); - if(sysPkg) { - replaceSystemPackageLI(deletedPackage, - parseFlags, - tmpPackageFile, destFilePath, - destPackageFile, destResourceFile, pkg, forwardLocked, res); - } else { - replaceNonSystemPackageLI(deletedPackage, parseFlags, tmpPackageFile, destFilePath, - destPackageFile, destResourceFile, pkg, forwardLocked, res); - } - } - - private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, - File tmpPackageFile, - String destFilePath, File destPackageFile, File destResourceFile, - PackageParser.Package pkg, boolean forwardLocked, - PackageInstalledInfo res) { - PackageParser.Package newPackage = null; - String pkgName = deletedPackage.packageName; - boolean deletedPkg = true; - boolean updatedSettings = false; - // First delete the existing package while retaining the data directory - if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA, - res.removedInfo)) { - // If the existing package was'nt successfully deleted - res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; - deletedPkg = false; - } else { - // Successfully deleted the old package. Now proceed with re-installation - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - newPackage = scanPackageLI(tmpPackageFile, destPackageFile, - destResourceFile, pkg, parseFlags, - SCAN_MONITOR | SCAN_FORCE_DEX - | SCAN_UPDATE_SIGNATURE - | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); - if (newPackage == null) { - Log.w(TAG, "Package couldn't be installed in " + destPackageFile); - if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; - } - } else { - updateSettingsLI(pkgName, tmpPackageFile, - destFilePath, destPackageFile, - destResourceFile, pkg, - newPackage, - true, - forwardLocked, - res); - updatedSettings = true; - } - } - - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - // If we deleted an exisiting package, the old source and resource files that we - // were keeping around in case we needed them (see below) can now be deleted - final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo; - final ApplicationInfo installedPackageAppInfo = - newPackage.applicationInfo; - if (!deletedPackageAppInfo.sourceDir - .equals(installedPackageAppInfo.sourceDir)) { - new File(deletedPackageAppInfo.sourceDir).delete(); - } - if (!deletedPackageAppInfo.publicSourceDir - .equals(installedPackageAppInfo.publicSourceDir)) { - new File(deletedPackageAppInfo.publicSourceDir).delete(); - } - //update signature on the new package setting - //this should always succeed, since we checked the - //signature earlier. - synchronized(mPackages) { - verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg, - parseFlags, true); - } - } else { - // remove package from internal structures. Note that we want deletePackageX to - // delete the package data and cache directories that it created in - // scanPackageLocked, unless those directories existed before we even tried to - // install. - if(updatedSettings) { - deletePackageLI( - pkgName, true, - PackageManager.DONT_DELETE_DATA, - res.removedInfo); - } - // Since we failed to install the new package we need to restore the old - // package that we deleted. - if(deletedPkg) { - installPackageLI( - Uri.fromFile(new File(deletedPackage.mPath)), - isForwardLocked(deletedPackage) - ? PackageManager.FORWARD_LOCK_PACKAGE - : 0); - } - } - } - - private void replaceSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags, - File tmpPackageFile, - String destFilePath, File destPackageFile, File destResourceFile, - PackageParser.Package pkg, boolean forwardLocked, - PackageInstalledInfo res) { - PackageParser.Package newPackage = null; - boolean updatedSettings = false; - parseFlags |= PackageParser.PARSE_IS_SYSTEM; - String packageName = deletedPackage.packageName; - res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); - return; - } - PackageParser.Package oldPkg; - PackageSetting oldPkgSetting; - synchronized (mPackages) { - oldPkg = mPackages.get(packageName); - oldPkgSetting = mSettings.mPackages.get(packageName); - if((oldPkg == null) || (oldPkg.applicationInfo == null) || - (oldPkgSetting == null)) { - Log.w(TAG, "Could'nt find package:"+packageName+" information"); - return; - } - } - res.removedInfo.uid = oldPkg.applicationInfo.uid; - res.removedInfo.removedPackage = packageName; - // Remove existing system package - removePackageLI(oldPkg, true); - synchronized (mPackages) { - res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName); - } - - // Successfully disabled the old package. Now proceed with re-installation - mLastScanError = PackageManager.INSTALL_SUCCEEDED; - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - newPackage = scanPackageLI(tmpPackageFile, destPackageFile, - destResourceFile, pkg, parseFlags, - SCAN_MONITOR | SCAN_FORCE_DEX - | SCAN_UPDATE_SIGNATURE - | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); - if (newPackage == null) { - Log.w(TAG, "Package couldn't be installed in " + destPackageFile); - if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; - } - } else { - updateSettingsLI(packageName, tmpPackageFile, - destFilePath, destPackageFile, - destResourceFile, pkg, - newPackage, - true, - forwardLocked, - res); - updatedSettings = true; - } - - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - //update signature on the new package setting - //this should always succeed, since we checked the - //signature earlier. - synchronized(mPackages) { - verifySignaturesLP(mSettings.mPackages.get(packageName), pkg, - parseFlags, true); - } - } else { - // Re installation failed. Restore old information - // Remove new pkg information - removePackageLI(newPackage, true); - // Add back the old system package - scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, - oldPkgSetting.resourcePath, - oldPkg, parseFlags, - SCAN_MONITOR - | SCAN_UPDATE_SIGNATURE - | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)); - // Restore the old system information in Settings - synchronized(mPackages) { - if(updatedSettings) { - mSettings.enableSystemPackageLP(packageName); - } - mSettings.writeLP(); - } - } - } - - private void updateSettingsLI(String pkgName, File tmpPackageFile, - String destFilePath, File destPackageFile, - File destResourceFile, - PackageParser.Package pkg, - PackageParser.Package newPackage, - boolean replacingExistingPackage, - boolean forwardLocked, - PackageInstalledInfo res) { - synchronized (mPackages) { - //write settings. the installStatus will be incomplete at this stage. - //note that the new package setting would have already been - //added to mPackages. It hasn't been persisted yet. - mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE); - mSettings.writeLP(); - } - - int retCode = 0; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - retCode = mInstaller.movedex(tmpPackageFile.toString(), - destPackageFile.toString()); - if (retCode != 0) { - Log.e(TAG, "Couldn't rename dex file: " + destPackageFile); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - return; - } - } - // XXX There are probably some big issues here: upon doing - // the rename, we have reached the point of no return (the - // original .apk is gone!), so we can't fail. Yet... we can. - if (!tmpPackageFile.renameTo(destPackageFile)) { - Log.e(TAG, "Couldn't move package file to: " + destPackageFile); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } else { - res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath, - destResourceFile, - forwardLocked); - if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { - return; - } else { - Log.d(TAG, "New package installed in " + destPackageFile); - } - } - if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) { - if (mInstaller != null) { - mInstaller.rmdex(tmpPackageFile.getPath()); - } - } - - synchronized (mPackages) { - grantPermissionsLP(newPackage, true); - res.name = pkgName; - res.uid = newPackage.applicationInfo.uid; - res.pkg = newPackage; - mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE); - res.returnCode = PackageManager.INSTALL_SUCCEEDED; - //to update install status - mSettings.writeLP(); - } - } - - private PackageInstalledInfo installPackageLI(Uri pPackageURI, int pFlags) { - File tmpPackageFile = null; - String pkgName = null; - boolean forwardLocked = false; - boolean replacingExistingPackage = false; - - // Result object to be returned - PackageInstalledInfo res = new PackageInstalledInfo(); - res.returnCode = PackageManager.INSTALL_SUCCEEDED; - res.uid = -1; - res.pkg = null; - res.removedInfo = new PackageRemovedInfo(); - - main_flow: try { - tmpPackageFile = createTempPackageFile(); - if (tmpPackageFile == null) { - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - tmpPackageFile.deleteOnExit(); // paranoia - if (pPackageURI.getScheme().equals("file")) { - final File srcPackageFile = new File(pPackageURI.getPath()); - // We copy the source package file to a temp file and then rename it to the - // destination file in order to eliminate a window where the package directory - // scanner notices the new package file but it's not completely copied yet. - if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { - Log.e(TAG, "Couldn't copy package file to temp file."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - } else if (pPackageURI.getScheme().equals("content")) { - ParcelFileDescriptor fd; - try { - fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r"); - } catch (FileNotFoundException e) { - Log.e(TAG, "Couldn't open file descriptor from download service."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - if (fd == null) { - Log.e(TAG, "Couldn't open file descriptor from download service (null)."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - if (Config.LOGV) { - Log.v(TAG, "Opened file descriptor from download service."); - } - ParcelFileDescriptor.AutoCloseInputStream - dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd); - // We copy the source package file to a temp file and then rename it to the - // destination file in order to eliminate a window where the package directory - // scanner notices the new package file but it's not completely copied yet. - if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) { - Log.e(TAG, "Couldn't copy package stream to temp file."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - } else { - Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; - break main_flow; - } - pkgName = PackageParser.parsePackageName( - tmpPackageFile.getAbsolutePath(), 0); - if (pkgName == null) { - Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile); - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; - break main_flow; - } - res.name = pkgName; - //initialize some variables before installing pkg - final String pkgFileName = pkgName + ".apk"; - final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) - ? mDrmAppPrivateInstallDir - : mAppInstallDir; - final File destPackageFile = new File(destDir, pkgFileName); - final String destFilePath = destPackageFile.getAbsolutePath(); - File destResourceFile; - if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) { - final String publicZipFileName = pkgName + ".zip"; - destResourceFile = new File(mAppInstallDir, publicZipFileName); - forwardLocked = true; - } else { - destResourceFile = destPackageFile; - } - // Retrieve PackageSettings and parse package - int parseFlags = PackageParser.PARSE_CHATTY; - parseFlags |= mDefParseFlags; - PackageParser pp = new PackageParser(tmpPackageFile.getPath()); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setSdkVersion(mSdkVersion); - final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, - destPackageFile.getAbsolutePath(), mMetrics, parseFlags); - if (pkg == null) { - res.returnCode = pp.getParseError(); - break main_flow; - } - if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { - res.returnCode = pp.getParseError(); - break main_flow; - } - - synchronized (mPackages) { - //check if installing already existing package - if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0 - && mPackages.containsKey(pkgName)) { - replacingExistingPackage = true; - } - } - - if(replacingExistingPackage) { - replacePackageLI(pkgName, pFlags, - tmpPackageFile, - destFilePath, destPackageFile, destResourceFile, - pkg, forwardLocked, - res); - } else { - installNewPackageLI(pkgName, pFlags, - tmpPackageFile, - destFilePath, destPackageFile, destResourceFile, - pkg, forwardLocked, - res); - } - } finally { - if (tmpPackageFile != null && tmpPackageFile.exists()) { - tmpPackageFile.delete(); - } - return res; - } - } - - private int setPermissionsLI(String pkgName, - PackageParser.Package newPackage, - String destFilePath, - File destResourceFile, - boolean forwardLocked) { - int retCode; - if (forwardLocked) { - try { - extractPublicFiles(newPackage, destResourceFile); - } catch (IOException e) { - Log.e(TAG, "Couldn't create a new zip file for the public parts of a" + - " forward-locked app."); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } finally { - //TODO clean up the extracted public files - } - if (mInstaller != null) { - retCode = mInstaller.setForwardLockPerm(pkgName, - newPackage.applicationInfo.uid); - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, - newPackage.applicationInfo.uid); - } - } else { - final int filePermissions = - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IROTH; - retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1); - } - if (retCode != 0) { - Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath - + ". The return code was: " + retCode); - } - return PackageManager.INSTALL_SUCCEEDED; - } - - private boolean isForwardLocked(PackageParser.Package deletedPackage) { - final ApplicationInfo applicationInfo = deletedPackage.applicationInfo; - return applicationInfo.sourceDir.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath()); - } - - private void extractPublicFiles(PackageParser.Package newPackage, - File publicZipFile) throws IOException { - final ZipOutputStream publicZipOutStream = - new ZipOutputStream(new FileOutputStream(publicZipFile)); - final ZipFile privateZip = new ZipFile(newPackage.mPath); - - // Copy manifest, resources.arsc and res directory to public zip - - final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries(); - while (privateZipEntries.hasMoreElements()) { - final ZipEntry zipEntry = privateZipEntries.nextElement(); - final String zipEntryName = zipEntry.getName(); - if ("AndroidManifest.xml".equals(zipEntryName) - || "resources.arsc".equals(zipEntryName) - || zipEntryName.startsWith("res/")) { - try { - copyZipEntry(zipEntry, privateZip, publicZipOutStream); - } catch (IOException e) { - try { - publicZipOutStream.close(); - throw e; - } finally { - publicZipFile.delete(); - } - } - } - } - - publicZipOutStream.close(); - FileUtils.setPermissions( - publicZipFile.getAbsolutePath(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH, - -1, -1); - } - - private static void copyZipEntry(ZipEntry zipEntry, - ZipFile inZipFile, - ZipOutputStream outZipStream) throws IOException { - byte[] buffer = new byte[4096]; - int num; - - ZipEntry newEntry; - if (zipEntry.getMethod() == ZipEntry.STORED) { - // Preserve the STORED method of the input entry. - newEntry = new ZipEntry(zipEntry); - } else { - // Create a new entry so that the compressed len is recomputed. - newEntry = new ZipEntry(zipEntry.getName()); - } - outZipStream.putNextEntry(newEntry); - - InputStream data = inZipFile.getInputStream(zipEntry); - while ((num = data.read(buffer)) > 0) { - outZipStream.write(buffer, 0, num); - } - outZipStream.flush(); - } - - private void deleteTempPackageFiles() { - FilenameFilter filter = new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.startsWith("vmdl") && name.endsWith(".tmp"); - } - }; - String tmpFilesList[] = mAppInstallDir.list(filter); - if(tmpFilesList == null) { - return; - } - for(int i = 0; i < tmpFilesList.length; i++) { - File tmpFile = new File(mAppInstallDir, tmpFilesList[i]); - tmpFile.delete(); - } - } - - private File createTempPackageFile() { - File tmpPackageFile; - try { - tmpPackageFile = File.createTempFile("vmdl", ".tmp", mAppInstallDir); - } catch (IOException e) { - Log.e(TAG, "Couldn't create temp file for downloaded package file."); - return null; - } - try { - FileUtils.setPermissions( - tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR, - -1, -1); - } catch (IOException e) { - Log.e(TAG, "Trouble getting the canoncical path for a temp file."); - return null; - } - return tmpPackageFile; - } - - public void deletePackage(final String packageName, - final IPackageDeleteObserver observer, - final int flags) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.DELETE_PACKAGES, null); - // Queue up an async operation since the package deletion may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - final boolean succeded = deletePackageX(packageName, true, true, flags); - if (observer != null) { - try { - observer.packageDeleted(succeded); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } //end catch - } //end if - } //end run - }); - } - - /** - * This method is an internal method that could be get invoked either - * to delete an installed package or to clean up a failed installation. - * After deleting an installed package, a broadcast is sent to notify any - * listeners that the package has been installed. For cleaning up a failed - * installation, the broadcast is not necessary since the package's - * installation wouldn't have sent the initial broadcast either - * The key steps in deleting a package are - * deleting the package information in internal structures like mPackages, - * deleting the packages base directories through installd - * updating mSettings to reflect current status - * persisting settings for later use - * sending a broadcast if necessary - */ - - private boolean deletePackageX(String packageName, boolean sendBroadCast, - boolean deleteCodeAndResources, int flags) { - PackageRemovedInfo info = new PackageRemovedInfo(); - boolean res = false; - - synchronized (mInstallLock) { - res = deletePackageLI(packageName, deleteCodeAndResources, flags, info); - } - - if(res && sendBroadCast) { - info.sendBroadcast(deleteCodeAndResources, false); - } - return res; - } - - static class PackageRemovedInfo { - String removedPackage; - int uid = -1; - int removedUid = -1; - - 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); - } - if (removedUid >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras); - } - } - } - - /* - * This method deletes the package from internal data structures. If the DONT_DELETE_DATA - * flag is not set, the data directory is removed as well. - * make sure this flag is set for partially installed apps. If not its meaningless to - * delete a partially installed application. - */ - private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo, - int flags) { - String packageName = p.packageName; - outInfo.removedPackage = packageName; - removePackageLI(p, true); - // Retrieve object to delete permissions for shared user later on - PackageSetting deletedPs; - synchronized (mPackages) { - deletedPs = mSettings.mPackages.get(packageName); - } - if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { - if (mInstaller != null) { - int retCode = mInstaller.remove(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove app data or cache directory for package: " - + packageName + ", retcode=" + retCode); - // we don't consider this to be a failure of the core package deletion - } - } else { - //for emulator - PackageParser.Package pkg = mPackages.get(packageName); - File dataDir = new File(pkg.applicationInfo.dataDir); - dataDir.delete(); - } - synchronized (mPackages) { - outInfo.removedUid = mSettings.removePackageLP(packageName); - } - } - synchronized (mPackages) { - if ( (deletedPs != null) && (deletedPs.sharedUser != null)) { - // remove permissions associated with package - mSettings.updateSharedUserPerms (deletedPs); - } - // Save settings now - mSettings.writeLP (); - } - } - - /* - * Tries to delete system package. - */ - private boolean deleteSystemPackageLI(PackageParser.Package p, - boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { - ApplicationInfo applicationInfo = p.applicationInfo; - //applicable for non-partially installed applications only - if (applicationInfo == null) { - Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); - return false; - } - PackageSetting ps = null; - // Confirm if the system package has been updated - // An updated system app can be deleted. This will also have to restore - // the system pkg from system partition - synchronized (mPackages) { - ps = mSettings.getDisabledSystemPkg(p.packageName); - } - if (ps == null) { - Log.w(TAG, "Attempt to delete system package "+ p.packageName); - return false; - } else { - Log.i(TAG, "Deleting system pkg from data partition"); - } - // Delete the updated package - boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo); - if (!ret) { - return false; - } - synchronized (mPackages) { - // Reinstate the old system package - mSettings.enableSystemPackageLP(p.packageName); - } - // Install the system package - PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath, - PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM, - SCAN_MONITOR); - - if (newPkg == null) { - Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError); - return false; - } - synchronized (mPackages) { - mSettings.writeLP(); - } - return true; - } - - private boolean deleteInstalledPackageLI(PackageParser.Package p, - boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { - ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); - return false; - } - // Delete application's source directory - File sourceFile = new File(applicationInfo.sourceDir); - if (!sourceFile.exists()) { - Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist."); - return false; - } - outInfo.uid = applicationInfo.uid; - - // Delete package data from internal structures and also remove data if flag is set - removePackageDataLI(p, outInfo, flags); - - // Delete application code and resources - if (deleteCodeAndResources) { - sourceFile.delete(); - final File publicSourceFile = new File(applicationInfo.publicSourceDir); - if (publicSourceFile.exists()) { - publicSourceFile.delete(); - } - if (mInstaller != null) { - int retCode = mInstaller.rmdex(sourceFile.toString()); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove dex file for package: " - + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode); - // we don't consider this to be a failure of the core package deletion - } - } - } - return true; - } - - /* - * This method handles package deletion in general - */ - private boolean deletePackageLI(String packageName, - boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) { - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); - return false; - } - PackageParser.Package p; - boolean dataOnly = false; - synchronized (mPackages) { - p = mPackages.get(packageName); - if (p == null) { - //this retrieves partially installed apps - dataOnly = true; - PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - p = ps.pkg; - } - } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - - if (dataOnly) { - // Delete application data first - removePackageDataLI(p, outInfo, flags); - return true; - } - // At this point the package should have ApplicationInfo associated with it - if (p.applicationInfo == null) { - Log.w(TAG, "Package " + p.packageName + " has no applicationInfo."); - return false; - } - if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - Log.i(TAG, "Removing system package:"+p.packageName); - // When an updated system application is deleted we delete the existing resources as well and - // fall back to existing code in system partition - return deleteSystemPackageLI(p, true, flags, outInfo); - } - Log.i(TAG, "Removing non-system package:"+p.packageName); - return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo); - } - - public void clearApplicationUserData(final String packageName, - final IPackageDataObserver observer) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CLEAR_APP_USER_DATA, null); - // Queue up an async operation since the package deletion may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - final boolean succeeded; - synchronized (mInstallLock) { - succeeded = clearApplicationUserDataLI(packageName); - } - if (succeeded) { - // invoke DeviceStorageMonitor's update method to clear any notifications - DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) - ServiceManager.getService(DeviceStorageMonitorService.SERVICE); - if (dsm != null) { - dsm.updateMemory(); - } - } - if(observer != null) { - try { - observer.onRemoveCompleted(packageName, succeeded); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } //end if observer - } //end run - }); - } - - private boolean clearApplicationUserDataLI(String packageName) { - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); - return false; - } - PackageParser.Package p; - boolean dataOnly = false; - synchronized (mPackages) { - p = mPackages.get(packageName); - if(p == null) { - dataOnly = true; - PackageSetting ps = mSettings.mPackages.get(packageName); - if((ps == null) || (ps.pkg == null)) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - p = ps.pkg; - } - } - if(!dataOnly) { - //need to check this only for fully installed applications - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; - } - } - if (mInstaller != null) { - int retCode = mInstaller.clearUserData(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove cache files for package: " - + packageName); - return false; - } - } - return true; - } - - public void deleteApplicationCacheFiles(final String packageName, - final IPackageDataObserver observer) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.DELETE_CACHE_FILES, null); - // Queue up an async operation since the package deletion may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - final boolean succeded; - synchronized (mInstallLock) { - succeded = deleteApplicationCacheFilesLI(packageName); - } - if(observer != null) { - try { - observer.onRemoveCompleted(packageName, succeded); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } //end if observer - } //end run - }); - } - - private boolean deleteApplicationCacheFilesLI(String packageName) { - if (packageName == null) { - Log.w(TAG, "Attempt to delete null packageName."); - return false; - } - PackageParser.Package p; - synchronized (mPackages) { - p = mPackages.get(packageName); - } - if (p == null) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; - } - if (mInstaller != null) { - int retCode = mInstaller.deleteCacheFiles(packageName); - if (retCode < 0) { - Log.w(TAG, "Couldn't remove cache files for package: " - + packageName); - return false; - } - } - return true; - } - - public void getPackageSizeInfo(final String packageName, - final IPackageStatsObserver observer) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.GET_PACKAGE_SIZE, null); - // Queue up an async operation since the package deletion may take a little while. - mHandler.post(new Runnable() { - public void run() { - mHandler.removeCallbacks(this); - PackageStats lStats = new PackageStats(packageName); - final boolean succeded; - synchronized (mInstallLock) { - succeded = getPackageSizeInfoLI(packageName, lStats); - } - if(observer != null) { - try { - observer.onGetStatsCompleted(lStats, succeded); - } catch (RemoteException e) { - Log.i(TAG, "Observer no longer exists."); - } - } //end if observer - } //end run - }); - } - - private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) { - if (packageName == null) { - Log.w(TAG, "Attempt to get size of null packageName."); - return false; - } - PackageParser.Package p; - boolean dataOnly = false; - synchronized (mPackages) { - p = mPackages.get(packageName); - if(p == null) { - dataOnly = true; - PackageSetting ps = mSettings.mPackages.get(packageName); - if((ps == null) || (ps.pkg == null)) { - Log.w(TAG, "Package named '" + packageName +"' doesn't exist."); - return false; - } - p = ps.pkg; - } - } - String publicSrcDir = null; - if(!dataOnly) { - final ApplicationInfo applicationInfo = p.applicationInfo; - if (applicationInfo == null) { - Log.w(TAG, "Package " + packageName + " has no applicationInfo."); - return false; - } - publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null; - } - if (mInstaller != null) { - int res = mInstaller.getSizeInfo(packageName, p.mPath, - publicSrcDir, pStats); - if (res < 0) { - return false; - } else { - return true; - } - } - return true; - } - - - public void addPackageToPreferred(String packageName) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); - - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if (p == null) { - return; - } - PackageSetting ps = (PackageSetting)p.mExtras; - if (ps != null) { - mSettings.mPreferredPackages.remove(ps); - mSettings.mPreferredPackages.add(0, ps); - updatePreferredIndicesLP(); - mSettings.writeLP(); - } - } - } - - public void removePackageFromPreferred(String packageName) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); - - synchronized (mPackages) { - PackageParser.Package p = mPackages.get(packageName); - if (p == null) { - return; - } - if (p.mPreferredOrder > 0) { - PackageSetting ps = (PackageSetting)p.mExtras; - if (ps != null) { - mSettings.mPreferredPackages.remove(ps); - p.mPreferredOrder = 0; - updatePreferredIndicesLP(); - mSettings.writeLP(); - } - } - } - } - - private void updatePreferredIndicesLP() { - final ArrayList<PackageSetting> pkgs - = mSettings.mPreferredPackages; - final int N = pkgs.size(); - for (int i=0; i<N; i++) { - pkgs.get(i).pkg.mPreferredOrder = N - i; - } - } - - public List<PackageInfo> getPreferredPackages(int flags) { - synchronized (mPackages) { - final ArrayList<PackageInfo> res = new ArrayList<PackageInfo>(); - final ArrayList<PackageSetting> pref = mSettings.mPreferredPackages; - final int N = pref.size(); - for (int i=0; i<N; i++) { - res.add(generatePackageInfo(pref.get(i).pkg, flags)); - } - return res; - } - } - - public void addPreferredActivity(IntentFilter filter, int match, - ComponentName[] set, ComponentName activity) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); - - synchronized (mPackages) { - Log.i(TAG, "Adding preferred activity " + activity + ":"); - filter.dump(new LogPrinter(Log.INFO, TAG), " "); - mSettings.mPreferredActivities.addFilter( - new PreferredActivity(filter, match, set, activity)); - mSettings.writeLP(); - } - } - - public void clearPackagePreferredActivities(String packageName) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); - - synchronized (mPackages) { - if (clearPackagePreferredActivitiesLP(packageName)) { - mSettings.writeLP(); - } - } - } - - boolean clearPackagePreferredActivitiesLP(String packageName) { - boolean changed = false; - Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); - while (it.hasNext()) { - PreferredActivity pa = it.next(); - if (pa.mActivity.getPackageName().equals(packageName)) { - it.remove(); - changed = true; - } - } - return changed; - } - - public int getPreferredActivities(List<IntentFilter> outFilters, - List<ComponentName> outActivities, String packageName) { - - int num = 0; - synchronized (mPackages) { - Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); - while (it.hasNext()) { - PreferredActivity pa = it.next(); - if (packageName == null - || pa.mActivity.getPackageName().equals(packageName)) { - if (outFilters != null) { - outFilters.add(new IntentFilter(pa)); - } - if (outActivities != null) { - outActivities.add(pa.mActivity); - } - } - } - } - - return num; - } - - public void setApplicationEnabledSetting(String appPackageName, - int newState, int flags) { - setEnabledSetting(appPackageName, null, newState, flags); - } - - public void setComponentEnabledSetting(ComponentName componentName, - int newState, int flags) { - setEnabledSetting(componentName.getPackageName(), - componentName.getClassName(), newState, flags); - } - - private void setEnabledSetting( - final String packageNameStr, String classNameStr, int newState, final int flags) { - if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT - || newState == COMPONENT_ENABLED_STATE_ENABLED - || newState == COMPONENT_ENABLED_STATE_DISABLED)) { - throw new IllegalArgumentException("Invalid new component state: " - + newState); - } - PackageSetting pkgSetting; - final int uid = Binder.getCallingUid(); - final int permission = mContext.checkCallingPermission( - android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); - final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); - int packageUid = -1; - synchronized (mPackages) { - pkgSetting = mSettings.mPackages.get(packageNameStr); - if (pkgSetting == null) { - if (classNameStr == null) { - throw new IllegalArgumentException( - "Unknown package: " + packageNameStr); - } - throw new IllegalArgumentException( - "Unknown component: " + packageNameStr - + "/" + classNameStr); - } - if (!allowedByPermission && (uid != pkgSetting.userId)) { - throw new SecurityException( - "Permission Denial: attempt to change component state from pid=" - + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.userId); - } - packageUid = pkgSetting.userId; - if (classNameStr == null) { - // We're dealing with an application/package level state change - pkgSetting.enabled = newState; - } else { - // We're dealing with a component level state change - switch (newState) { - case COMPONENT_ENABLED_STATE_ENABLED: - pkgSetting.enableComponentLP(classNameStr); - break; - case COMPONENT_ENABLED_STATE_DISABLED: - pkgSetting.disableComponentLP(classNameStr); - break; - case COMPONENT_ENABLED_STATE_DEFAULT: - pkgSetting.restoreComponentLP(classNameStr); - break; - default: - Log.e(TAG, "Invalid new component state: " + newState); - } - } - mSettings.writeLP(); - } - - long callingId = Binder.clearCallingIdentity(); - try { - Bundle extras = new Bundle(2); - extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, - (flags&PackageManager.DONT_KILL_APP) != 0); - extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageNameStr, extras); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - - public int getApplicationEnabledSetting(String appPackageName) { - synchronized (mPackages) { - PackageSetting pkg = mSettings.mPackages.get(appPackageName); - if (pkg == null) { - throw new IllegalArgumentException("Unknown package: " + appPackageName); - } - return pkg.enabled; - } - } - - public int getComponentEnabledSetting(ComponentName componentName) { - synchronized (mPackages) { - final String packageNameStr = componentName.getPackageName(); - PackageSetting pkg = mSettings.mPackages.get(packageNameStr); - if (pkg == null) { - throw new IllegalArgumentException("Unknown component: " + componentName); - } - final String classNameStr = componentName.getClassName(); - return pkg.currentEnabledStateLP(classNameStr); - } - } - - public void enterSafeMode() { - if (!mSystemReady) { - mSafeMode = true; - } - } - - public void systemReady() { - mSystemReady = true; - } - - public boolean isSafeMode() { - return mSafeMode; - } - - public boolean hasSystemUidErrors() { - return mHasSystemUidErrors; - } - - static String arrayToString(int[] array) { - StringBuffer buf = new StringBuffer(128); - buf.append('['); - if (array != null) { - for (int i=0; i<array.length; i++) { - if (i > 0) buf.append(", "); - buf.append(array[i]); - } - } - buf.append(']'); - return buf.toString(); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - - Printer printer = new PrintWriterPrinter(pw); - synchronized (mPackages) { - pw.println("Activity Resolver Table:"); - mActivities.dump(printer, " "); - pw.println(" "); - pw.println("Receiver Resolver Table:"); - mReceivers.dump(printer, " "); - pw.println(" "); - pw.println("Service Resolver Table:"); - mServices.dump(printer, " "); - pw.println(" "); - pw.println("Preferred Activities:"); - mSettings.mPreferredActivities.dump(printer, " "); - pw.println(" "); - pw.println("Preferred Packages:"); - { - for (PackageSetting ps : mSettings.mPreferredPackages) { - pw.println(" " + ps.name); - } - } - pw.println(" "); - pw.println("Permissions:"); - { - for (BasePermission p : mSettings.mPermissions.values()) { - pw.println(" Permission [" + p.name + "] (" - + Integer.toHexString(System.identityHashCode(p)) - + "):"); - pw.println(" sourcePackage=" + p.sourcePackage); - pw.println(" uid=" + p.uid - + " gids=" + arrayToString(p.gids) - + " type=" + p.type); - } - } - pw.println(" "); - pw.println("Packages:"); - { - for (PackageSetting ps : mSettings.mPackages.values()) { - pw.println(" Package [" + ps.name + "] (" - + Integer.toHexString(System.identityHashCode(ps)) - + "):"); - pw.println(" userId=" + ps.userId - + " gids=" + arrayToString(ps.gids)); - pw.println(" sharedUser=" + ps.sharedUser); - pw.println(" pkg=" + ps.pkg); - pw.println(" codePath=" + ps.codePathString); - pw.println(" resourcePath=" + ps.resourcePathString); - if (ps.pkg != null) { - pw.println(" dataDir=" + ps.pkg.applicationInfo.dataDir); - } - pw.println(" timeStamp=" + ps.getTimeStampStr()); - pw.println(" signatures=" + ps.signatures); - pw.println(" permissionsFixed=" + ps.permissionsFixed - + " pkgFlags=0x" + Integer.toHexString(ps.pkgFlags) - + " installStatus=" + ps.installStatus - + " enabled=" + ps.enabled); - if (ps.disabledComponents.size() > 0) { - pw.println(" disabledComponents:"); - for (String s : ps.disabledComponents) { - pw.println(" " + s); - } - } - if (ps.enabledComponents.size() > 0) { - pw.println(" enabledComponents:"); - for (String s : ps.enabledComponents) { - pw.println(" " + s); - } - } - pw.println(" grantedPermissions:"); - for (String s : ps.grantedPermissions) { - pw.println(" " + s); - } - pw.println(" loadedPermissions:"); - for (String s : ps.loadedPermissions) { - pw.println(" " + s); - } - } - } - pw.println(" "); - pw.println("Shared Users:"); - { - for (SharedUserSetting su : mSettings.mSharedUsers.values()) { - pw.println(" SharedUser [" + su.name + "] (" - + Integer.toHexString(System.identityHashCode(su)) - + "):"); - pw.println(" userId=" + su.userId - + " gids=" + arrayToString(su.gids)); - pw.println(" grantedPermissions:"); - for (String s : su.grantedPermissions) { - pw.println(" " + s); - } - pw.println(" loadedPermissions:"); - for (String s : su.loadedPermissions) { - pw.println(" " + s); - } - } - } - pw.println(" "); - pw.println("Settings parse messages:"); - pw.println(mSettings.mReadMessages.toString()); - } - } - - static final class BasePermission { - final static int TYPE_NORMAL = 0; - final static int TYPE_BUILTIN = 1; - final static int TYPE_DYNAMIC = 2; - - final String name; - final String sourcePackage; - final int type; - PackageParser.Permission perm; - PermissionInfo pendingInfo; - int uid; - int[] gids; - - BasePermission(String _name, String _sourcePackage, int _type) { - name = _name; - sourcePackage = _sourcePackage; - type = _type; - } - } - - static class PackageSignatures { - private Signature[] mSignatures; - - PackageSignatures(Signature[] sigs) { - assignSignatures(sigs); - } - - PackageSignatures() { - } - - void writeXml(XmlSerializer serializer, String tagName, - ArrayList<Signature> pastSignatures) throws IOException { - if (mSignatures == null) { - return; - } - serializer.startTag(null, tagName); - serializer.attribute(null, "count", - Integer.toString(mSignatures.length)); - for (int i=0; i<mSignatures.length; i++) { - serializer.startTag(null, "cert"); - final Signature sig = mSignatures[i]; - final int sigHash = sig.hashCode(); - final int numPast = pastSignatures.size(); - int j; - for (j=0; j<numPast; j++) { - Signature pastSig = pastSignatures.get(j); - if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) { - serializer.attribute(null, "index", Integer.toString(j)); - break; - } - } - if (j >= numPast) { - pastSignatures.add(sig); - serializer.attribute(null, "index", Integer.toString(numPast)); - serializer.attribute(null, "key", sig.toCharsString()); - } - serializer.endTag(null, "cert"); - } - serializer.endTag(null, tagName); - } - - void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures) - throws IOException, XmlPullParserException { - String countStr = parser.getAttributeValue(null, "count"); - if (countStr == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <signatures> has" - + " no count at " + parser.getPositionDescription()); - XmlUtils.skipCurrentTag(parser); - } - final int count = Integer.parseInt(countStr); - mSignatures = new Signature[count]; - int pos = 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("cert")) { - if (pos < count) { - String index = parser.getAttributeValue(null, "index"); - if (index != null) { - try { - int idx = Integer.parseInt(index); - String key = parser.getAttributeValue(null, "key"); - if (key == null) { - if (idx >= 0 && idx < pastSignatures.size()) { - Signature sig = pastSignatures.get(idx); - if (sig != null) { - mSignatures[pos] = pastSignatures.get(idx); - pos++; - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is not defined at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is out of bounds at " - + parser.getPositionDescription()); - } - } else { - while (pastSignatures.size() <= idx) { - pastSignatures.add(null); - } - Signature sig = new Signature(key); - pastSignatures.set(idx, sig); - mSignatures[pos] = sig; - pos++; - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> " - + "index " + index + " is not a number at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <cert> has" - + " no index at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: too " - + "many <cert> tags, expected " + count - + " at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <cert>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - - if (pos < count) { - // Should never happen -- there is an error in the written - // settings -- but if it does we don't want to generate - // a bad array. - Signature[] newSigs = new Signature[pos]; - System.arraycopy(mSignatures, 0, newSigs, 0, pos); - mSignatures = newSigs; - } - } - - /** - * If any of the given 'sigs' is contained in the existing signatures, - * then completely replace the current signatures with the ones in - * 'sigs'. This is used for updating an existing package to a newly - * installed version. - */ - boolean updateSignatures(Signature[] sigs, boolean update) { - if (mSignatures == null) { - if (update) { - assignSignatures(sigs); - } - return true; - } - if (sigs == null) { - return false; - } - - for (int i=0; i<sigs.length; i++) { - Signature sig = sigs[i]; - for (int j=0; j<mSignatures.length; j++) { - if (mSignatures[j].equals(sig)) { - if (update) { - assignSignatures(sigs); - } - return true; - } - } - } - return false; - } - - /** - * If any of the given 'sigs' is contained in the existing signatures, - * then add in any new signatures found in 'sigs'. This is used for - * including a new package into an existing shared user id. - */ - boolean mergeSignatures(Signature[] sigs, boolean update) { - if (mSignatures == null) { - if (update) { - assignSignatures(sigs); - } - return true; - } - if (sigs == null) { - return false; - } - - Signature[] added = null; - int addedCount = 0; - boolean haveMatch = false; - for (int i=0; i<sigs.length; i++) { - Signature sig = sigs[i]; - boolean found = false; - for (int j=0; j<mSignatures.length; j++) { - if (mSignatures[j].equals(sig)) { - found = true; - haveMatch = true; - break; - } - } - - if (!found) { - if (added == null) { - added = new Signature[sigs.length]; - } - added[i] = sig; - addedCount++; - } - } - - if (!haveMatch) { - // Nothing matched -- reject the new signatures. - return false; - } - if (added == null) { - // Completely matched -- nothing else to do. - return true; - } - - // Add additional signatures in. - if (update) { - Signature[] total = new Signature[addedCount+mSignatures.length]; - System.arraycopy(mSignatures, 0, total, 0, mSignatures.length); - int j = mSignatures.length; - for (int i=0; i<added.length; i++) { - if (added[i] != null) { - total[j] = added[i]; - j++; - } - } - mSignatures = total; - } - return true; - } - - private void assignSignatures(Signature[] sigs) { - if (sigs == null) { - mSignatures = null; - return; - } - mSignatures = new Signature[sigs.length]; - for (int i=0; i<sigs.length; i++) { - mSignatures[i] = sigs[i]; - } - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(128); - buf.append("PackageSignatures{"); - buf.append(Integer.toHexString(System.identityHashCode(this))); - buf.append(" ["); - if (mSignatures != null) { - for (int i=0; i<mSignatures.length; i++) { - if (i > 0) buf.append(", "); - buf.append(Integer.toHexString( - System.identityHashCode(mSignatures[i]))); - } - } - buf.append("]}"); - return buf.toString(); - } - } - - static class PreferredActivity extends IntentFilter { - final int mMatch; - final String[] mSetPackages; - final String[] mSetClasses; - final String[] mSetComponents; - final ComponentName mActivity; - final String mShortActivity; - String mParseError; - - PreferredActivity(IntentFilter filter, int match, ComponentName[] set, - ComponentName activity) { - super(filter); - mMatch = match&IntentFilter.MATCH_CATEGORY_MASK; - mActivity = activity; - mShortActivity = activity.flattenToShortString(); - mParseError = null; - if (set != null) { - final int N = set.length; - String[] myPackages = new String[N]; - String[] myClasses = new String[N]; - String[] myComponents = new String[N]; - for (int i=0; i<N; i++) { - ComponentName cn = set[i]; - if (cn == null) { - mSetPackages = null; - mSetClasses = null; - mSetComponents = null; - return; - } - myPackages[i] = cn.getPackageName().intern(); - myClasses[i] = cn.getClassName().intern(); - myComponents[i] = cn.flattenToShortString().intern(); - } - mSetPackages = myPackages; - mSetClasses = myClasses; - mSetComponents = myComponents; - } else { - mSetPackages = null; - mSetClasses = null; - mSetComponents = null; - } - } - - PreferredActivity(XmlPullParser parser) throws XmlPullParserException, - IOException { - mShortActivity = parser.getAttributeValue(null, "name"); - mActivity = ComponentName.unflattenFromString(mShortActivity); - if (mActivity == null) { - mParseError = "Bad activity name " + mShortActivity; - } - String matchStr = parser.getAttributeValue(null, "match"); - mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0; - String setCountStr = parser.getAttributeValue(null, "set"); - int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0; - - String[] myPackages = setCount > 0 ? new String[setCount] : null; - String[] myClasses = setCount > 0 ? new String[setCount] : null; - String[] myComponents = setCount > 0 ? new String[setCount] : null; - - int setPos = 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(); - //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth=" - // + parser.getDepth() + " tag=" + tagName); - if (tagName.equals("set")) { - String name = parser.getAttributeValue(null, "name"); - if (name == null) { - if (mParseError == null) { - mParseError = "No name in set tag in preferred activity " - + mShortActivity; - } - } else if (setPos >= setCount) { - if (mParseError == null) { - mParseError = "Too many set tags in preferred activity " - + mShortActivity; - } - } else { - ComponentName cn = ComponentName.unflattenFromString(name); - if (cn == null) { - if (mParseError == null) { - mParseError = "Bad set name " + name + " in preferred activity " - + mShortActivity; - } - } else { - myPackages[setPos] = cn.getPackageName(); - myClasses[setPos] = cn.getClassName(); - myComponents[setPos] = name; - setPos++; - } - } - XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("filter")) { - //Log.i(TAG, "Starting to parse filter..."); - readFromXml(parser); - //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth=" - // + parser.getDepth() + " tag=" + parser.getName()); - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <preferred-activities>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - - if (setPos != setCount) { - if (mParseError == null) { - mParseError = "Not enough set tags (expected " + setCount - + " but found " + setPos + ") in " + mShortActivity; - } - } - - mSetPackages = myPackages; - mSetClasses = myClasses; - mSetComponents = myComponents; - } - - public void writeToXml(XmlSerializer serializer) throws IOException { - final int NS = mSetClasses != null ? mSetClasses.length : 0; - serializer.attribute(null, "name", mShortActivity); - serializer.attribute(null, "match", Integer.toHexString(mMatch)); - serializer.attribute(null, "set", Integer.toString(NS)); - for (int s=0; s<NS; s++) { - serializer.startTag(null, "set"); - serializer.attribute(null, "name", mSetComponents[s]); - serializer.endTag(null, "set"); - } - serializer.startTag(null, "filter"); - super.writeToXml(serializer); - serializer.endTag(null, "filter"); - } - - boolean sameSet(List<ResolveInfo> query, int priority) { - if (mSetPackages == null) return false; - final int NQ = query.size(); - final int NS = mSetPackages.length; - int numMatch = 0; - for (int i=0; i<NQ; i++) { - ResolveInfo ri = query.get(i); - if (ri.priority != priority) continue; - ActivityInfo ai = ri.activityInfo; - boolean good = false; - for (int j=0; j<NS; j++) { - if (mSetPackages[j].equals(ai.packageName) - && mSetClasses[j].equals(ai.name)) { - numMatch++; - good = true; - break; - } - } - if (!good) return false; - } - return numMatch == NS; - } - } - - static class GrantedPermissions { - final int pkgFlags; - - HashSet<String> grantedPermissions = new HashSet<String>(); - int[] gids; - - HashSet<String> loadedPermissions = new HashSet<String>(); - - GrantedPermissions(int pkgFlags) { - this.pkgFlags = pkgFlags & ApplicationInfo.FLAG_SYSTEM; - } - } - - /** - * Settings base class for pending and resolved classes. - */ - static class PackageSettingBase extends GrantedPermissions { - final String name; - final File codePath; - final String codePathString; - final File resourcePath; - final String resourcePathString; - private long timeStamp; - private String timeStampString = "0"; - - PackageSignatures signatures = new PackageSignatures(); - - boolean permissionsFixed; - - /* Explicitly disabled components */ - HashSet<String> disabledComponents = new HashSet<String>(0); - /* Explicitly enabled components */ - HashSet<String> enabledComponents = new HashSet<String>(0); - int enabled = COMPONENT_ENABLED_STATE_DEFAULT; - int installStatus = PKG_INSTALL_COMPLETE; - - PackageSettingBase(String name, File codePath, File resourcePath, - int pkgFlags) { - super(pkgFlags); - this.name = name; - this.codePath = codePath; - this.codePathString = codePath.toString(); - this.resourcePath = resourcePath; - this.resourcePathString = resourcePath.toString(); - } - - public void setInstallStatus(int newStatus) { - installStatus = newStatus; - } - - public int getInstallStatus() { - return installStatus; - } - - public void setTimeStamp(long newStamp) { - if (newStamp != timeStamp) { - timeStamp = newStamp; - timeStampString = Long.toString(newStamp); - } - } - - public void setTimeStamp(long newStamp, String newStampStr) { - timeStamp = newStamp; - timeStampString = newStampStr; - } - - public long getTimeStamp() { - return timeStamp; - } - - public String getTimeStampStr() { - return timeStampString; - } - - public void copyFrom(PackageSettingBase base) { - grantedPermissions = base.grantedPermissions; - gids = base.gids; - loadedPermissions = base.loadedPermissions; - - timeStamp = base.timeStamp; - timeStampString = base.timeStampString; - signatures = base.signatures; - permissionsFixed = base.permissionsFixed; - disabledComponents = base.disabledComponents; - enabledComponents = base.enabledComponents; - enabled = base.enabled; - installStatus = base.installStatus; - } - - void enableComponentLP(String componentClassName) { - disabledComponents.remove(componentClassName); - enabledComponents.add(componentClassName); - } - - void disableComponentLP(String componentClassName) { - enabledComponents.remove(componentClassName); - disabledComponents.add(componentClassName); - } - - void restoreComponentLP(String componentClassName) { - enabledComponents.remove(componentClassName); - disabledComponents.remove(componentClassName); - } - - int currentEnabledStateLP(String componentName) { - if (enabledComponents.contains(componentName)) { - return COMPONENT_ENABLED_STATE_ENABLED; - } else if (disabledComponents.contains(componentName)) { - return COMPONENT_ENABLED_STATE_DISABLED; - } else { - return COMPONENT_ENABLED_STATE_DEFAULT; - } - } - } - - /** - * Settings data for a particular package we know about. - */ - static final class PackageSetting extends PackageSettingBase { - int userId; - PackageParser.Package pkg; - SharedUserSetting sharedUser; - - PackageSetting(String name, File codePath, File resourcePath, - int pkgFlags) { - super(name, codePath, resourcePath, pkgFlags); - } - - @Override - public String toString() { - return "PackageSetting{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + userId + "}"; - } - } - - /** - * Settings data for a particular shared user ID we know about. - */ - static final class SharedUserSetting extends GrantedPermissions { - final String name; - int userId; - final HashSet<PackageSetting> packages = new HashSet<PackageSetting>(); - final PackageSignatures signatures = new PackageSignatures(); - - SharedUserSetting(String _name, int _pkgFlags) { - super(_pkgFlags); - name = _name; - } - - @Override - public String toString() { - return "SharedUserSetting{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + userId + "}"; - } - } - - /** - * Holds information about dynamic settings. - */ - private static final class Settings { - private final File mSettingsFilename; - private final File mBackupSettingsFilename; - private final HashMap<String, PackageSetting> mPackages = - new HashMap<String, PackageSetting>(); - // The user's preferred packages/applications, in order of preference. - // First is the most preferred. - private final ArrayList<PackageSetting> mPreferredPackages = - new ArrayList<PackageSetting>(); - // List of replaced system applications - final HashMap<String, PackageSetting> mDisabledSysPackages = - new HashMap<String, PackageSetting>(); - - // The user's preferred activities associated with particular intent - // filters. - private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities = - new IntentResolver<PreferredActivity, PreferredActivity>() { - @Override - protected void dumpFilter(Printer out, String prefix, - PreferredActivity filter) { - out.println(prefix - + Integer.toHexString(System.identityHashCode(filter)) - + " " + filter.mActivity.flattenToShortString() - + " match=0x" + Integer.toHexString(filter.mMatch)); - if (filter.mSetComponents != null) { - out.println(prefix + " Selected from:"); - for (int i=0; i<filter.mSetComponents.length; i++) { - out.println(prefix + " " + filter.mSetComponents[i]); - } - } - } - }; - private final HashMap<String, SharedUserSetting> mSharedUsers = - new HashMap<String, SharedUserSetting>(); - private final ArrayList<Object> mUserIds = new ArrayList<Object>(); - private final SparseArray<Object> mOtherUserIds = - new SparseArray<Object>(); - - // For reading/writing settings file. - private final ArrayList<Signature> mPastSignatures = - new ArrayList<Signature>(); - - // Mapping from permission names to info about them. - final HashMap<String, BasePermission> mPermissions = - new HashMap<String, BasePermission>(); - - // Mapping from permission tree names to info about them. - final HashMap<String, BasePermission> mPermissionTrees = - new HashMap<String, BasePermission>(); - - private final ArrayList<String> mPendingPreferredPackages - = new ArrayList<String>(); - - private final StringBuilder mReadMessages = new StringBuilder(); - - private static final class PendingPackage extends PackageSettingBase { - final int sharedId; - - PendingPackage(String name, File codePath, File resourcePath, - int sharedId, int pkgFlags) { - super(name, codePath, resourcePath, pkgFlags); - this.sharedId = sharedId; - } - } - private final ArrayList<PendingPackage> mPendingPackages - = new ArrayList<PendingPackage>(); - - Settings() { - File dataDir = Environment.getDataDirectory(); - File systemDir = new File(dataDir, "system"); - systemDir.mkdirs(); - FileUtils.setPermissions(systemDir.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG - |FileUtils.S_IROTH|FileUtils.S_IXOTH, - -1, -1); - mSettingsFilename = new File(systemDir, "packages.xml"); - mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); - } - - PackageSetting getPackageLP(PackageParser.Package pkg, - SharedUserSetting sharedUser, File codePath, File resourcePath, - int pkgFlags, boolean create) { - final String name = pkg.packageName; - PackageSetting p = getPackageLP(name, sharedUser, codePath, - resourcePath, pkgFlags, create); - - if (p != null) { - p.pkg = pkg; - } - return p; - } - - PackageSetting peekPackageLP(String name, String codePath) { - PackageSetting p = mPackages.get(name); - if (p != null && p.codePath.getPath().equals(codePath)) { - return p; - } - return null; - } - - void setInstallStatus(String pkgName, int status) { - PackageSetting p = mPackages.get(pkgName); - if(p != null) { - if(p.getInstallStatus() != status) { - p.setInstallStatus(status); - } - } - } - - int getInstallStatus(String pkgName) { - PackageSetting p = mPackages.get(pkgName); - if(p != null) { - return p.getInstallStatus(); - } - return -1; - } - - SharedUserSetting getSharedUserLP(String name, - int pkgFlags, boolean create) { - SharedUserSetting s = mSharedUsers.get(name); - if (s == null) { - if (!create) { - return null; - } - s = new SharedUserSetting(name, pkgFlags); - if (MULTIPLE_APPLICATION_UIDS) { - s.userId = newUserIdLP(s); - } else { - s.userId = FIRST_APPLICATION_UID; - } - Log.i(TAG, "New shared user " + name + ": id=" + s.userId); - // < 0 means we couldn't assign a userid; fall out and return - // s, which is currently null - if (s.userId >= 0) { - mSharedUsers.put(name, s); - } - } - - return s; - } - - int disableSystemPackageLP(String name) { - PackageSetting p = mPackages.get(name); - if(p == null) { - Log.w(TAG, "Package:"+name+" is not an installed package"); - return -1; - } - PackageSetting dp = mDisabledSysPackages.get(name); - // always make sure the system package code and resource paths dont change - if(dp == null) { - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - } - mDisabledSysPackages.put(name, p); - } - return removePackageLP(name); - } - - PackageSetting enableSystemPackageLP(String name) { - PackageSetting p = mDisabledSysPackages.get(name); - if(p == null) { - Log.w(TAG, "Package:"+name+" is not disabled"); - return null; - } - // Reset flag in ApplicationInfo object - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; - } - PackageSetting ret = addPackageLP(name, p.codePath, - p.resourcePath, p.userId, p.pkgFlags); - mDisabledSysPackages.remove(name); - return ret; - } - - PackageSetting addPackageLP(String name, File codePath, - File resourcePath, int uid, int pkgFlags) { - PackageSetting p = mPackages.get(name); - if (p != null) { - if (p.userId == uid) { - return p; - } - reportSettingsProblem(Log.ERROR, - "Adding duplicate package, keeping first: " + name); - return null; - } - p = new PackageSetting(name, codePath, resourcePath, pkgFlags); - p.userId = uid; - if (addUserIdLP(uid, p, name)) { - mPackages.put(name, p); - return p; - } - return null; - } - - SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) { - SharedUserSetting s = mSharedUsers.get(name); - if (s != null) { - if (s.userId == uid) { - return s; - } - reportSettingsProblem(Log.ERROR, - "Adding duplicate shared user, keeping first: " + name); - return null; - } - s = new SharedUserSetting(name, pkgFlags); - s.userId = uid; - if (addUserIdLP(uid, s, name)) { - mSharedUsers.put(name, s); - return s; - } - return null; - } - - private PackageSetting getPackageLP(String name, - SharedUserSetting sharedUser, File codePath, File resourcePath, - int pkgFlags, boolean create) { - PackageSetting p = mPackages.get(name); - if (p != null) { - if (!p.codePath.equals(codePath)) { - // Check to see if its a disabled system app - PackageSetting ps = mDisabledSysPackages.get(name); - if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) { - // Could be a replaced system package - // Note that if the user replaced a system app, the user has to physically - // delete the new one in order to revert to the system app. So even - // if the user updated the system app via an update, the user still - // has to delete the one installed in the data partition in order to pick up the - // new system package. - return p; - } else { - reportSettingsProblem(Log.WARN, - "Package " + name + " codePath changed from " + p.codePath - + " to " + codePath + "; replacing with new"); - p = null; - } - } else if (p.sharedUser != sharedUser) { - reportSettingsProblem(Log.WARN, - "Package " + name + " shared user changed from " - + (p.sharedUser != null ? p.sharedUser.name : "<nothing>") - + " to " - + (sharedUser != null ? sharedUser.name : "<nothing>") - + "; replacing with new"); - p = null; - } - } - if (p == null) { - // Create a new PackageSettings entry. this can end up here because - // of code path mismatch or user id mismatch of an updated system partition - if (!create) { - return null; - } - p = new PackageSetting(name, codePath, resourcePath, pkgFlags); - p.setTimeStamp(codePath.lastModified()); - if (sharedUser != null) { - p.userId = sharedUser.userId; - } else if (MULTIPLE_APPLICATION_UIDS) { - p.userId = newUserIdLP(p); - } else { - p.userId = FIRST_APPLICATION_UID; - } - - if (p.userId < 0) { - reportSettingsProblem(Log.WARN, - "Package " + name + " could not be assigned a valid uid"); - return null; - } - mPackages.put(name, p); - } - - if (sharedUser != null) { - if (p.sharedUser != null && p.sharedUser != sharedUser) { - reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user " - + p.sharedUser + " but is now " + sharedUser - + "; I am not changing its files so it will probably fail!"); - p.sharedUser.packages.remove(p); - } else if (p.userId != sharedUser.userId) { - reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user id " + p.userId - + " but is now user " + sharedUser - + " with id " + sharedUser.userId - + "; I am not changing its files so it will probably fail!"); - } - - sharedUser.packages.add(p); - p.sharedUser = sharedUser; - p.userId = sharedUser.userId; - } - return p; - } - - private void updateSharedUserPerms (PackageSetting deletedPs) { - if ( (deletedPs == null) || (deletedPs.pkg == null)) { - Log.i(TAG, "Trying to update info for null package. Just ignoring"); - return; - } - // No sharedUserId - if (deletedPs.sharedUser == null) { - return; - } - SharedUserSetting sus = deletedPs.sharedUser; - // Update permissions - for (String eachPerm: deletedPs.pkg.requestedPermissions) { - boolean used = false; - if (!sus.grantedPermissions.contains (eachPerm)) { - continue; - } - for (PackageSetting pkg:sus.packages) { - if (pkg.grantedPermissions.contains (eachPerm)) { - used = true; - break; - } - } - if (!used) { - // can safely delete this permission from list - sus.grantedPermissions.remove(eachPerm); - sus.loadedPermissions.remove(eachPerm); - } - } - // Update gids - int newGids[] = null; - for (PackageSetting pkg:sus.packages) { - newGids = appendInts(newGids, pkg.gids); - } - sus.gids = newGids; - } - - private int removePackageLP(String name) { - PackageSetting p = mPackages.get(name); - if (p != null) { - mPackages.remove(name); - if (p.sharedUser != null) { - p.sharedUser.packages.remove(p); - if (p.sharedUser.packages.size() == 0) { - mSharedUsers.remove(p.sharedUser.name); - removeUserIdLP(p.sharedUser.userId); - return p.sharedUser.userId; - } - } else { - removeUserIdLP(p.userId); - return p.userId; - } - } - return -1; - } - - private boolean addUserIdLP(int uid, Object obj, Object name) { - if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) { - return false; - } - - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - while (index >= N) { - mUserIds.add(null); - N++; - } - if (mUserIds.get(index) != null) { - reportSettingsProblem(Log.ERROR, - "Adding duplicate shared id: " + uid - + " name=" + name); - return false; - } - mUserIds.set(index, obj); - } else { - if (mOtherUserIds.get(uid) != null) { - reportSettingsProblem(Log.ERROR, - "Adding duplicate shared id: " + uid - + " name=" + name); - return false; - } - mOtherUserIds.put(uid, obj); - } - return true; - } - - public Object getUserIdLP(int uid) { - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - return index < N ? mUserIds.get(index) : null; - } else { - return mOtherUserIds.get(uid); - } - } - - private void removeUserIdLP(int uid) { - if (uid >= FIRST_APPLICATION_UID) { - int N = mUserIds.size(); - final int index = uid - FIRST_APPLICATION_UID; - if (index < N) mUserIds.set(index, null); - } else { - mOtherUserIds.remove(uid); - } - } - - void writeLP() { - //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); - - // Keep the old settings around until we know the new ones have - // been successfully written. - if (mSettingsFilename.exists()) { - if (mBackupSettingsFilename.exists()) { - mBackupSettingsFilename.delete(); - } - mSettingsFilename.renameTo(mBackupSettingsFilename); - } - - mPastSignatures.clear(); - - try { - FileOutputStream str = new FileOutputStream(mSettingsFilename); - - //XmlSerializer serializer = XmlUtils.serializerInstance(); - XmlSerializer serializer = new FastXmlSerializer(); - serializer.setOutput(str, "utf-8"); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startTag(null, "packages"); - - serializer.startTag(null, "permission-trees"); - for (BasePermission bp : mPermissionTrees.values()) { - writePermission(serializer, bp); - } - serializer.endTag(null, "permission-trees"); - - serializer.startTag(null, "permissions"); - for (BasePermission bp : mPermissions.values()) { - writePermission(serializer, bp); - } - serializer.endTag(null, "permissions"); - - for (PackageSetting pkg : mPackages.values()) { - writePackage(serializer, pkg); - } - - for (PackageSetting pkg : mDisabledSysPackages.values()) { - writeDisabledSysPackage(serializer, pkg); - } - - serializer.startTag(null, "preferred-packages"); - int N = mPreferredPackages.size(); - for (int i=0; i<N; i++) { - PackageSetting pkg = mPreferredPackages.get(i); - serializer.startTag(null, "item"); - serializer.attribute(null, "name", pkg.name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "preferred-packages"); - - serializer.startTag(null, "preferred-activities"); - for (PreferredActivity pa : mPreferredActivities.filterSet()) { - serializer.startTag(null, "item"); - pa.writeToXml(serializer); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "preferred-activities"); - - for (SharedUserSetting usr : mSharedUsers.values()) { - serializer.startTag(null, "shared-user"); - serializer.attribute(null, "name", usr.name); - serializer.attribute(null, "userId", - Integer.toString(usr.userId)); - usr.signatures.writeXml(serializer, "sigs", mPastSignatures); - serializer.startTag(null, "perms"); - for (String name : usr.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "perms"); - serializer.endTag(null, "shared-user"); - } - - serializer.endTag(null, "packages"); - - serializer.endDocument(); - - str.flush(); - str.close(); - - // New settings successfully written, old ones are no longer - // needed. - mBackupSettingsFilename.delete(); - FileUtils.setPermissions(mSettingsFilename.toString(), - FileUtils.S_IRUSR|FileUtils.S_IWUSR - |FileUtils.S_IRGRP|FileUtils.S_IWGRP - |FileUtils.S_IROTH, - -1, -1); - - } catch(XmlPullParserException e) { - Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e); - - } catch(java.io.IOException e) { - Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e); - - } - - //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"); - serializer.attribute(null, "name", pkg.name); - serializer.attribute(null, "codePath", pkg.codePathString); - if (!pkg.resourcePathString.equals(pkg.codePathString)) { - serializer.attribute(null, "resourcePath", pkg.resourcePathString); - } - serializer.attribute(null, "system", - (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 - ? "true" : "false"); - serializer.attribute(null, "ts", pkg.getTimeStampStr()); - if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", - Integer.toString(pkg.userId)); - } else { - serializer.attribute(null, "sharedUserId", - Integer.toString(pkg.userId)); - } - if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", - pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED - ? "true" : "false"); - } - if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) { - serializer.attribute(null, "installStatus", "false"); - } - pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); - if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { - 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) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - } - serializer.endTag(null, "perms"); - } - if (pkg.disabledComponents.size() > 0) { - serializer.startTag(null, "disabled-components"); - for (final String name : pkg.disabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "disabled-components"); - } - if (pkg.enabledComponents.size() > 0) { - serializer.startTag(null, "enabled-components"); - for (final String name : pkg.enabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "enabled-components"); - } - serializer.endTag(null, "package"); - } - - void writePermission(XmlSerializer serializer, BasePermission bp) - throws XmlPullParserException, java.io.IOException { - if (bp.type != BasePermission.TYPE_BUILTIN - && bp.sourcePackage != null) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", bp.name); - serializer.attribute(null, "package", bp.sourcePackage); - if (DEBUG_SETTINGS) Log.v(TAG, - "Writing perm: name=" + bp.name + " type=" + bp.type); - if (bp.type == BasePermission.TYPE_DYNAMIC) { - PermissionInfo pi = bp.perm != null ? bp.perm.info - : bp.pendingInfo; - if (pi != null) { - serializer.attribute(null, "type", "dynamic"); - if (pi.icon != 0) { - serializer.attribute(null, "icon", - Integer.toString(pi.icon)); - } - if (pi.nonLocalizedLabel != null) { - serializer.attribute(null, "label", - pi.nonLocalizedLabel.toString()); - } - if (pi.protectionLevel != - PermissionInfo.PROTECTION_NORMAL) { - serializer.attribute(null, "protection", - Integer.toString(pi.protectionLevel)); - } - } - } - serializer.endTag(null, "item"); - } - } - - String getReadMessagesLP() { - return mReadMessages.toString(); - } - - ArrayList<String> getListOfIncompleteInstallPackages() { - HashSet<String> kList = new HashSet<String>(mPackages.keySet()); - Iterator<String> its = kList.iterator(); - ArrayList<String> ret = new ArrayList<String>(); - while(its.hasNext()) { - String key = its.next(); - PackageSetting ps = mPackages.get(key); - if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) { - ret.add(key); - } - } - return ret; - } - - boolean readLP() { - FileInputStream str = null; - if (mBackupSettingsFilename.exists()) { - try { - str = new FileInputStream(mBackupSettingsFilename); - mReadMessages.append("Reading from backup settings file\n"); - Log.i(TAG, "Reading from backup settings file!"); - } catch (java.io.IOException e) { - // We'll try for the normal settings file. - } - } - - mPastSignatures.clear(); - - try { - if (str == null) { - if (!mSettingsFilename.exists()) { - mReadMessages.append("No settings file found\n"); - Log.i(TAG, "No current settings file!"); - return false; - } - str = new FileInputStream(mSettingsFilename); - } - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(str, null); - - int type; - while ((type=parser.next()) != XmlPullParser.START_TAG - && type != XmlPullParser.END_DOCUMENT) { - ; - } - - if (type != XmlPullParser.START_TAG) { - mReadMessages.append("No start tag found in settings file\n"); - Log.e(TAG, "No start tag found in package manager settings"); - return false; - } - - int outerDepth = parser.getDepth(); - 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("package")) { - readPackageLP(parser); - } else if (tagName.equals("permissions")) { - readPermissionsLP(mPermissions, parser); - } else if (tagName.equals("permission-trees")) { - readPermissionsLP(mPermissionTrees, parser); - } else if (tagName.equals("shared-user")) { - readSharedUserLP(parser); - } else if (tagName.equals("preferred-packages")) { - readPreferredPackagesLP(parser); - } else if (tagName.equals("preferred-activities")) { - readPreferredActivitiesLP(parser); - } else if(tagName.equals("updated-package")) { - readDisabledSysPackageLP(parser); - } else { - Log.w(TAG, "Unknown element under <packages>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - - str.close(); - - } catch(XmlPullParserException e) { - mReadMessages.append("Error reading: " + e.toString()); - Log.e(TAG, "Error reading package manager settings", e); - - } catch(java.io.IOException e) { - mReadMessages.append("Error reading: " + e.toString()); - Log.e(TAG, "Error reading package manager settings", e); - - } - - int N = mPendingPackages.size(); - for (int i=0; i<N; i++) { - final PendingPackage pp = mPendingPackages.get(i); - Object idObj = getUserIdLP(pp.sharedId); - if (idObj != null && idObj instanceof SharedUserSetting) { - PackageSetting p = getPackageLP(pp.name, - (SharedUserSetting)idObj, pp.codePath, pp.resourcePath, - pp.pkgFlags, true); - if (p == null) { - Log.w(TAG, "Unable to create application package for " - + pp.name); - continue; - } - p.copyFrom(pp); - } else if (idObj != null) { - String msg = "Bad package setting: package " + pp.name - + " has shared uid " + pp.sharedId - + " that is not a shared uid\n"; - mReadMessages.append(msg); - Log.e(TAG, msg); - } else { - String msg = "Bad package setting: package " + pp.name - + " has shared uid " + pp.sharedId - + " that is not defined\n"; - mReadMessages.append(msg); - Log.e(TAG, msg); - } - } - mPendingPackages.clear(); - - N = mPendingPreferredPackages.size(); - mPreferredPackages.clear(); - for (int i=0; i<N; i++) { - final String name = mPendingPreferredPackages.get(i); - final PackageSetting p = mPackages.get(name); - if (p != null) { - mPreferredPackages.add(p); - } else { - Log.w(TAG, "Unknown preferred package: " + name); - } - } - mPendingPreferredPackages.clear(); - - mReadMessages.append("Read completed successfully: " - + mPackages.size() + " packages, " - + mSharedUsers.size() + " shared uids\n"); - - return true; - } - - private int readInt(XmlPullParser parser, String ns, String name, - int defValue) { - String v = parser.getAttributeValue(ns, name); - try { - if (v == null) { - return defValue; - } - return Integer.parseInt(v); - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: attribute " + - name + " has bad integer value " + v + " at " - + parser.getPositionDescription()); - } - return defValue; - } - - private void readPermissionsLP(HashMap<String, BasePermission> out, - XmlPullParser parser) - throws IOException, XmlPullParserException { - 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("item")) { - String name = parser.getAttributeValue(null, "name"); - String sourcePackage = parser.getAttributeValue(null, "package"); - String ptype = parser.getAttributeValue(null, "type"); - if (name != null && sourcePackage != null) { - boolean dynamic = "dynamic".equals(ptype); - BasePermission bp = new BasePermission(name, sourcePackage, - dynamic - ? BasePermission.TYPE_DYNAMIC - : BasePermission.TYPE_NORMAL); - if (dynamic) { - PermissionInfo pi = new PermissionInfo(); - pi.packageName = sourcePackage.intern(); - pi.name = name.intern(); - pi.icon = readInt(parser, null, "icon", 0); - pi.nonLocalizedLabel = parser.getAttributeValue( - null, "label"); - pi.protectionLevel = readInt(parser, null, "protection", - PermissionInfo.PROTECTION_NORMAL); - bp.pendingInfo = pi; - } - out.put(bp.name, bp); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: permissions has" - + " no name at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element reading permissions: " - + parser.getName() + " at " - + parser.getPositionDescription()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - 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 <updated-package>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - mDisabledSysPackages.put(name, ps); - } - - private void readPackageLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - String name = null; - String idStr = null; - String sharedIdStr = null; - String codePathStr = null; - String resourcePathStr = null; - String systemStr = null; - int pkgFlags = 0; - String timeStampStr; - long timeStamp = 0; - PackageSettingBase packageSetting = null; - try { - name = parser.getAttributeValue(null, "name"); - idStr = parser.getAttributeValue(null, "userId"); - sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - codePathStr = parser.getAttributeValue(null, "codePath"); - resourcePathStr = parser.getAttributeValue(null, "resourcePath"); - systemStr = parser.getAttributeValue(null, "system"); - if (systemStr != null) { - if ("true".equals(systemStr)) { - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - } else { - // Old settings that don't specify system... just treat - // them as system, good enough. - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - timeStampStr = parser.getAttributeValue(null, "ts"); - if (timeStampStr != null) { - try { - timeStamp = Long.parseLong(timeStampStr); - } catch (NumberFormatException e) { - } - } - if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name - + " userId=" + idStr + " sharedUserId=" + sharedIdStr); - int userId = idStr != null ? Integer.parseInt(idStr) : 0; - if (resourcePathStr == null) { - resourcePathStr = codePathStr; - } - if (name == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <package> has no name at " - + parser.getPositionDescription()); - } else if (codePathStr == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <package> has no codePath at " - + parser.getPositionDescription()); - } else if (userId > 0) { - packageSetting = addPackageLP(name.intern(), new File(codePathStr), - new File(resourcePathStr), userId, pkgFlags); - if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name - + ": userId=" + userId + " pkg=" + packageSetting); - if (packageSetting == null) { - reportSettingsProblem(Log.ERROR, - "Failure adding uid " + userId - + " while parsing settings at " - + parser.getPositionDescription()); - } else { - packageSetting.setTimeStamp(timeStamp, timeStampStr); - } - } else if (sharedIdStr != null) { - userId = sharedIdStr != null - ? Integer.parseInt(sharedIdStr) : 0; - if (userId > 0) { - packageSetting = new PendingPackage(name.intern(), new File(codePathStr), - new File(resourcePathStr), userId, pkgFlags); - packageSetting.setTimeStamp(timeStamp, timeStampStr); - mPendingPackages.add((PendingPackage) packageSetting); - if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name - + ": sharedUserId=" + userId + " pkg=" - + packageSetting); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad sharedId " + sharedIdStr - + " at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } - if (packageSetting != null) { - final String enabledStr = parser.getAttributeValue(null, "enabled"); - if (enabledStr != null) { - if (enabledStr.equalsIgnoreCase("true")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; - } else if (enabledStr.equalsIgnoreCase("false")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; - } else if (enabledStr.equalsIgnoreCase("default")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad enabled value: " + idStr - + " at " + parser.getPositionDescription()); - } - } else { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; - } - final String installStatusStr = parser.getAttributeValue(null, "installStatus"); - if (installStatusStr != null) { - if (installStatusStr.equalsIgnoreCase("false")) { - packageSetting.installStatus = PKG_INSTALL_INCOMPLETE; - } else { - packageSetting.installStatus = PKG_INSTALL_COMPLETE; - } - } - - 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("disabled-components")) { - readDisabledComponentsLP(packageSetting, parser); - } else if (tagName.equals("enabled-components")) { - readEnabledComponentsLP(packageSetting, parser); - } else if (tagName.equals("sigs")) { - packageSetting.signatures.readXml(parser, mPastSignatures); - } else if (tagName.equals("perms")) { - readGrantedPermissionsLP(parser, - packageSetting.loadedPermissions); - packageSetting.permissionsFixed = true; - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <package>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - } else { - XmlUtils.skipCurrentTag(parser); - } - } - - private void readDisabledComponentsLP(PackageSettingBase packageSetting, - XmlPullParser parser) - throws IOException, XmlPullParserException { - 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("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - packageSetting.disabledComponents.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <disabled-components> has" - + " no name at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <disabled-components>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readEnabledComponentsLP(PackageSettingBase packageSetting, - XmlPullParser parser) - throws IOException, XmlPullParserException { - 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("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - packageSetting.enabledComponents.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <enabled-components> has" - + " no name at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <enabled-components>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readSharedUserLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - String name = null; - String idStr = null; - int pkgFlags = 0; - SharedUserSetting su = null; - try { - name = parser.getAttributeValue(null, "name"); - idStr = parser.getAttributeValue(null, "userId"); - int userId = idStr != null ? Integer.parseInt(idStr) : 0; - if ("true".equals(parser.getAttributeValue(null, "system"))) { - pkgFlags |= ApplicationInfo.FLAG_SYSTEM; - } - if (name == null) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <shared-user> has no name at " - + parser.getPositionDescription()); - } else if (userId == 0) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: shared-user " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - } else { - if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) { - reportSettingsProblem(Log.ERROR, - "Occurred while parsing settings at " - + parser.getPositionDescription()); - } - } - } catch (NumberFormatException e) { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: package " - + name + " has bad userId " + idStr + " at " - + parser.getPositionDescription()); - }; - - if (su != null) { - 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("sigs")) { - su.signatures.readXml(parser, mPastSignatures); - } else if (tagName.equals("perms")) { - readGrantedPermissionsLP(parser, su.loadedPermissions); - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <shared-user>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - - } else { - XmlUtils.skipCurrentTag(parser); - } - } - - private void readGrantedPermissionsLP(XmlPullParser parser, - HashSet<String> outPerms) throws IOException, XmlPullParserException { - 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("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - outPerms.add(name.intern()); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <perms> has" - + " no name at " + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <perms>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readPreferredPackagesLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - 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("item")) { - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - mPendingPreferredPackages.add(name); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <preferred-package> has no name at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <preferred-packages>: " - + parser.getName()); - } - XmlUtils.skipCurrentTag(parser); - } - } - - private void readPreferredActivitiesLP(XmlPullParser parser) - throws XmlPullParserException, IOException { - 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("item")) { - PreferredActivity pa = new PreferredActivity(parser); - if (pa.mParseError == null) { - mPreferredActivities.addFilter(pa); - } else { - reportSettingsProblem(Log.WARN, - "Error in package manager settings: <preferred-activity> " - + pa.mParseError + " at " - + parser.getPositionDescription()); - } - } else { - reportSettingsProblem(Log.WARN, - "Unknown element under <preferred-activities>: " - + parser.getName()); - XmlUtils.skipCurrentTag(parser); - } - } - } - - // Returns -1 if we could not find an available UserId to assign - private int newUserIdLP(Object obj) { - // Let's be stupidly inefficient for now... - final int N = mUserIds.size(); - for (int i=0; i<N; i++) { - if (mUserIds.get(i) == null) { - mUserIds.set(i, obj); - return FIRST_APPLICATION_UID + i; - } - } - - // None left? - if (N >= MAX_APPLICATION_UIDS) { - return -1; - } - - mUserIds.add(obj); - return FIRST_APPLICATION_UID + N; - } - - public PackageSetting getDisabledSystemPkg(String name) { - synchronized(mPackages) { - PackageSetting ps = mDisabledSysPackages.get(name); - return ps; - } - } - - boolean isEnabledLP(ComponentInfo componentInfo, int flags) { - final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); - if (Config.LOGV) { - Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName - + " componentName = " + componentInfo.name); - Log.v(TAG, "enabledComponents: " - + Arrays.toString(packageSettings.enabledComponents.toArray())); - Log.v(TAG, "disabledComponents: " - + Arrays.toString(packageSettings.disabledComponents.toArray())); - } - return ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) - || ((componentInfo.enabled - && ((packageSettings.enabled == COMPONENT_ENABLED_STATE_ENABLED) - || (componentInfo.applicationInfo.enabled - && packageSettings.enabled != COMPONENT_ENABLED_STATE_DISABLED)) - && !packageSettings.disabledComponents.contains(componentInfo.name)) - || packageSettings.enabledComponents.contains(componentInfo.name)); - } - } -} diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java deleted file mode 100644 index f41d21f..0000000 --- a/services/java/com/android/server/PowerManagerService.java +++ /dev/null @@ -1,1864 +0,0 @@ -/* - * Copyright (C) 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; - -import com.android.internal.app.IBatteryStats; -import com.android.server.am.BatteryStatsService; - -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.content.BroadcastReceiver; -import android.content.ContentQueryMap; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.os.BatteryStats; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.IPowerManager; -import android.os.LocalPowerManager; -import android.os.Power; -import android.os.PowerManager; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemClock; -import android.provider.Settings.SettingNotFoundException; -import android.provider.Settings; -import android.util.EventLog; -import android.util.Log; -import android.view.WindowManagerPolicy; -import static android.provider.Settings.System.DIM_SCREEN; -import static android.provider.Settings.System.SCREEN_BRIGHTNESS; -import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; -import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; - -class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor { - - private static final String TAG = "PowerManagerService"; - static final String PARTIAL_NAME = "PowerManagerService"; - - private static final boolean LOG_PARTIAL_WL = false; - - // Indicates whether touch-down cycles should be logged as part of the - // LOG_POWER_SCREEN_STATE log events - private static final boolean LOG_TOUCH_DOWNS = true; - - private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK - | PowerManager.SCREEN_DIM_WAKE_LOCK - | PowerManager.SCREEN_BRIGHT_WAKE_LOCK - | PowerManager.FULL_WAKE_LOCK; - - // time since last state: time since last event: - // The short keylight delay comes from Gservices; this is the default. - private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec - private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec - private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec - private static final int LONG_DIM_TIME = 7000; // t+N-5 sec - - // Cached Gservices settings; see updateGservicesValues() - private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT; - - // flags for setPowerState - private static final int SCREEN_ON_BIT = 0x00000001; - private static final int SCREEN_BRIGHT_BIT = 0x00000002; - private static final int BUTTON_BRIGHT_BIT = 0x00000004; - private static final int KEYBOARD_BRIGHT_BIT = 0x00000008; - private static final int BATTERY_LOW_BIT = 0x00000010; - - // values for setPowerState - - // SCREEN_OFF == everything off - private static final int SCREEN_OFF = 0x00000000; - - // SCREEN_DIM == screen on, screen backlight dim - private static final int SCREEN_DIM = SCREEN_ON_BIT; - - // SCREEN_BRIGHT == screen on, screen backlight bright - private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT; - - // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright - private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT; - - // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright - private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT; - - // used for noChangeLights in setPowerState() - private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT; - - static final boolean ANIMATE_SCREEN_LIGHTS = true; - static final boolean ANIMATE_BUTTON_LIGHTS = false; - static final boolean ANIMATE_KEYBOARD_LIGHTS = false; - - static final int ANIM_STEPS = 60/4; - - // These magic numbers are the initial state of the LEDs at boot. Ideally - // we should read them from the driver, but our current hardware returns 0 - // for the initial value. Oops! - static final int INITIAL_SCREEN_BRIGHTNESS = 255; - static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF; - static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF; - - static final int LOG_POWER_SLEEP_REQUESTED = 2724; - static final int LOG_POWER_SCREEN_BROADCAST_SEND = 2725; - static final int LOG_POWER_SCREEN_BROADCAST_DONE = 2726; - static final int LOG_POWER_SCREEN_BROADCAST_STOP = 2727; - static final int LOG_POWER_SCREEN_STATE = 2728; - static final int LOG_POWER_PARTIAL_WAKE_STATE = 2729; - - private final int MY_UID; - - private boolean mDoneBooting = false; - private int mStayOnConditions = 0; - private int mNotificationQueue = -1; - private int mNotificationWhy; - private int mPartialCount = 0; - private int mPowerState; - private boolean mOffBecauseOfUser; - private int mUserState; - private boolean mKeyboardVisible = false; - private boolean mUserActivityAllowed = true; - private int mTotalDelaySetting; - private int mKeylightDelay; - private int mDimDelay; - private int mScreenOffDelay; - private int mWakeLockState; - private long mLastEventTime = 0; - private long mScreenOffTime; - private volatile WindowManagerPolicy mPolicy; - private final LockList mLocks = new LockList(); - private Intent mScreenOffIntent; - private Intent mScreenOnIntent; - private Context mContext; - private UnsynchronizedWakeLock mBroadcastWakeLock; - private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock; - private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock; - private UnsynchronizedWakeLock mPreventScreenOnPartialLock; - private HandlerThread mHandlerThread; - private Handler mHandler; - private TimeoutTask mTimeoutTask = new TimeoutTask(); - private LightAnimator mLightAnimator = new LightAnimator(); - private final BrightnessState mScreenBrightness - = new BrightnessState(Power.SCREEN_LIGHT); - private final BrightnessState mKeyboardBrightness - = new BrightnessState(Power.KEYBOARD_LIGHT); - private final BrightnessState mButtonBrightness - = new BrightnessState(Power.BUTTON_LIGHT); - private boolean mIsPowered = false; - private IActivityManager mActivityService; - private IBatteryStats mBatteryStats; - private BatteryService mBatteryService; - private boolean mDimScreen = true; - private long mNextTimeout; - private volatile int mPokey = 0; - private volatile boolean mPokeAwakeOnSet = false; - private volatile boolean mInitComplete = false; - private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>(); - private long mScreenOnTime; - private long mScreenOnStartTime; - private boolean mPreventScreenOn; - private int mScreenBrightnessOverride = -1; - - // Used when logging number and duration of touch-down cycles - private long mTotalTouchDownTime; - private long mLastTouchDown; - private int mTouchCycles; - - // could be either static or controllable at runtime - private static final boolean mSpew = false; - - /* - static PrintStream mLog; - static { - try { - mLog = new PrintStream("/data/power.log"); - } - catch (FileNotFoundException e) { - android.util.Log.e(TAG, "Life is hard", e); - } - } - static class Log { - static void d(String tag, String s) { - mLog.println(s); - android.util.Log.d(tag, s); - } - static void i(String tag, String s) { - mLog.println(s); - android.util.Log.i(tag, s); - } - static void w(String tag, String s) { - mLog.println(s); - android.util.Log.w(tag, s); - } - static void e(String tag, String s) { - mLog.println(s); - android.util.Log.e(tag, s); - } - } - */ - - /** - * This class works around a deadlock between the lock in PowerManager.WakeLock - * and our synchronizing on mLocks. PowerManager.WakeLock synchronizes on its - * mToken object so it can be accessed from any thread, but it calls into here - * with its lock held. This class is essentially a reimplementation of - * PowerManager.WakeLock, but without that extra synchronized block, because we'll - * only call it with our own locks held. - */ - private class UnsynchronizedWakeLock { - int mFlags; - String mTag; - IBinder mToken; - int mCount = 0; - boolean mRefCounted; - - UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) { - mFlags = flags; - mTag = tag; - mToken = new Binder(); - mRefCounted = refCounted; - } - - public void acquire() { - if (!mRefCounted || mCount++ == 0) { - long ident = Binder.clearCallingIdentity(); - try { - PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, - MY_UID, mTag); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - public void release() { - if (!mRefCounted || --mCount == 0) { - PowerManagerService.this.releaseWakeLockLocked(mToken, false); - } - if (mCount < 0) { - throw new RuntimeException("WakeLock under-locked " + mTag); - } - } - - public String toString() { - return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags) - + " mCount=" + mCount + ")"; - } - } - - private final class BatteryReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mLocks) { - boolean wasPowered = mIsPowered; - mIsPowered = mBatteryService.isPowered(); - - if (mIsPowered != wasPowered) { - // update mStayOnWhilePluggedIn wake lock - updateWakeLockLocked(); - - // treat plugging and unplugging the devices as a user activity. - // users find it disconcerting when they unplug the device - // and it shuts off right away. - // temporarily set mUserActivityAllowed to true so this will work - // even when the keyguard is on. - synchronized (mLocks) { - boolean savedActivityAllowed = mUserActivityAllowed; - mUserActivityAllowed = true; - userActivity(SystemClock.uptimeMillis(), false); - mUserActivityAllowed = savedActivityAllowed; - } - } - } - } - } - - /** - * Set the setting that determines whether the device stays on when plugged in. - * The argument is a bit string, with each bit specifying a power source that, - * when the device is connected to that source, causes the device to stay on. - * See {@link android.os.BatteryManager} for the list of power sources that - * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC} - * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB} - * @param val an {@code int} containing the bits that specify which power sources - * should cause the device to stay on. - */ - public void setStayOnSetting(int val) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.STAY_ON_WHILE_PLUGGED_IN, val); - } - - private class SettingsObserver implements Observer { - private int getInt(String name) { - return mSettings.getValues(name).getAsInteger(Settings.System.VALUE); - } - - public void update(Observable o, Object arg) { - synchronized (mLocks) { - // STAY_ON_WHILE_PLUGGED_IN - mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN); - updateWakeLockLocked(); - - // SCREEN_OFF_TIMEOUT - mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT); - - // DIM_SCREEN - //mDimScreen = getInt(DIM_SCREEN) != 0; - - // recalculate everything - setScreenOffTimeoutsLocked(); - } - } - } - - PowerManagerService() - { - // Hack to get our uid... should have a func for this. - long token = Binder.clearCallingIdentity(); - MY_UID = Binder.getCallingUid(); - Binder.restoreCallingIdentity(token); - - // XXX remove this when the kernel doesn't timeout wake locks - Power.setLastUserActivityTimeout(7*24*3600*1000); // one week - - // assume nothing is on yet - mUserState = mPowerState = 0; - - // Add ourself to the Watchdog monitors. - Watchdog.getInstance().addMonitor(this); - mScreenOnStartTime = SystemClock.elapsedRealtime(); - } - - private ContentQueryMap mSettings; - - void init(Context context, IActivityManager activity, BatteryService battery) { - mContext = context; - mActivityService = activity; - mBatteryStats = BatteryStatsService.getService(); - mBatteryService = battery; - - mHandlerThread = new HandlerThread("PowerManagerService") { - @Override - protected void onLooperPrepared() { - super.onLooperPrepared(); - initInThread(); - } - }; - mHandlerThread.start(); - - synchronized (mHandlerThread) { - while (!mInitComplete) { - try { - mHandlerThread.wait(); - } catch (InterruptedException e) { - // Ignore - } - } - } - } - - void initInThread() { - mHandler = new Handler(); - - mBroadcastWakeLock = new UnsynchronizedWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "sleep_notification", true); - mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock( - PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false); - mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false); - mPreventScreenOnPartialLock = new UnsynchronizedWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false); - - mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); - mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF); - mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - - ContentResolver resolver = mContext.getContentResolver(); - Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null, - "(" + Settings.System.NAME + "=?) or (" - + Settings.System.NAME + "=?) or (" - + Settings.System.NAME + "=?)", - new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN}, - null); - mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler); - SettingsObserver settingsObserver = new SettingsObserver(); - mSettings.addObserver(settingsObserver); - - // pretend that the settings changed so we will get their initial state - settingsObserver.update(mSettings, null); - - // register for the battery changed notifications - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - mContext.registerReceiver(new BatteryReceiver(), filter); - - // Listen for Gservices changes - IntentFilter gservicesChangedFilter = - new IntentFilter(Settings.Gservices.CHANGED_ACTION); - mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter); - // And explicitly do the initial update of our cached settings - updateGservicesValues(); - - // turn everything on - setPowerState(ALL_BRIGHT); - - synchronized (mHandlerThread) { - mInitComplete = true; - mHandlerThread.notifyAll(); - } - } - - private class WakeLock implements IBinder.DeathRecipient - { - WakeLock(int f, IBinder b, String t, int u) { - super(); - flags = f; - binder = b; - tag = t; - uid = u == MY_UID ? Process.SYSTEM_UID : u; - if (u != MY_UID || ( - !"KEEP_SCREEN_ON_FLAG".equals(tag) - && !"KeyInputQueue".equals(tag))) { - monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK - ? BatteryStats.WAKE_TYPE_PARTIAL - : BatteryStats.WAKE_TYPE_FULL; - } else { - monitorType = -1; - } - try { - b.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - public void binderDied() { - synchronized (mLocks) { - releaseWakeLockLocked(this.binder, true); - } - } - final int flags; - final IBinder binder; - final String tag; - final int uid; - final int monitorType; - boolean activated = true; - int minState; - } - - private void updateWakeLockLocked() { - if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { - // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set. - mStayOnWhilePluggedInScreenDimLock.acquire(); - mStayOnWhilePluggedInPartialLock.acquire(); - } else { - mStayOnWhilePluggedInScreenDimLock.release(); - mStayOnWhilePluggedInPartialLock.release(); - } - } - - private boolean isScreenLock(int flags) - { - int n = flags & LOCK_MASK; - return n == PowerManager.FULL_WAKE_LOCK - || n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK - || n == PowerManager.SCREEN_DIM_WAKE_LOCK; - } - - public void acquireWakeLock(int flags, IBinder lock, String tag) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - int uid = Binder.getCallingUid(); - long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLocks) { - acquireWakeLockLocked(flags, lock, uid, tag); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) { - int acquireUid = -1; - String acquireName = null; - int acquireType = -1; - - if (mSpew) { - Log.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag); - } - - int index = mLocks.getIndex(lock); - WakeLock wl; - boolean newlock; - if (index < 0) { - wl = new WakeLock(flags, lock, tag, uid); - switch (wl.flags & LOCK_MASK) - { - case PowerManager.FULL_WAKE_LOCK: - wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT); - break; - case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: - wl.minState = SCREEN_BRIGHT; - break; - case PowerManager.SCREEN_DIM_WAKE_LOCK: - wl.minState = SCREEN_DIM; - break; - case PowerManager.PARTIAL_WAKE_LOCK: - break; - default: - // just log and bail. we're in the server, so don't - // throw an exception. - Log.e(TAG, "bad wakelock type for lock '" + tag + "' " - + " flags=" + flags); - return; - } - mLocks.addLock(wl); - newlock = true; - } else { - wl = mLocks.get(index); - newlock = false; - } - if (isScreenLock(flags)) { - // if this causes a wakeup, we reactivate all of the locks and - // set it to whatever they want. otherwise, we modulate that - // by the current state so we never turn it more on than - // it already is. - if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { - reactivateWakeLocksLocked(); - if (mSpew) { - Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState) - + " mLocks.gatherState()=0x" - + Integer.toHexString(mLocks.gatherState()) - + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); - } - mWakeLockState = mLocks.gatherState(); - } else { - if (mSpew) { - Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState) - + " mLocks.gatherState()=0x" - + Integer.toHexString(mLocks.gatherState()) - + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); - } - mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState(); - } - setPowerState(mWakeLockState | mUserState); - } - else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) { - if (newlock) { - mPartialCount++; - if (mPartialCount == 1) { - if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 1, tag); - } - } - Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME); - } - if (newlock) { - acquireUid = wl.uid; - acquireName = wl.tag; - acquireType = wl.monitorType; - } - - if (acquireType >= 0) { - try { - mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType); - } catch (RemoteException e) { - // Ignore - } - } - } - - public void releaseWakeLock(IBinder lock) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - - synchronized (mLocks) { - releaseWakeLockLocked(lock, false); - } - } - - private void releaseWakeLockLocked(IBinder lock, boolean death) { - int releaseUid; - String releaseName; - int releaseType; - - WakeLock wl = mLocks.removeLock(lock); - if (wl == null) { - return; - } - - if (mSpew) { - Log.d(TAG, "releaseWakeLock flags=0x" - + Integer.toHexString(wl.flags) + " tag=" + wl.tag); - } - - if (isScreenLock(wl.flags)) { - mWakeLockState = mLocks.gatherState(); - // goes in the middle to reduce flicker - if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) { - userActivity(SystemClock.uptimeMillis(), false); - } - setPowerState(mWakeLockState | mUserState); - } - else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) { - mPartialCount--; - if (mPartialCount == 0) { - if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag); - Power.releaseWakeLock(PARTIAL_NAME); - } - } - // Unlink the lock from the binder. - wl.binder.unlinkToDeath(wl, 0); - releaseUid = wl.uid; - releaseName = wl.tag; - releaseType = wl.monitorType; - - if (releaseType >= 0) { - long origId = Binder.clearCallingIdentity(); - try { - mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType); - } catch (RemoteException e) { - // Ignore - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - private void reactivateWakeLocksLocked() - { - int N = mLocks.size(); - for (int i=0; i<N; i++) { - WakeLock wl = mLocks.get(i); - if (isScreenLock(wl.flags)) { - mLocks.get(i).activated = true; - } - } - } - - private class PokeLock implements IBinder.DeathRecipient - { - PokeLock(int p, IBinder b, String t) { - super(); - this.pokey = p; - this.binder = b; - this.tag = t; - try { - b.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - public void binderDied() { - setPokeLock(0, this.binder, this.tag); - } - int pokey; - IBinder binder; - String tag; - boolean awakeOnSet; - } - - public void setPokeLock(int pokey, IBinder token, String tag) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - if (token == null) { - Log.e(TAG, "setPokeLock got null token for tag='" + tag + "'"); - return; - } - - if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) { - throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT" - + " and POKE_LOCK_MEDIUM_TIMEOUT"); - } - - synchronized (mLocks) { - if (pokey != 0) { - PokeLock p = mPokeLocks.get(token); - int oldPokey = 0; - if (p != null) { - oldPokey = p.pokey; - p.pokey = pokey; - } else { - p = new PokeLock(pokey, token, tag); - mPokeLocks.put(token, p); - } - int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK; - int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK; - if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) { - p.awakeOnSet = true; - } - } else { - mPokeLocks.remove(token); - } - - int oldPokey = mPokey; - int cumulative = 0; - boolean oldAwakeOnSet = mPokeAwakeOnSet; - boolean awakeOnSet = false; - for (PokeLock p: mPokeLocks.values()) { - cumulative |= p.pokey; - if (p.awakeOnSet) { - awakeOnSet = true; - } - } - mPokey = cumulative; - mPokeAwakeOnSet = awakeOnSet; - - int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK; - int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK; - - if (oldCumulativeTimeout != newCumulativeTimeout) { - setScreenOffTimeoutsLocked(); - // reset the countdown timer, but use the existing nextState so it doesn't - // change anything - setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState); - } - } - } - - private static String lockType(int type) - { - switch (type) - { - case PowerManager.FULL_WAKE_LOCK: - return "FULL_WAKE_LOCK "; - case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: - return "SCREEN_BRIGHT_WAKE_LOCK"; - case PowerManager.SCREEN_DIM_WAKE_LOCK: - return "SCREEN_DIM_WAKE_LOCK "; - case PowerManager.PARTIAL_WAKE_LOCK: - return "PARTIAL_WAKE_LOCK "; - default: - return "??? "; - } - } - - private static String dumpPowerState(int state) { - return (((state & KEYBOARD_BRIGHT_BIT) != 0) - ? "KEYBOARD_BRIGHT_BIT " : "") - + (((state & SCREEN_BRIGHT_BIT) != 0) - ? "SCREEN_BRIGHT_BIT " : "") - + (((state & SCREEN_ON_BIT) != 0) - ? "SCREEN_ON_BIT " : "") - + (((state & BATTERY_LOW_BIT) != 0) - ? "BATTERY_LOW_BIT " : ""); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump PowerManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - long now = SystemClock.uptimeMillis(); - - pw.println("Power Manager State:"); - pw.println(" mIsPowered=" + mIsPowered - + " mPowerState=" + mPowerState - + " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime) - + " ms"); - pw.println(" mPartialCount=" + mPartialCount); - pw.println(" mWakeLockState=" + dumpPowerState(mWakeLockState)); - pw.println(" mUserState=" + dumpPowerState(mUserState)); - pw.println(" mPowerState=" + dumpPowerState(mPowerState)); - pw.println(" mLocks.gather=" + dumpPowerState(mLocks.gatherState())); - pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now - + " " + ((mNextTimeout-now)/1000) + "s from now"); - pw.println(" mDimScreen=" + mDimScreen - + " mStayOnConditions=" + mStayOnConditions); - pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser - + " mUserState=" + mUserState); - pw.println(" mNotificationQueue=" + mNotificationQueue - + " mNotificationWhy=" + mNotificationWhy); - pw.println(" mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet); - pw.println(" mKeyboardVisible=" + mKeyboardVisible - + " mUserActivityAllowed=" + mUserActivityAllowed); - pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay - + " mScreenOffDelay=" + mScreenOffDelay); - pw.println(" mPreventScreenOn=" + mPreventScreenOn - + " mScreenBrightnessOverride=" + mScreenBrightnessOverride); - pw.println(" mTotalDelaySetting=" + mTotalDelaySetting); - pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock); - pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock); - pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock); - pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock); - mScreenBrightness.dump(pw, " mScreenBrightness: "); - mKeyboardBrightness.dump(pw, " mKeyboardBrightness: "); - mButtonBrightness.dump(pw, " mButtonBrightness: "); - - int N = mLocks.size(); - pw.println(); - pw.println("mLocks.size=" + N + ":"); - for (int i=0; i<N; i++) { - WakeLock wl = mLocks.get(i); - String type = lockType(wl.flags & LOCK_MASK); - String acquireCausesWakeup = ""; - if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { - acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP "; - } - String activated = ""; - if (wl.activated) { - activated = " activated"; - } - pw.println(" " + type + " '" + wl.tag + "'" + acquireCausesWakeup - + activated + " (minState=" + wl.minState + ")"); - } - - pw.println(); - pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":"); - for (PokeLock p: mPokeLocks.values()) { - pw.println(" poke lock '" + p.tag + "':" - + ((p.pokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0 - ? " POKE_LOCK_IGNORE_CHEEK_EVENTS" : "") - + ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0 - ? " POKE_LOCK_SHORT_TIMEOUT" : "") - + ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0 - ? " POKE_LOCK_MEDIUM_TIMEOUT" : "")); - } - - pw.println(); - } - - private void setTimeoutLocked(long now, int nextState) - { - if (mDoneBooting) { - mHandler.removeCallbacks(mTimeoutTask); - mTimeoutTask.nextState = nextState; - long when = now; - switch (nextState) - { - case SCREEN_BRIGHT: - when += mKeylightDelay; - break; - case SCREEN_DIM: - if (mDimDelay >= 0) { - when += mDimDelay; - break; - } else { - Log.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim"); - } - case SCREEN_OFF: - synchronized (mLocks) { - when += mScreenOffDelay; - } - break; - } - if (mSpew) { - Log.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState - + " when=" + when); - } - mHandler.postAtTime(mTimeoutTask, when); - mNextTimeout = when; // for debugging - } - } - - private void cancelTimerLocked() - { - mHandler.removeCallbacks(mTimeoutTask); - mTimeoutTask.nextState = -1; - } - - private class TimeoutTask implements Runnable - { - int nextState; // access should be synchronized on mLocks - public void run() - { - synchronized (mLocks) { - if (mSpew) { - Log.d(TAG, "user activity timeout timed out nextState=" + this.nextState); - } - - if (nextState == -1) { - return; - } - - mUserState = this.nextState; - setPowerState(this.nextState | mWakeLockState); - - long now = SystemClock.uptimeMillis(); - - switch (this.nextState) - { - case SCREEN_BRIGHT: - if (mDimDelay >= 0) { - setTimeoutLocked(now, SCREEN_DIM); - break; - } - case SCREEN_DIM: - setTimeoutLocked(now, SCREEN_OFF); - break; - } - } - } - } - - private void sendNotificationLocked(boolean on, int why) - { - - if (!on) { - mNotificationWhy = why; - } - - int value = on ? 1 : 0; - if (mNotificationQueue == -1) { - // empty - // Acquire the broadcast wake lock before changing the power - // state. It will be release after the broadcast is sent. - mBroadcastWakeLock.acquire(); - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount); - mNotificationQueue = value; - mHandler.post(mNotificationTask); - } else if (mNotificationQueue != value) { - // it's a pair, so cancel it - mNotificationQueue = -1; - mHandler.removeCallbacks(mNotificationTask); - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount); - mBroadcastWakeLock.release(); - } else { - // else, same so do nothing -- maybe we should warn? - Log.w(TAG, "Duplicate notification: on=" + on + " why=" + why); - } - } - - private Runnable mNotificationTask = new Runnable() - { - public void run() - { - int value; - int why; - WindowManagerPolicy policy; - synchronized (mLocks) { - policy = getPolicyLocked(); - value = mNotificationQueue; - why = mNotificationWhy; - mNotificationQueue = -1; - } - if (value == 1) { - mScreenOnStart = SystemClock.uptimeMillis(); - - policy.screenTurnedOn(); - try { - ActivityManagerNative.getDefault().wakingUp(); - } catch (RemoteException e) { - // ignore it - } - - if (mSpew) { - Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock); - } - if (mContext != null) { - if (ActivityManagerNative.isSystemReady()) { - mContext.sendOrderedBroadcast(mScreenOnIntent, null, - mScreenOnBroadcastDone, mHandler, 0, null, null); - } - } else { - synchronized (mLocks) { - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2, - mBroadcastWakeLock.mCount); - mBroadcastWakeLock.release(); - } - } - } - else if (value == 0) { - mScreenOffStart = SystemClock.uptimeMillis(); - - policy.screenTurnedOff(why); - try { - ActivityManagerNative.getDefault().goingToSleep(); - } catch (RemoteException e) { - // ignore it. - } - - if (mContext != null) { - mContext.sendOrderedBroadcast(mScreenOffIntent, null, - mScreenOffBroadcastDone, mHandler, 0, null, null); - } else { - synchronized (mLocks) { - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3, - mBroadcastWakeLock.mCount); - mBroadcastWakeLock.release(); - } - } - } - else { - // If we're in this case, then this handler is running for a previous - // paired transaction. mBroadcastWakeLock will already have been released - // in sendNotificationLocked. - } - } - }; - - long mScreenOnStart; - private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - synchronized (mLocks) { - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 1, - SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount); - mBroadcastWakeLock.release(); - } - } - }; - - long mScreenOffStart; - private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - synchronized (mLocks) { - EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 0, - SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount); - mBroadcastWakeLock.release(); - } - } - }; - - void logPointerUpEvent() { - if (LOG_TOUCH_DOWNS) { - mTotalTouchDownTime += SystemClock.elapsedRealtime() - mLastTouchDown; - mLastTouchDown = 0; - } - } - - void logPointerDownEvent() { - if (LOG_TOUCH_DOWNS) { - // If we are not already timing a down/up sequence - if (mLastTouchDown == 0) { - mLastTouchDown = SystemClock.elapsedRealtime(); - mTouchCycles++; - } - } - } - - /** - * Prevents the screen from turning on even if it *should* turn on due - * to a subsequent full wake lock being acquired. - * <p> - * This is a temporary hack that allows an activity to "cover up" any - * display glitches that happen during the activity's startup - * sequence. (Specifically, this API was added to work around a - * cosmetic bug in the "incoming call" sequence, where the lock screen - * would flicker briefly before the incoming call UI became visible.) - * TODO: There ought to be a more elegant way of doing this, - * probably by having the PowerManager and ActivityManager - * work together to let apps specify that the screen on/off - * state should be synchronized with the Activity lifecycle. - * <p> - * Note that calling preventScreenOn(true) will NOT turn the screen - * off if it's currently on. (This API only affects *future* - * acquisitions of full wake locks.) - * But calling preventScreenOn(false) WILL turn the screen on if - * it's currently off because of a prior preventScreenOn(true) call. - * <p> - * Any call to preventScreenOn(true) MUST be followed promptly by a call - * to preventScreenOn(false). In fact, if the preventScreenOn(false) - * call doesn't occur within 5 seconds, we'll turn the screen back on - * ourselves (and log a warning about it); this prevents a buggy app - * from disabling the screen forever.) - * <p> - * TODO: this feature should really be controlled by a new type of poke - * lock (rather than an IPowerManager call). - */ - public void preventScreenOn(boolean prevent) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - synchronized (mLocks) { - if (prevent) { - // First of all, grab a partial wake lock to - // make sure the CPU stays on during the entire - // preventScreenOn(true) -> preventScreenOn(false) sequence. - mPreventScreenOnPartialLock.acquire(); - - // Post a forceReenableScreen() call (for 5 seconds in the - // future) to make sure the matching preventScreenOn(false) call - // has happened by then. - mHandler.removeCallbacks(mForceReenableScreenTask); - mHandler.postDelayed(mForceReenableScreenTask, 5000); - - // Finally, set the flag that prevents the screen from turning on. - // (Below, in setPowerState(), we'll check mPreventScreenOn and - // we *won't* call Power.setScreenState(true) if it's set.) - mPreventScreenOn = true; - } else { - // (Re)enable the screen. - mPreventScreenOn = false; - - // We're "undoing" a the prior preventScreenOn(true) call, so we - // no longer need the 5-second safeguard. - mHandler.removeCallbacks(mForceReenableScreenTask); - - // Forcibly turn on the screen if it's supposed to be on. (This - // handles the case where the screen is currently off because of - // a prior preventScreenOn(true) call.) - if ((mPowerState & SCREEN_ON_BIT) != 0) { - if (mSpew) { - Log.d(TAG, - "preventScreenOn: turning on after a prior preventScreenOn(true)!"); - } - int err = Power.setScreenState(true); - if (err != 0) { - Log.w(TAG, "preventScreenOn: error from Power.setScreenState(): " + err); - } - } - - // Release the partial wake lock that we held during the - // preventScreenOn(true) -> preventScreenOn(false) sequence. - mPreventScreenOnPartialLock.release(); - } - } - } - - public void setScreenBrightnessOverride(int brightness) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - synchronized (mLocks) { - if (mScreenBrightnessOverride != brightness) { - mScreenBrightnessOverride = brightness; - updateLightsLocked(mPowerState, SCREEN_ON_BIT); - } - } - } - - /** - * Sanity-check that gets called 5 seconds after any call to - * preventScreenOn(true). This ensures that the original call - * is followed promptly by a call to preventScreenOn(false). - */ - private void forceReenableScreen() { - // We shouldn't get here at all if mPreventScreenOn is false, since - // we should have already removed any existing - // mForceReenableScreenTask messages... - if (!mPreventScreenOn) { - Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do"); - return; - } - - // Uh oh. It's been 5 seconds since a call to - // preventScreenOn(true) and we haven't re-enabled the screen yet. - // This means the app that called preventScreenOn(true) is either - // slow (i.e. it took more than 5 seconds to call preventScreenOn(false)), - // or buggy (i.e. it forgot to call preventScreenOn(false), or - // crashed before doing so.) - - // Log a warning, and forcibly turn the screen back on. - Log.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! " - + "Forcing the screen back on..."); - preventScreenOn(false); - } - - private Runnable mForceReenableScreenTask = new Runnable() { - public void run() { - forceReenableScreen(); - } - }; - - private void setPowerState(int state) - { - setPowerState(state, false, false); - } - - private void setPowerState(int newState, boolean noChangeLights, boolean becauseOfUser) - { - synchronized (mLocks) { - int err; - - if (mSpew) { - Log.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState) - + " newState=0x" + Integer.toHexString(newState) - + " noChangeLights=" + noChangeLights); - } - - if (noChangeLights) { - newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK); - } - - if (batteryIsLow()) { - newState |= BATTERY_LOW_BIT; - } else { - newState &= ~BATTERY_LOW_BIT; - } - if (newState == mPowerState) { - return; - } - - if (!mDoneBooting) { - newState |= ALL_BRIGHT; - } - - boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0; - boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0; - - if (mSpew) { - Log.d(TAG, "setPowerState: mPowerState=" + mPowerState - + " newState=" + newState + " noChangeLights=" + noChangeLights); - Log.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0) - + " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0)); - Log.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0) - + " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0)); - Log.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0) - + " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0)); - Log.d(TAG, " oldScreenOn=" + oldScreenOn - + " newScreenOn=" + newScreenOn); - Log.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0) - + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0)); - } - - if (mPowerState != newState) { - err = updateLightsLocked(newState, 0); - if (err != 0) { - return; - } - mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK); - } - - if (oldScreenOn != newScreenOn) { - if (newScreenOn) { - // Turn on the screen UNLESS there was a prior - // preventScreenOn(true) request. (Note that the lifetime - // of a single preventScreenOn() request is limited to 5 - // seconds to prevent a buggy app from disabling the - // screen forever; see forceReenableScreen().) - boolean reallyTurnScreenOn = true; - if (mSpew) { - Log.d(TAG, "- turning screen on... mPreventScreenOn = " - + mPreventScreenOn); - } - - if (mPreventScreenOn) { - if (mSpew) { - Log.d(TAG, "- PREVENTING screen from really turning on!"); - } - reallyTurnScreenOn = false; - } - 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... - err = 0; - } - - mScreenOnStartTime = SystemClock.elapsedRealtime(); - mLastTouchDown = 0; - mTotalTouchDownTime = 0; - mTouchCycles = 0; - EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 1, becauseOfUser ? 1 : 0, - mTotalTouchDownTime, mTouchCycles); - if (err == 0) { - mPowerState |= SCREEN_ON_BIT; - sendNotificationLocked(true, -1); - } - } 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); - } - mPowerState &= ~SCREEN_ON_BIT; - if (!mScreenBrightness.animating) { - err = screenOffFinishedAnimating(becauseOfUser); - } else { - mOffBecauseOfUser = becauseOfUser; - err = 0; - mLastTouchDown = 0; - } - } - } - } - } - - private int screenOffFinishedAnimating(boolean becauseOfUser) { - // I don't think we need to check the current state here because all of these - // Power.setScreenState and sendNotificationLocked can both handle being - // called multiple times in the same state. -joeo - EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0, - mTotalTouchDownTime, mTouchCycles); - mLastTouchDown = 0; - int err = Power.setScreenState(false); - if (mScreenOnStartTime != 0) { - mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime; - mScreenOnStartTime = 0; - } - if (err == 0) { - int why = becauseOfUser - ? WindowManagerPolicy.OFF_BECAUSE_OF_USER - : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT; - sendNotificationLocked(false, why); - } - return err; - } - - private boolean batteryIsLow() { - return (!mIsPowered && - mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD); - } - - private int updateLightsLocked(int newState, int forceState) { - int oldState = mPowerState; - int difference = (newState ^ oldState) | forceState; - if (difference == 0) { - return 0; - } - - int offMask = 0; - int dimMask = 0; - int onMask = 0; - - int preferredBrightness = getPreferredBrightness(); - boolean startAnimation = false; - - if ((difference & KEYBOARD_BRIGHT_BIT) != 0) { - if (ANIMATE_KEYBOARD_LIGHTS) { - if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { - mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF, - ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS); - } else { - mKeyboardBrightness.setTargetLocked(preferredBrightness, - ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS); - } - startAnimation = true; - } else { - if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { - offMask |= Power.KEYBOARD_LIGHT; - } else { - onMask |= Power.KEYBOARD_LIGHT; - } - } - } - - if ((difference & BUTTON_BRIGHT_BIT) != 0) { - if (ANIMATE_BUTTON_LIGHTS) { - if ((newState & BUTTON_BRIGHT_BIT) == 0) { - mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF, - ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS); - } else { - mButtonBrightness.setTargetLocked(preferredBrightness, - ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS); - } - startAnimation = true; - } else { - if ((newState & BUTTON_BRIGHT_BIT) == 0) { - offMask |= Power.BUTTON_LIGHT; - } else { - onMask |= Power.BUTTON_LIGHT; - } - } - } - - if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { - if (ANIMATE_SCREEN_LIGHTS) { - if ((newState & SCREEN_BRIGHT_BIT) == 0) { - // dim or turn off backlight, depending on if the screen is on - // the scale is because the brightness ramp isn't linear and this biases - // it so the later parts take longer. - final float scale = 1.5f; - float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness); - if (ratio > 1.0f) ratio = 1.0f; - if ((newState & SCREEN_ON_BIT) == 0) { - int steps; - if ((oldState & SCREEN_BRIGHT_BIT) != 0) { - // was bright - steps = ANIM_STEPS; - } else { - // was dim - steps = (int)(ANIM_STEPS*ratio*scale); - } - mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_OFF, - steps, INITIAL_SCREEN_BRIGHTNESS); - } else { - int steps; - if ((oldState & SCREEN_ON_BIT) != 0) { - // was bright - steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale); - } else { - // was dim - steps = (int)(ANIM_STEPS*ratio); - } - if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { - // If the "stay on while plugged in" option is - // turned on, then the screen will often not - // automatically turn off while plugged in. To - // still have a sense of when it is inactive, we - // will then count going dim as turning off. - mScreenOffTime = SystemClock.elapsedRealtime(); - } - mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_DIM, - steps, INITIAL_SCREEN_BRIGHTNESS); - } - } else { - mScreenBrightness.setTargetLocked(preferredBrightness, - ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS); - } - startAnimation = true; - } else { - if ((newState & SCREEN_BRIGHT_BIT) == 0) { - // dim or turn off backlight, depending on if the screen is on - if ((newState & SCREEN_ON_BIT) == 0) { - offMask |= Power.SCREEN_LIGHT; - } else { - dimMask |= Power.SCREEN_LIGHT; - } - } else { - onMask |= Power.SCREEN_LIGHT; - } - } - } - - if (startAnimation) { - if (mSpew) { - Log.i(TAG, "Scheduling light animator!"); - } - mHandler.removeCallbacks(mLightAnimator); - mHandler.post(mLightAnimator); - } - - int err = 0; - if (offMask != 0) { - //Log.i(TAG, "Setting brightess off: " + offMask); - err |= Power.setLightBrightness(offMask, Power.BRIGHTNESS_OFF); - } - if (dimMask != 0) { - int brightness = Power.BRIGHTNESS_DIM; - if ((newState & BATTERY_LOW_BIT) != 0 && - brightness > Power.BRIGHTNESS_LOW_BATTERY) { - brightness = Power.BRIGHTNESS_LOW_BATTERY; - } - //Log.i(TAG, "Setting brightess dim " + brightness + ": " + offMask); - err |= Power.setLightBrightness(dimMask, brightness); - } - if (onMask != 0) { - int brightness = getPreferredBrightness(); - if ((newState & BATTERY_LOW_BIT) != 0 && - brightness > Power.BRIGHTNESS_LOW_BATTERY) { - brightness = Power.BRIGHTNESS_LOW_BATTERY; - } - //Log.i(TAG, "Setting brightess on " + brightness + ": " + onMask); - err |= Power.setLightBrightness(onMask, brightness); - } - - return err; - } - - class BrightnessState { - final int mask; - - boolean initialized; - int targetValue; - float curValue; - float delta; - boolean animating; - - BrightnessState(int m) { - mask = m; - } - - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "animating=" + animating - + " targetValue=" + targetValue - + " curValue=" + curValue - + " delta=" + delta); - } - - void setTargetLocked(int target, int stepsToTarget, int initialValue) { - if (!initialized) { - initialized = true; - curValue = (float)initialValue; - } - targetValue = target; - delta = (targetValue-curValue) / stepsToTarget; - if (mSpew) { - Log.i(TAG, "Setting target " + mask + ": cur=" + curValue - + " target=" + targetValue + " delta=" + delta); - } - animating = true; - } - - boolean stepLocked() { - if (!animating) return false; - if (false && mSpew) { - Log.i(TAG, "Step target " + mask + ": cur=" + curValue - + " target=" + targetValue + " delta=" + delta); - } - curValue += delta; - int curIntValue = (int)curValue; - boolean more = true; - if (delta == 0) { - more = false; - } else if (delta > 0) { - if (curIntValue >= targetValue) { - curValue = curIntValue = targetValue; - more = false; - } - } else { - if (curIntValue <= targetValue) { - curValue = curIntValue = targetValue; - more = false; - } - } - //Log.i(TAG, "Animating brightess " + curIntValue + ": " + mask); - Power.setLightBrightness(mask, curIntValue); - animating = more; - if (!more) { - if (mask == Power.SCREEN_LIGHT && curIntValue == Power.BRIGHTNESS_OFF) { - screenOffFinishedAnimating(mOffBecauseOfUser); - } - } - return more; - } - } - - private class LightAnimator implements Runnable { - public void run() { - synchronized (mLocks) { - long now = SystemClock.uptimeMillis(); - boolean more = mScreenBrightness.stepLocked(); - if (mKeyboardBrightness.stepLocked()) { - more = true; - } - if (mButtonBrightness.stepLocked()) { - more = true; - } - if (more) { - mHandler.postAtTime(mLightAnimator, now+(1000/60)); - } - } - } - } - - private int getPreferredBrightness() { - try { - if (mScreenBrightnessOverride >= 0) { - return mScreenBrightnessOverride; - } - final int brightness = Settings.System.getInt(mContext.getContentResolver(), - SCREEN_BRIGHTNESS); - // Don't let applications turn the screen all the way off - return Math.max(brightness, Power.BRIGHTNESS_DIM); - } catch (SettingNotFoundException snfe) { - return Power.BRIGHTNESS_ON; - } - } - - boolean screenIsOn() { - synchronized (mLocks) { - return (mPowerState & SCREEN_ON_BIT) != 0; - } - } - - boolean screenIsBright() { - synchronized (mLocks) { - return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT; - } - } - - public void userActivityWithForce(long time, boolean noChangeLights, boolean force) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - userActivity(time, noChangeLights, OTHER_EVENT, force); - } - - public void userActivity(long time, boolean noChangeLights) { - userActivity(time, noChangeLights, OTHER_EVENT, false); - } - - public void userActivity(long time, boolean noChangeLights, int eventType) { - userActivity(time, noChangeLights, eventType, false); - } - - public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) { - //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - - if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0) - && !((eventType == OTHER_EVENT) || (eventType == BUTTON_EVENT))) { - if (false) { - Log.d(TAG, "dropping mPokey=0x" + Integer.toHexString(mPokey)); - } - return; - } - - if (false) { - if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) { - Log.d(TAG, "userActivity !!!");//, new RuntimeException()); - } else { - Log.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey)); - } - } - - synchronized (mLocks) { - if (mSpew) { - Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time - + " mUserActivityAllowed=" + mUserActivityAllowed - + " mUserState=0x" + Integer.toHexString(mUserState) - + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); - } - if (mLastEventTime <= time || force) { - mLastEventTime = time; - if (mUserActivityAllowed || force) { - // Only turn on button backlights if a button was pressed. - if (eventType == BUTTON_EVENT) { - mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT); - } else { - // don't clear button/keyboard backlights when the screen is touched. - mUserState |= SCREEN_BRIGHT; - } - - reactivateWakeLocksLocked(); - mWakeLockState = mLocks.gatherState(); - setPowerState(mUserState | mWakeLockState, noChangeLights, true); - setTimeoutLocked(time, SCREEN_BRIGHT); - } - } - } - } - - /** - * The user requested that we go to sleep (probably with the power button). - * This overrides all wake locks that are held. - */ - public void goToSleep(long time) - { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - synchronized (mLocks) { - goToSleepLocked(time); - } - } - - /** - * Returns the time the screen has been on since boot, in millis. - * @return screen on time - */ - public long getScreenOnTime() { - synchronized (mLocks) { - if (mScreenOnStartTime == 0) { - return mScreenOnTime; - } else { - return SystemClock.elapsedRealtime() - mScreenOnStartTime + mScreenOnTime; - } - } - } - - private void goToSleepLocked(long time) { - - if (mLastEventTime <= time) { - mLastEventTime = time; - // cancel all of the wake locks - mWakeLockState = SCREEN_OFF; - int N = mLocks.size(); - int numCleared = 0; - for (int i=0; i<N; i++) { - WakeLock wl = mLocks.get(i); - if (isScreenLock(wl.flags)) { - mLocks.get(i).activated = false; - numCleared++; - } - } - EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared); - mUserState = SCREEN_OFF; - setPowerState(SCREEN_OFF, false, true); - cancelTimerLocked(); - } - } - - public long timeSinceScreenOn() { - synchronized (mLocks) { - if ((mPowerState & SCREEN_ON_BIT) != 0) { - return 0; - } - return SystemClock.elapsedRealtime() - mScreenOffTime; - } - } - - public void setKeyboardVisibility(boolean visible) { - mKeyboardVisible = visible; - } - - /** - * When the keyguard is up, it manages the power state, and userActivity doesn't do anything. - */ - public void enableUserActivity(boolean enabled) { - synchronized (mLocks) { - mUserActivityAllowed = enabled; - mLastEventTime = SystemClock.uptimeMillis(); // we might need to pass this in - } - } - - /** Sets the screen off timeouts: - * mKeylightDelay - * mDimDelay - * mScreenOffDelay - * */ - private void setScreenOffTimeoutsLocked() { - if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) { - mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices - mDimDelay = -1; - mScreenOffDelay = 0; - } else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) { - mKeylightDelay = MEDIUM_KEYLIGHT_DELAY; - mDimDelay = -1; - mScreenOffDelay = 0; - } else { - int totalDelay = mTotalDelaySetting; - mKeylightDelay = LONG_KEYLIGHT_DELAY; - if (totalDelay < 0) { - mScreenOffDelay = Integer.MAX_VALUE; - } else if (mKeylightDelay < totalDelay) { - // subtract the time that the keylight delay. This will give us the - // remainder of the time that we need to sleep to get the accurate - // screen off timeout. - mScreenOffDelay = totalDelay - mKeylightDelay; - } else { - mScreenOffDelay = 0; - } - if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) { - mDimDelay = mScreenOffDelay - LONG_DIM_TIME; - mScreenOffDelay = LONG_DIM_TIME; - } else { - mDimDelay = -1; - } - } - if (mSpew) { - Log.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay - + " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay - + " mDimScreen=" + mDimScreen); - } - } - - /** - * Refreshes cached Gservices settings. Called once on startup, and - * on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see - * GservicesChangedReceiver). - */ - private void updateGservicesValues() { - mShortKeylightDelay = Settings.Gservices.getInt( - mContext.getContentResolver(), - Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS, - SHORT_KEYLIGHT_DELAY_DEFAULT); - // Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay); - } - - /** - * Receiver for the Gservices.CHANGED_ACTION broadcast intent, - * which tells us we need to refresh our cached Gservices settings. - */ - private class GservicesChangedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - // Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent); - updateGservicesValues(); - } - } - - private class LockList extends ArrayList<WakeLock> - { - void addLock(WakeLock wl) - { - int index = getIndex(wl.binder); - if (index < 0) { - this.add(wl); - } - } - - WakeLock removeLock(IBinder binder) - { - int index = getIndex(binder); - if (index >= 0) { - return this.remove(index); - } else { - return null; - } - } - - int getIndex(IBinder binder) - { - int N = this.size(); - for (int i=0; i<N; i++) { - if (this.get(i).binder == binder) { - return i; - } - } - return -1; - } - - int gatherState() - { - int result = 0; - int N = this.size(); - for (int i=0; i<N; i++) { - WakeLock wl = this.get(i); - if (wl.activated) { - if (isScreenLock(wl.flags)) { - result |= wl.minState; - } - } - } - return result; - } - } - - void setPolicy(WindowManagerPolicy p) { - synchronized (mLocks) { - mPolicy = p; - mLocks.notifyAll(); - } - } - - WindowManagerPolicy getPolicyLocked() { - while (mPolicy == null || !mDoneBooting) { - try { - mLocks.wait(); - } catch (InterruptedException e) { - // Ignore - } - } - return mPolicy; - } - - void systemReady() { - synchronized (mLocks) { - Log.d(TAG, "system ready!"); - mDoneBooting = true; - userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true); - updateWakeLockLocked(); - mLocks.notifyAll(); - } - } - - public void monitor() { - synchronized (mLocks) { } - } -} diff --git a/services/java/com/android/server/ProcessMap.java b/services/java/com/android/server/ProcessMap.java deleted file mode 100644 index 6b26403..0000000 --- a/services/java/com/android/server/ProcessMap.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2006 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.util.SparseArray; - -import java.util.HashMap; - -public class ProcessMap<E> { - final HashMap<String, SparseArray<E>> mMap - = new HashMap<String, SparseArray<E>>(); - - public E get(String name, int uid) { - SparseArray<E> uids = mMap.get(name); - if (uids == null) return null; - return uids.get(uid); - } - - public E put(String name, int uid, E value) { - SparseArray<E> uids = mMap.get(name); - if (uids == null) { - uids = new SparseArray<E>(2); - mMap.put(name, uids); - } - uids.put(uid, value); - return value; - } - - public void remove(String name, int uid) { - SparseArray<E> uids = mMap.get(name); - if (uids != null) { - uids.remove(uid); - if (uids.size() == 0) { - mMap.remove(name); - } - } - } - - public HashMap<String, SparseArray<E>> getMap() { - return mMap; - } -} diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java deleted file mode 100644 index 55adabb..0000000 --- a/services/java/com/android/server/ProcessStats.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (C) 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; - -import static android.os.Process.*; - -import android.os.Process; -import android.os.SystemClock; -import android.util.Config; -import android.util.Log; - -import java.io.File; -import java.io.FileInputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; - -public class ProcessStats { - private static final String TAG = "ProcessStats"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG || Config.LOGV; - - private static final int[] PROCESS_STATS_FORMAT = new int[] { - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime - }; - - private final long[] mProcessStatsData = new long[2]; - - private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] { - PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime - }; - - private final String[] mProcessFullStatsStringData = new String[3]; - private final long[] mProcessFullStatsData = new long[3]; - - private static final int[] SYSTEM_CPU_FORMAT = new int[] { - PROC_SPACE_TERM|PROC_COMBINE, - PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time - PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time - PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time - PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time - PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time - PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time - PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time - }; - - private final long[] mSystemCpuData = new long[7]; - - private static final int[] LOAD_AVERAGE_FORMAT = new int[] { - PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min - PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins - PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins - }; - - private final float[] mLoadAverageData = new float[3]; - - private final boolean mIncludeThreads; - - private float mLoad1 = 0; - private float mLoad5 = 0; - private float mLoad15 = 0; - - private long mCurrentSampleTime; - private long mLastSampleTime; - - private long mBaseUserTime; - private long mBaseSystemTime; - private long mBaseIoWaitTime; - private long mBaseIrqTime; - private long mBaseSoftIrqTime; - private long mBaseIdleTime; - private int mRelUserTime; - private int mRelSystemTime; - private int mRelIoWaitTime; - private int mRelIrqTime; - private int mRelSoftIrqTime; - private int mRelIdleTime; - - private int[] mCurPids; - private int[] mCurThreadPids; - - private final ArrayList<Stats> mProcStats = new ArrayList<Stats>(); - private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>(); - private boolean mWorkingProcsSorted; - - private boolean mFirst = true; - - private byte[] mBuffer = new byte[256]; - - public static class Stats { - public final int pid; - final String statFile; - final String cmdlineFile; - final String threadsDir; - final ArrayList<Stats> threadStats; - final ArrayList<Stats> workingThreads; - - public String baseName; - public String name; - int nameWidth; - - public long base_utime; - public long base_stime; - public int rel_utime; - public int rel_stime; - - public boolean active; - public boolean added; - public boolean removed; - - Stats(int _pid, int parentPid, boolean includeThreads) { - pid = _pid; - if (parentPid < 0) { - final File procDir = new File("/proc", Integer.toString(pid)); - statFile = new File(procDir, "stat").toString(); - cmdlineFile = new File(procDir, "cmdline").toString(); - threadsDir = (new File(procDir, "task")).toString(); - if (includeThreads) { - threadStats = new ArrayList<Stats>(); - workingThreads = new ArrayList<Stats>(); - } else { - threadStats = null; - workingThreads = null; - } - } else { - final File procDir = new File("/proc", Integer.toString( - parentPid)); - final File taskDir = new File( - new File(procDir, "task"), Integer.toString(pid)); - statFile = new File(taskDir, "stat").toString(); - cmdlineFile = null; - threadsDir = null; - threadStats = null; - workingThreads = null; - } - } - } - - private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() { - public final int - compare(Stats sta, Stats stb) - { - int ta = sta.rel_utime + sta.rel_stime; - int tb = stb.rel_utime + stb.rel_stime; - if (ta != tb) { - return ta > tb ? -1 : 1; - } - if (sta.added != stb.added) { - return sta.added ? -1 : 1; - } - if (sta.removed != stb.removed) { - return sta.added ? -1 : 1; - } - return 0; - } - }; - - - public ProcessStats(boolean includeThreads) { - mIncludeThreads = includeThreads; - } - - public void onLoadChanged(float load1, float load5, float load15) { - } - - public int onMeasureProcessName(String name) { - return 0; - } - - public void init() { - mFirst = true; - update(); - } - - public void update() { - mLastSampleTime = mCurrentSampleTime; - mCurrentSampleTime = SystemClock.uptimeMillis(); - - final float[] loadAverages = mLoadAverageData; - if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT, - null, null, loadAverages)) { - float load1 = loadAverages[0]; - float load5 = loadAverages[1]; - float load15 = loadAverages[2]; - if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) { - mLoad1 = load1; - mLoad5 = load5; - mLoad15 = load15; - onLoadChanged(load1, load5, load15); - } - } - - mCurPids = collectStats("/proc", -1, mFirst, mCurPids, - mProcStats, mWorkingProcs); - mFirst = false; - - final long[] sysCpu = mSystemCpuData; - if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, - null, sysCpu, null)) { - // Total user time is user + nice time. - final long usertime = sysCpu[0]+sysCpu[1]; - // Total system time is simply system time. - final long systemtime = sysCpu[2]; - // Total idle time is simply idle time. - final long idletime = sysCpu[3]; - // Total irq time is iowait + irq + softirq time. - final long iowaittime = sysCpu[4]; - final long irqtime = sysCpu[5]; - final long softirqtime = sysCpu[6]; - - mRelUserTime = (int)(usertime - mBaseUserTime); - mRelSystemTime = (int)(systemtime - mBaseSystemTime); - mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime); - mRelIrqTime = (int)(irqtime - mBaseIrqTime); - mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime); - mRelIdleTime = (int)(idletime - mBaseIdleTime); - - if (false) { - Log.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1] - + " S:" + sysCpu[2] + " I:" + sysCpu[3] - + " W:" + sysCpu[4] + " Q:" + sysCpu[5] - + " O:" + sysCpu[6]); - Log.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime - + " I:" + mRelIdleTime + " Q:" + mRelIrqTime); - } - - mBaseUserTime = usertime; - mBaseSystemTime = systemtime; - mBaseIoWaitTime = iowaittime; - mBaseIrqTime = irqtime; - mBaseSoftIrqTime = softirqtime; - mBaseIdleTime = idletime; - } - - mWorkingProcsSorted = false; - mFirst = false; - } - - private int[] collectStats(String statsFile, int parentPid, boolean first, - int[] curPids, ArrayList<Stats> allProcs, - ArrayList<Stats> workingProcs) { - - workingProcs.clear(); - - int[] pids = Process.getPids(statsFile, curPids); - int NP = (pids == null) ? 0 : pids.length; - int NS = allProcs.size(); - int curStatsIndex = 0; - for (int i=0; i<NP; i++) { - int pid = pids[i]; - if (pid < 0) { - NP = pid; - break; - } - Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null; - - if (st != null && st.pid == pid) { - // Update an existing process... - st.added = false; - curStatsIndex++; - if (localLOGV) Log.v(TAG, "Existing pid " + pid + ": " + st); - - final long[] procStats = mProcessStatsData; - if (!Process.readProcFile(st.statFile.toString(), - PROCESS_STATS_FORMAT, null, procStats, null)) { - continue; - } - - final long utime = procStats[0]; - final long stime = procStats[1]; - - if (utime == st.base_utime && stime == st.base_stime) { - st.rel_utime = 0; - st.rel_stime = 0; - if (st.active) { - st.active = false; - } - continue; - } - - if (!st.active) { - st.active = true; - } - - if (parentPid < 0) { - getName(st, st.cmdlineFile); - if (st.threadStats != null) { - mCurThreadPids = collectStats(st.threadsDir, pid, false, - mCurThreadPids, st.threadStats, - st.workingThreads); - } - } - - st.rel_utime = (int)(utime - st.base_utime); - st.rel_stime = (int)(stime - st.base_stime); - st.base_utime = utime; - st.base_stime = stime; - //Log.i("Load", "Stats changed " + name + " pid=" + st.pid - // + " name=" + st.name + " utime=" + utime - // + " stime=" + stime); - workingProcs.add(st); - continue; - } - - if (st == null || st.pid > pid) { - // We have a new process! - st = new Stats(pid, parentPid, mIncludeThreads); - allProcs.add(curStatsIndex, st); - curStatsIndex++; - NS++; - if (localLOGV) Log.v(TAG, "New pid " + pid + ": " + st); - - final String[] procStatsString = mProcessFullStatsStringData; - final long[] procStats = mProcessFullStatsData; - if (Process.readProcFile(st.statFile.toString(), - PROCESS_FULL_STATS_FORMAT, procStatsString, - procStats, null)) { - st.baseName = parentPid < 0 - ? procStatsString[0] : Integer.toString(pid); - st.base_utime = procStats[1]; - st.base_stime = procStats[2]; - } else { - st.baseName = "<unknown>"; - st.base_utime = st.base_stime = 0; - } - - if (parentPid < 0) { - getName(st, st.cmdlineFile); - } else { - st.name = st.baseName; - st.nameWidth = onMeasureProcessName(st.name); - if (st.threadStats != null) { - mCurThreadPids = collectStats(st.threadsDir, pid, true, - mCurThreadPids, st.threadStats, - st.workingThreads); - } - } - - //Log.i("Load", "New process: " + st.pid + " " + st.name); - st.rel_utime = 0; - st.rel_stime = 0; - st.added = true; - if (!first) { - workingProcs.add(st); - } - continue; - } - - // This process has gone away! - st.rel_utime = 0; - st.rel_stime = 0; - st.removed = true; - workingProcs.add(st); - allProcs.remove(curStatsIndex); - NS--; - if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st); - // Decrement the loop counter so that we process the current pid - // again the next time through the loop. - i--; - continue; - } - - while (curStatsIndex < NS) { - // This process has gone away! - final Stats st = allProcs.get(curStatsIndex); - st.rel_utime = 0; - st.rel_stime = 0; - st.removed = true; - workingProcs.add(st); - allProcs.remove(curStatsIndex); - NS--; - if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st); - } - - return pids; - } - - final public int getLastUserTime() { - return mRelUserTime; - } - - final public int getLastSystemTime() { - return mRelSystemTime; - } - - final public int getLastIoWaitTime() { - return mRelIoWaitTime; - } - - final public int getLastIrqTime() { - return mRelIrqTime; - } - - final public int getLastSoftIrqTime() { - return mRelSoftIrqTime; - } - - final public int getLastIdleTime() { - return mRelIdleTime; - } - - final public float getTotalCpuPercent() { - return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) - / (mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime); - } - - final public int countWorkingStats() { - if (!mWorkingProcsSorted) { - Collections.sort(mWorkingProcs, sLoadComparator); - mWorkingProcsSorted = true; - } - return mWorkingProcs.size(); - } - - final public Stats getWorkingStats(int index) { - return mWorkingProcs.get(index); - } - - final public String printCurrentState() { - if (!mWorkingProcsSorted) { - Collections.sort(mWorkingProcs, sLoadComparator); - mWorkingProcsSorted = true; - } - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.print("Load: "); - pw.print(mLoad1); - pw.print(" / "); - pw.print(mLoad5); - pw.print(" / "); - pw.println(mLoad15); - - long now = SystemClock.uptimeMillis(); - - pw.print("CPU usage from "); - pw.print(now-mLastSampleTime); - pw.print("ms to "); - pw.print(now-mCurrentSampleTime); - pw.println("ms ago:"); - - final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime + mRelIrqTime + - mRelSoftIrqTime + mRelIdleTime; - - int N = mWorkingProcs.size(); - for (int i=0; i<N; i++) { - Stats st = mWorkingProcs.get(i); - printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "), - st.name, totalTime, st.rel_utime, st.rel_stime, 0, 0, 0); - if (!st.removed && st.workingThreads != null) { - int M = st.workingThreads.size(); - for (int j=0; j<M; j++) { - Stats tst = st.workingThreads.get(j); - printProcessCPU(pw, - tst.added ? " +" : (tst.removed ? " -": " "), - tst.name, totalTime, tst.rel_utime, tst.rel_stime, 0, 0, 0); - } - } - } - - printProcessCPU(pw, "", "TOTAL", totalTime, mRelUserTime, mRelSystemTime, mRelIoWaitTime, - mRelIrqTime, mRelSoftIrqTime); - - return sw.toString(); - } - - private void printProcessCPU(PrintWriter pw, String prefix, String label, int totalTime, - int user, int system, int iowait, int irq, int softIrq) { - pw.print(prefix); - pw.print(label); - pw.print(": "); - if (totalTime == 0) totalTime = 1; - pw.print(((user+system+iowait+irq+softIrq)*100)/totalTime); - pw.print("% = "); - pw.print((user*100)/totalTime); - pw.print("% user + "); - pw.print((system*100)/totalTime); - pw.print("% kernel"); - if (iowait > 0) { - pw.print(" + "); - pw.print((iowait*100)/totalTime); - pw.print("% iowait"); - } - if (irq > 0) { - pw.print(" + "); - pw.print((irq*100)/totalTime); - pw.print("% irq"); - } - if (softIrq > 0) { - pw.print(" + "); - pw.print((softIrq*100)/totalTime); - pw.print("% softirq"); - } - pw.println(); - } - - private String readFile(String file, char endChar) { - try { - FileInputStream is = new FileInputStream(file); - int len = is.read(mBuffer); - is.close(); - - if (len > 0) { - int i; - for (i=0; i<len; i++) { - if (mBuffer[i] == endChar) { - break; - } - } - return new String(mBuffer, 0, 0, i); - } - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { - } - return null; - } - - private void getName(Stats st, String cmdlineFile) { - String newName = st.baseName; - if (st.baseName == null || st.baseName.equals("app_process")) { - String cmdName = readFile(cmdlineFile, '\0'); - if (cmdName != null && cmdName.length() > 1) { - newName = cmdName; - int i = newName.lastIndexOf("/"); - if (i > 0 && i < newName.length()-1) { - newName = newName.substring(i+1); - } - } - } - if (st.name == null || !newName.equals(st.name)) { - st.name = newName; - st.nameWidth = onMeasureProcessName(st.name); - } - } -} - diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java deleted file mode 100644 index 29b45ab..0000000 --- a/services/java/com/android/server/SensorService.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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.hardware.ISensorService; -import android.os.Binder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.IBinder; -import android.util.Config; -import android.util.Log; - -import java.util.ArrayList; - -import com.android.internal.app.IBatteryStats; -import com.android.server.am.BatteryStatsService; - - -/** - * Class that manages the device's sensors. It register clients and activate - * the needed sensors. The sensor events themselves are not broadcasted from - * this service, instead, a file descriptor is provided to each client they - * can read events from. - */ - -class SensorService extends ISensorService.Stub { - static final String TAG = SensorService.class.getSimpleName(); - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final int SENSOR_DISABLE = -1; - - /** - * Battery statistics to be updated when sensors are enabled and diabled. - */ - final IBatteryStats mBatteryStats = BatteryStatsService.getService(); - - private final class Listener implements IBinder.DeathRecipient { - final IBinder mToken; - - int mSensors = 0; - int mDelay = 0x7FFFFFFF; - - Listener(IBinder token) { - mToken = token; - } - - void addSensor(int sensor, int delay) { - mSensors |= (1<<sensor); - if (mDelay > delay) - mDelay = delay; - } - - void removeSensor(int sensor) { - mSensors &= ~(1<<sensor); - } - - boolean hasSensor(int sensor) { - return ((mSensors & (1<<sensor)) != 0); - } - - public void binderDied() { - if (localLOGV) Log.d(TAG, "sensor listener died"); - synchronized(mListeners) { - mListeners.remove(this); - mToken.unlinkToDeath(this, 0); - // go through the lists of sensors used by the listener that - // died and deactivate them. - for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { - if (hasSensor(sensor)) { - removeSensor(sensor); - try { - deactivateIfUnused(sensor); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException in binderDied"); - } - } - } - mListeners.notify(); - } - } - } - - @SuppressWarnings("unused") - public SensorService(Context context) { - if (localLOGV) Log.d(TAG, "SensorService startup"); - _sensors_control_init(); - } - - public ParcelFileDescriptor getDataChanel() throws RemoteException { - return _sensors_control_open(); - } - - public boolean enableSensor(IBinder binder, String name, int sensor, int enable) - throws RemoteException { - 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); - } else { - mBatteryStats.noteStartSensor(uid, sensor); - } - Binder.restoreCallingIdentity(identity); - - if (binder == null) throw new NullPointerException("listener is null in enableSensor"); - - synchronized(mListeners) { - if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { - Log.w(TAG, "could not enable sensor " + sensor); - return false; - } - - Listener l = null; - int minDelay = enable; - for (Listener listener : mListeners) { - if (binder == listener.mToken) { - l = listener; - } - if (minDelay > listener.mDelay) - minDelay = listener.mDelay; - } - - if (l == null && enable!=SENSOR_DISABLE) { - l = new Listener(binder); - binder.linkToDeath(l, 0); - mListeners.add(l); - mListeners.notify(); - } - - if (l == null) { - throw new NullPointerException("no Listener object in enableSensor"); - } - - if (minDelay >= 0) { - _sensors_control_set_delay(minDelay); - } - - if (enable != SENSOR_DISABLE) { - l.addSensor(sensor, enable); - } else { - l.removeSensor(sensor); - deactivateIfUnused(sensor); - if (l.mSensors == 0) { - mListeners.remove(l); - binder.unlinkToDeath(l, 0); - mListeners.notify(); - } - } - - if (mListeners.size() == 0) { - _sensors_control_wake(); - } - } - return true; - } - - void deactivateIfUnused(int sensor) throws RemoteException { - int size = mListeners.size(); - for (int i=0 ; i<size ; i++) { - if (mListeners.get(i).hasSensor(sensor)) - return; - } - _sensors_control_activate(sensor, false); - } - - ArrayList<Listener> mListeners = new ArrayList<Listener>(); - - private static native int _sensors_control_init(); - private static native ParcelFileDescriptor _sensors_control_open(); - private static native boolean _sensors_control_activate(int sensor, boolean activate); - private static native int _sensors_control_set_delay(int ms); - private static native int _sensors_control_wake(); -} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java deleted file mode 100644 index fc25e38..0000000 --- a/services/java/com/android/server/SystemServer.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import com.android.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.provider.Contacts.People; -import android.provider.Settings; -import android.server.BluetoothA2dpService; -import android.server.BluetoothDeviceService; -import android.server.search.SearchManagerService; -import android.util.EventLog; -import android.util.Log; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -class ServerThread extends Thread { - private static final String TAG = "SystemServer"; - private final static boolean INCLUDE_DEMO = false; - - private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010; - - private ContentResolver mContentResolver; - - private class AdbSettingsObserver extends ContentObserver { - public AdbSettingsObserver() { - super(null); - } - @Override - public void onChange(boolean selfChange) { - boolean enableAdb = (Settings.Secure.getInt(mContentResolver, - Settings.Secure.ADB_ENABLED, 0) > 0); - // setting this secure property will start or stop adbd - SystemProperties.set("persist.service.adb.enable", enableAdb ? "1" : "0"); - } - } - - @Override - public void run() { - EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN, - SystemClock.uptimeMillis()); - - ActivityManagerService.prepareTraceFile(false); // create dir - - Looper.prepare(); - - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND); - - String factoryTestStr = SystemProperties.get("ro.factorytest"); - int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF - : Integer.parseInt(factoryTestStr); - - PowerManagerService power = null; - IPackageManager pm = null; - Context context = null; - WindowManagerService wm = null; - BluetoothDeviceService bluetooth = null; - BluetoothA2dpService bluetoothA2dp = null; - HeadsetObserver headset = null; - - // Critical services... - try { - Log.i(TAG, "Starting Power Manager."); - power = new PowerManagerService(); - ServiceManager.addService(Context.POWER_SERVICE, power); - - Log.i(TAG, "Starting Activity Manager."); - context = ActivityManagerService.main(factoryTest); - - Log.i(TAG, "Starting telephony registry"); - ServiceManager.addService("telephony.registry", new TelephonyRegistry(context)); - - AttributeCache.init(context); - - Log.i(TAG, "Starting Package Manager."); - pm = PackageManagerService.main(context, - factoryTest != SystemServer.FACTORY_TEST_OFF); - - ActivityManagerService.setSystemProcess(); - - mContentResolver = context.getContentResolver(); - - Log.i(TAG, "Starting Content Manager."); - ContentService.main(context, - factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL); - - Log.i(TAG, "Starting System Content Providers."); - ActivityManagerService.installSystemProviders(); - - Log.i(TAG, "Starting Battery Service."); - BatteryService battery = new BatteryService(context); - ServiceManager.addService("battery", battery); - - // only initialize the power service after we have started the - // content providers and the batter service. - power.init(context, ActivityManagerService.getDefault(), battery); - - Log.i(TAG, "Starting Alarm Manager."); - AlarmManagerService alarm = new AlarmManagerService(context); - ServiceManager.addService(Context.ALARM_SERVICE, alarm); - - Watchdog.getInstance().init(context, battery, power, alarm, - ActivityManagerService.self()); - - // Sensor Service is needed by Window Manager, so this goes first - Log.i(TAG, "Starting Sensor Service."); - ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context)); - - Log.i(TAG, "Starting Window Manager."); - wm = WindowManagerService.main(context, power, - factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL); - ServiceManager.addService(Context.WINDOW_SERVICE, wm); - - ((ActivityManagerService)ServiceManager.getService("activity")) - .setWindowManager(wm); - - // Skip Bluetooth if we have an emulator kernel - // TODO: Use a more reliable check to see if this product should - // support Bluetooth - see bug 988521 - if (SystemProperties.get("ro.kernel.qemu").equals("1")) { - Log.i(TAG, "Registering null Bluetooth Service (emulator)"); - ServiceManager.addService(Context.BLUETOOTH_SERVICE, null); - } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { - Log.i(TAG, "Registering null Bluetooth Service (factory test)"); - ServiceManager.addService(Context.BLUETOOTH_SERVICE, null); - } else { - Log.i(TAG, "Starting Bluetooth Service."); - bluetooth = new BluetoothDeviceService(context); - bluetooth.init(); - ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth); - bluetoothA2dp = new BluetoothA2dpService(context); - ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, - bluetoothA2dp); - - int bluetoothOn = Settings.Secure.getInt(mContentResolver, - Settings.Secure.BLUETOOTH_ON, 0); - if (bluetoothOn > 0) { - bluetooth.enable(null); - } - } - - } catch (RuntimeException e) { - Log.e("System", "Failure starting core service", e); - } - - StatusBarService statusBar = null; - InputMethodManagerService imm = null; - GadgetService gadget = null; - - if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - try { - Log.i(TAG, "Starting Status Bar Service."); - statusBar = new StatusBarService(context); - ServiceManager.addService("statusbar", statusBar); - com.android.server.status.StatusBarPolicy.installIcons(context, statusBar); - } catch (Throwable e) { - Log.e(TAG, "Failure starting StatusBarService", e); - } - - try { - Log.i(TAG, "Starting Clipboard Service."); - ServiceManager.addService("clipboard", new ClipboardService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Clipboard Service", e); - } - - try { - Log.i(TAG, "Starting Input Method Service."); - imm = new InputMethodManagerService(context, statusBar); - ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); - } 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)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Hardware Service", e); - } - - try { - Log.i(TAG, "Starting NetStat Service."); - ServiceManager.addService("netstat", new NetStatService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting NetStat Service", e); - } - - try { - Log.i(TAG, "Starting Connectivity Service."); - ServiceManager.addService(Context.CONNECTIVITY_SERVICE, - ConnectivityService.getInstance(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Connectivity Service", e); - } - - try { - Log.i(TAG, "Starting Notification Manager."); - ServiceManager.addService(Context.NOTIFICATION_SERVICE, - new NotificationManagerService(context, statusBar)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Notification Manager", e); - } - - try { - // MountService must start after NotificationManagerService - Log.i(TAG, "Starting Mount Service."); - ServiceManager.addService("mount", new MountService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Mount Service", e); - } - - try { - Log.i(TAG, "Starting DeviceStorageMonitor service"); - ServiceManager.addService(DeviceStorageMonitorService.SERVICE, - new DeviceStorageMonitorService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting DeviceStorageMonitor service", e); - } - - try { - Log.i(TAG, "Starting Location Manager."); - ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Location Manager", e); - } - - try { - Log.i(TAG, "Starting Search Service."); - ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) ); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Search Service", e); - } - - if (INCLUDE_DEMO) { - Log.i(TAG, "Installing demo data..."); - (new DemoThread(context)).start(); - } - - try { - 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); - } - - try { - Log.i(TAG, "Starting Wallpaper Service"); - ServiceManager.addService(Context.WALLPAPER_SERVICE, new WallpaperService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Wallpaper Service", e); - } - - try { - Log.i(TAG, "Starting Audio Service"); - ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Audio Service", e); - } - - try { - Log.i(TAG, "Starting HeadsetObserver"); - // Listen for wired headset changes - headset = new HeadsetObserver(context); - } catch (Throwable e) { - Log.e(TAG, "Failure starting HeadsetObserver", e); - } - - try { - Log.i(TAG, "Starting Gadget Service"); - gadget = new GadgetService(context); - ServiceManager.addService(Context.GADGET_SERVICE, gadget); - } catch (Throwable e) { - Log.e(TAG, "Failure starting Gadget Service", e); - } - } - - // make sure the ADB_ENABLED setting value matches the secure property value - Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, - "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0); - - // register observer to listen for settings changes - mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED), - false, new AdbSettingsObserver()); - - // It is now time to start up the app processes... - boolean safeMode = wm.detectSafeMode(); - if (statusBar != null) { - statusBar.systemReady(); - } - if (imm != null) { - imm.systemReady(); - } - wm.systemReady(); - power.systemReady(); - try { - pm.systemReady(); - } catch (RemoteException e) { - } - if (gadget != null) { - gadget.systemReady(safeMode); - } - - // After making the following code, third party code may be running... - try { - ActivityManagerNative.getDefault().systemReady(); - } catch (RemoteException e) { - } - - Watchdog.getInstance().start(); - - Looper.loop(); - Log.d(TAG, "System ServerThread is exiting!"); - } -} - -class DemoThread extends Thread -{ - DemoThread(Context context) - { - mContext = context; - } - - @Override - public void run() - { - try { - Cursor c = mContext.getContentResolver().query(People.CONTENT_URI, null, null, null, null); - boolean hasData = c != null && c.moveToFirst(); - if (c != null) { - c.deactivate(); - } - if (!hasData) { - DemoDataSet dataset = new DemoDataSet(); - dataset.add(mContext); - } - } catch (Throwable e) { - Log.e("SystemServer", "Failure installing demo data", e); - } - - } - - Context mContext; -} - -public class SystemServer -{ - private static final String TAG = "SystemServer"; - - public static final int FACTORY_TEST_OFF = 0; - public static final int FACTORY_TEST_LOW_LEVEL = 1; - public static final int FACTORY_TEST_HIGH_LEVEL = 2; - - /** - * This method is called from Zygote to initialize the system. This will cause the native - * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back - * up into init2() to start the Android services. - */ - native public static void init1(String[] args); - - public static void main(String[] args) { - // The system server has to run all of the time, so it needs to be - // as efficient as possible with its memory usage. - VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); - - System.loadLibrary("android_servers"); - init1(args); - } - - public static final void init2() { - Log.i(TAG, "Entered the Android system server!"); - Thread thr = new ServerThread(); - thr.setName("android.server.ServerThread"); - thr.start(); - } -} diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java deleted file mode 100644 index b5cf1aa..0000000 --- a/services/java/com/android/server/TelephonyRegistry.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 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; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.telephony.CellLocation; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import java.util.ArrayList; -import java.io.FileDescriptor; -import java.io.PrintWriter; - -import com.android.internal.telephony.ITelephonyRegistry; -import com.android.internal.telephony.IPhoneStateListener; -import com.android.internal.telephony.DefaultPhoneNotifier; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneStateIntentReceiver; -import com.android.internal.telephony.TelephonyIntents; - - -/** - * Since phone process can be restarted, this class provides a centralized - * place that applications can register and be called back from. - */ -class TelephonyRegistry extends ITelephonyRegistry.Stub { - private static final String TAG = "TelephonyRegistry"; - - private static class Record { - String pkgForDebug; - IBinder binder; - IPhoneStateListener callback; - int events; - } - - private Context mContext; - private ArrayList<Record> mRecords = new ArrayList(); - - private int mCallState = TelephonyManager.CALL_STATE_IDLE; - private String mCallIncomingNumber = ""; - private ServiceState mServiceState = new ServiceState(); - private int mSignalStrength = -1; - private boolean mMessageWaiting = false; - private boolean mCallForwarding = false; - private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; - private int mDataConnectionState = TelephonyManager.DATA_CONNECTED; - private boolean mDataConnectionPossible = false; - private String mDataConnectionReason = ""; - private String mDataConnectionApn = ""; - private String mDataConnectionInterfaceName = ""; - private Bundle mCellLocation = new Bundle(); - - // we keep a copy of all of the sate so we can send it out when folks register for it - // - // In these calls we call with the lock held. This is safe becasuse remote - // calls go through a oneway interface and local calls going through a handler before - // they get to app code. - - TelephonyRegistry(Context context) { - CellLocation.getEmpty().fillInNotifierBundle(mCellLocation); - mContext = context; - } - - public void listen(String pkgForDebug, IPhoneStateListener callback, int events, - boolean notifyNow) { - //Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)); - if (events != 0) { - // check permissions - if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_COARSE_LOCATION, null); - - } - - synchronized (mRecords) { - // register - Record r = null; - find_and_add: { - IBinder b = callback.asBinder(); - final int N = mRecords.size(); - for (int i=0; i<N; i++) { - r = mRecords.get(i); - if (b == r.binder) { - break find_and_add; - } - } - r = new Record(); - r.binder = b; - r.callback = callback; - r.pkgForDebug = pkgForDebug; - mRecords.add(r); - } - int send = events & (events ^ r.events); - r.events = events; - if (notifyNow) { - if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { - sendServiceState(r, mServiceState); - } - if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { - try { - r.callback.onSignalStrengthChanged(mSignalStrength); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { - try { - r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { - try { - r.callback.onCallForwardingIndicatorChanged(mCallForwarding); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { - sendCellLocation(r, mCellLocation); - } - if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { - try { - r.callback.onCallStateChanged(mCallState, mCallIncomingNumber); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { - try { - r.callback.onDataConnectionStateChanged(mDataConnectionState); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { - try { - r.callback.onDataActivity(mDataActivity); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - } else { - remove(callback.asBinder()); - } - } - - private void remove(IBinder binder) { - synchronized (mRecords) { - final int N = mRecords.size(); - for (int i=0; i<N; i++) { - if (mRecords.get(i).binder == binder) { - mRecords.remove(i); - return; - } - } - } - } - - public void notifyCallState(int state, String incomingNumber) { - synchronized (mRecords) { - mCallState = state; - mCallIncomingNumber = incomingNumber; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { - try { - r.callback.onCallStateChanged(state, incomingNumber); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - broadcastCallStateChanged(state, incomingNumber); - } - - public void notifyServiceState(ServiceState state) { - synchronized (mRecords) { - mServiceState = state; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { - sendServiceState(r, state); - } - } - } - broadcastServiceStateChanged(state); - } - - public void notifySignalStrength(int signalStrengthASU) { - synchronized (mRecords) { - mSignalStrength = signalStrengthASU; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { - try { - r.callback.onSignalStrengthChanged(signalStrengthASU); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - broadcastSignalStrengthChanged(signalStrengthASU); - } - - public void notifyMessageWaitingChanged(boolean mwi) { - synchronized (mRecords) { - mMessageWaiting = mwi; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { - try { - r.callback.onMessageWaitingIndicatorChanged(mwi); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - } - - public void notifyCallForwardingChanged(boolean cfi) { - synchronized (mRecords) { - mCallForwarding = cfi; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { - try { - r.callback.onCallForwardingIndicatorChanged(cfi); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - } - - public void notifyDataActivity(int state) { - synchronized (mRecords) { - mDataActivity = state; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { - try { - r.callback.onDataActivity(state); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - } - - public void notifyDataConnection(int state, boolean isDataConnectivityPissible, - String reason, String apn, String interfaceName) { - synchronized (mRecords) { - mDataConnectionState = state; - mDataConnectionPossible = isDataConnectivityPissible; - mDataConnectionReason = reason; - mDataConnectionApn = apn; - mDataConnectionInterfaceName = interfaceName; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { - try { - r.callback.onDataConnectionStateChanged(state); - } catch (RemoteException ex) { - remove(r.binder); - } - } - } - } - broadcastDataConnectionStateChanged(state, isDataConnectivityPissible, - reason, apn, interfaceName); - } - - public void notifyDataConnectionFailed(String reason) { - /* - * This is commented out because there is on onDataConnectionFailed callback - * on PhoneStateListener. There should be. - synchronized (mRecords) { - mDataConnectionFailedReason = reason; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) { - // XXX - } - } - } - */ - broadcastDataConnectionFailed(reason); - } - - public void notifyCellLocation(Bundle cellLocation) { - synchronized (mRecords) { - mCellLocation = cellLocation; - final int N = mRecords.size(); - for (int i=N-1; i>=0; i--) { - Record r = mRecords.get(i); - if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) { - sendCellLocation(r, cellLocation); - } - } - } - } - - // - // the new callback broadcasting - // - // copy the service state object so they can't mess it up in the local calls - // - public void sendServiceState(Record r, ServiceState state) { - try { - r.callback.onServiceStateChanged(new ServiceState(state)); - } catch (RemoteException ex) { - remove(r.binder); - } - } - - public void sendCellLocation(Record r, Bundle cellLocation) { - try { - r.callback.onCellLocationChanged(new Bundle(cellLocation)); - } catch (RemoteException ex) { - remove(r.binder); - } - } - - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump telephony.registry from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - synchronized (mRecords) { - final int N = mRecords.size(); - pw.println("last known state:"); - pw.println(" mCallState=" + mCallState); - pw.println(" mCallIncomingNumber=" + mCallIncomingNumber); - pw.println(" mServiceState=" + mServiceState); - pw.println(" mSignalStrength=" + mSignalStrength); - pw.println(" mMessageWaiting=" + mMessageWaiting); - pw.println(" mCallForwarding=" + mCallForwarding); - pw.println(" mDataActivity=" + mDataActivity); - pw.println(" mDataConnectionState=" + mDataConnectionState); - pw.println(" mDataConnectionPossible=" + mDataConnectionPossible); - pw.println(" mDataConnectionReason=" + mDataConnectionReason); - pw.println(" mDataConnectionApn=" + mDataConnectionApn); - pw.println(" mDataConnectionInterfaceName=" + mDataConnectionInterfaceName); - pw.println(" mCellLocation=" + mCellLocation); - pw.println("registrations: count=" + N); - for (int i=0; i<N; i++) { - Record r = mRecords.get(i); - pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events)); - } - } - } - - - // - // the legacy intent broadcasting - // - - private void broadcastServiceStateChanged(ServiceState state) { - Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); - Bundle data = new Bundle(); - state.fillInNotifierBundle(data); - intent.putExtras(data); - mContext.sendStickyBroadcast(intent); - } - - private void broadcastSignalStrengthChanged(int asu) { - Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); - intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu); - mContext.sendStickyBroadcast(intent); - } - - private void broadcastCallStateChanged(int state, String incomingNumber) { - Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - intent.putExtra(Phone.STATE_KEY, - DefaultPhoneNotifier.convertCallState(state).toString()); - if (!TextUtils.isEmpty(incomingNumber)) { - intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); - } - mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); - } - - private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, - String reason, String apn, String interfaceName) { - Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString()); - if (!isDataConnectivityPossible) { - intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true); - } - if (reason != null) { - intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason); - } - intent.putExtra(Phone.DATA_APN_KEY, apn); - intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName); - mContext.sendStickyBroadcast(intent); - } - - private void broadcastDataConnectionFailed(String reason) { - Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - intent.putExtra(Phone.FAILURE_REASON_KEY, reason); - mContext.sendStickyBroadcast(intent); - } -} diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java deleted file mode 100644 index 4201b39..0000000 --- a/services/java/com/android/server/ViewServer.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 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; - -import android.util.Log; - -import java.net.ServerSocket; -import java.net.Socket; -import java.net.InetAddress; -import java.io.IOException; -import java.io.BufferedReader; -import java.io.InputStreamReader; - -/** - * The ViewServer is local socket server that can be used to communicate with the - * views of the opened windows. Communication with the views is ensured by the - * {@link com.android.server.WindowManagerService} and is a cross-process operation. - * - * {@hide} - */ -class ViewServer implements Runnable { - /** - * The default port used to start view servers. - */ - public static final int VIEW_SERVER_DEFAULT_PORT = 4939; - - // Debug facility - private static final String LOG_TAG = "ViewServer"; - - // Protocol commands - // Lists all of the available windows in the system - private static final String COMMAND_WINDOW_MANAGER_LIST = "LIST"; - - private ServerSocket mServer; - private Thread mThread; - - private final WindowManagerService mWindowManager; - private final int mPort; - - /** - * Creates a new ViewServer associated with the specified window manager. - * The server uses the default port {@link #VIEW_SERVER_DEFAULT_PORT}. The server - * is not started by default. - * - * @param windowManager The window manager used to communicate with the views. - * - * @see #start() - */ - ViewServer(WindowManagerService windowManager) { - this(windowManager, VIEW_SERVER_DEFAULT_PORT); - } - - /** - * Creates a new ViewServer associated with the specified window manager on the - * specified local port. The server is not started by default. - * - * @param windowManager The window manager used to communicate with the views. - * @param port The port for the server to listen to. - * - * @see #start() - */ - ViewServer(WindowManagerService windowManager, int port) { - mWindowManager = windowManager; - mPort = port; - } - - /** - * Starts the server. - * - * @return True if the server was successfully created, or false if it already exists. - * @throws IOException If the server cannot be created. - * - * @see #stop() - * @see #isRunning() - * @see WindowManagerService#startViewServer(int) - */ - boolean start() throws IOException { - if (mThread != null) { - return false; - } - - mServer = new ServerSocket(mPort, 1, InetAddress.getLocalHost()); - mThread = new Thread(this, "Remote View Server [port=" + mPort + "]"); - mThread.start(); - - return true; - } - - /** - * Stops the server. - * - * @return True if the server was stopped, false if an error occured or if the - * server wasn't started. - * - * @see #start() - * @see #isRunning() - * @see WindowManagerService#stopViewServer() - */ - boolean stop() { - if (mThread != null) { - mThread.interrupt(); - mThread = null; - try { - mServer.close(); - mServer = null; - return true; - } catch (IOException e) { - Log.w(LOG_TAG, "Could not close the view server"); - } - } - return false; - } - - /** - * Indicates whether the server is currently running. - * - * @return True if the server is running, false otherwise. - * - * @see #start() - * @see #stop() - * @see WindowManagerService#isViewServerRunning() - */ - boolean isRunning() { - return mThread != null && mThread.isAlive(); - } - - /** - * Main server loop. - */ - public void run() { - final ServerSocket server = mServer; - - while (Thread.currentThread() == mThread) { - Socket client = null; - // Any uncaught exception will crash the system process - try { - client = server.accept(); - - BufferedReader in = null; - try { - in = new BufferedReader(new InputStreamReader(client.getInputStream()), 1024); - - final String request = in.readLine(); - - String command; - String parameters; - - int index = request.indexOf(' '); - if (index == -1) { - command = request; - parameters = ""; - } else { - command = request.substring(0, index); - parameters = request.substring(index + 1); - } - - boolean result; - if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) { - result = mWindowManager.viewServerListWindows(client); - } else { - result = mWindowManager.viewServerWindowCommand(client, - command, parameters); - } - - if (!result) { - Log.w(LOG_TAG, "An error occured with the command: " + command); - } - } finally { - if (in != null) { - in.close(); - } - } - } catch (Exception e) { - Log.w(LOG_TAG, "Connection error: ", e); - } finally { - if (client != null) { - try { - client.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - } -} diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java deleted file mode 100644 index 5532894..0000000 --- a/services/java/com/android/server/WallpaperService.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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 static android.os.FileObserver.*; -import static android.os.ParcelFileDescriptor.*; -import android.app.IWallpaperService; -import android.app.IWallpaperServiceCallback; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.RemoteException; -import android.os.FileObserver; -import android.os.ParcelFileDescriptor; -import android.os.RemoteCallbackList; -import android.util.Config; -import android.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; - -class WallpaperService extends IWallpaperService.Stub { - private static final String TAG = WallpaperService.class.getSimpleName(); - - private static final File WALLPAPER_DIR = new File( - "/data/data/com.android.settings/files"); - private static final String WALLPAPER = "wallpaper"; - private static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER); - - private static final String PREFERENCES = "wallpaper-hints"; - - private static final String HINT_WIDTH = "hintWidth"; - private static final String HINT_HEIGHT = "hintHeight"; - - /** - * List of callbacks registered they should each be notified - * when the wallpaper is changed. - */ - private final RemoteCallbackList<IWallpaperServiceCallback> mCallbacks - = new RemoteCallbackList<IWallpaperServiceCallback>(); - - /** - * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks - * that the wallpaper has changed. The CREATE is triggered when there is no - * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered - * everytime the wallpaper is changed. - */ - private final FileObserver mWallpaperObserver = new FileObserver( - WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE) { - @Override - public void onEvent(int event, String path) { - if (path == null) { - return; - } - - File changedFile = new File(WALLPAPER_DIR, path); - if (WALLPAPER_FILE.equals(changedFile)) { - notifyCallbacks(); - } - } - }; - - private final Context mContext; - - private int mWidth = -1; - private int mHeight = -1; - - public WallpaperService(Context context) { - if (Config.LOGD) Log.d(TAG, "WallpaperService startup"); - mContext = context; - createFilesDir(); - mWallpaperObserver.startWatching(); - - SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, - Context.MODE_PRIVATE); - mWidth = preferences.getInt(HINT_WIDTH, -1); - mHeight = preferences.getInt(HINT_HEIGHT, -1); - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - mWallpaperObserver.stopWatching(); - } - - public void clearWallpaper() { - File f = WALLPAPER_FILE; - if (f.exists()) { - f.delete(); - } - } - - public void setDimensionHints(int width, int height) throws RemoteException { - checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); - - if (width <= 0 || height <= 0) { - throw new IllegalArgumentException("width and height must be > 0"); - } - - if (width != mWidth || height != mHeight) { - mWidth = width; - mHeight = height; - - SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, - Context.MODE_PRIVATE); - - final SharedPreferences.Editor editor = preferences.edit(); - editor.putInt(HINT_WIDTH, width); - editor.putInt(HINT_HEIGHT, height); - editor.commit(); - } - } - - public int getWidthHint() throws RemoteException { - return mWidth; - } - - public int getHeightHint() throws RemoteException { - return mHeight; - } - - public ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb) { - try { - mCallbacks.register(cb); - File f = WALLPAPER_FILE; - if (!f.exists()) { - return null; - } - return ParcelFileDescriptor.open(f, MODE_READ_ONLY); - } catch (FileNotFoundException e) { - - /* Shouldn't happen as we check to see if the file exists */ - if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e); - } - return null; - } - - public ParcelFileDescriptor setWallpaper() { - checkPermission(android.Manifest.permission.SET_WALLPAPER); - try { - return ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE); - } catch (FileNotFoundException e) { - if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e); - } - return null; - } - - private void createFilesDir() { - if (!WALLPAPER_DIR.exists()) { - WALLPAPER_DIR.mkdirs(); - } - } - - private void notifyCallbacks() { - final int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onWallpaperChanged(); - } catch (RemoteException e) { - - // The RemoteCallbackList will take care of removing - // the dead object for us. - } - } - mCallbacks.finishBroadcast(); - final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); - mContext.sendBroadcast(intent); - } - - private void checkPermission(String permission) { - if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) { - throw new SecurityException("Access denied to process: " + Binder.getCallingPid() - + ", must have permission " + permission); - } - } -} diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java deleted file mode 100644 index fef3598..0000000 --- a/services/java/com/android/server/Watchdog.java +++ /dev/null @@ -1,855 +0,0 @@ -/* - * 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 com.android.server.am.ActivityManagerService; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Debug; -import android.os.Handler; -import android.os.Message; -import android.os.Process; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.provider.Settings; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; - -/** This class calls its monitor every minute. Killing this process if they don't return **/ -public class Watchdog extends Thread { - static final String TAG = "Watchdog"; - static final boolean localLOGV = false || Config.LOGV; - - // Set this to true to use debug default values. - static final boolean DB = false; - - static final int MONITOR = 2718; - static final int GLOBAL_PSS = 2719; - - static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000; - static final int EVENT_LOG_TAG = 2802; - static final int EVENT_LOG_PROC_PSS_TAG = 2803; - static final int EVENT_LOG_SOFT_RESET_TAG = 2804; - static final int EVENT_LOG_HARD_RESET_TAG = 2805; - static final int EVENT_LOG_PSS_STATS_TAG = 2806; - static final int EVENT_LOG_PROC_STATS_TAG = 2807; - static final int EVENT_LOG_SCHEDULED_REBOOT_TAG = 2808; - static final int EVENT_LOG_MEMINFO_TAG = 2809; - static final int EVENT_LOG_VMSTAT_TAG = 2810; - static final int EVENT_LOG_REQUESTED_REBOOT_TAG = 2811; - - static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes - static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours - static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB - static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB - static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB - static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB - - static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am - static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am - static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes - static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes - static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes - - static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot - static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am - static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour - - static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP"; - static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT"; - - static Watchdog sWatchdog; - - /* This handler will be used to post message back onto the main thread */ - final Handler mHandler; - final Runnable mGlobalPssCollected; - final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>(); - ContentResolver mResolver; - BatteryService mBattery; - PowerManagerService mPower; - AlarmManagerService mAlarm; - ActivityManagerService mActivity; - boolean mCompleted; - boolean mForceKillSystem; - Monitor mCurrentMonitor; - - PssRequestor mPhoneReq; - int mPhonePid; - int mPhonePss; - - long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000); - boolean mHavePss; - long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000); - boolean mHaveGlobalPss; - final MemMonitor mSystemMemMonitor = new MemMonitor("system", - Settings.Gservices.MEMCHECK_SYSTEM_ENABLED, - Settings.Gservices.MEMCHECK_SYSTEM_SOFT_THRESHOLD, - MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD, - Settings.Gservices.MEMCHECK_SYSTEM_HARD_THRESHOLD, - MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD); - final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone", - Settings.Gservices.MEMCHECK_PHONE_ENABLED, - Settings.Gservices.MEMCHECK_PHONE_SOFT_THRESHOLD, - MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD, - Settings.Gservices.MEMCHECK_PHONE_HARD_THRESHOLD, - MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD); - - final Calendar mCalendar = Calendar.getInstance(); - long mMemcheckLastTime; - long mMemcheckExecStartTime; - long mMemcheckExecEndTime; - int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; - int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM; - boolean mNeedScheduledCheck; - PendingIntent mCheckupIntent; - PendingIntent mRebootIntent; - - long mBootTime; - int mRebootInterval; - - boolean mReqRebootNoWait; // should wait for one interval before reboot? - int mReqRebootInterval = -1; // >= 0 if a reboot has been requested - int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested - int mReqRebootWindow = -1; // >= 0 if a specific window has been requested - int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested - int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested - int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested - - /** - * This class monitors the memory in a particular process. - */ - final class MemMonitor { - final String mProcessName; - final String mEnabledSetting; - final String mSoftSetting; - final String mHardSetting; - - int mSoftThreshold; - int mHardThreshold; - boolean mEnabled; - long mLastPss; - - static final int STATE_OK = 0; - static final int STATE_SOFT = 1; - static final int STATE_HARD = 2; - int mState; - - MemMonitor(String processName, String enabledSetting, - String softSetting, int defSoftThreshold, - String hardSetting, int defHardThreshold) { - mProcessName = processName; - mEnabledSetting = enabledSetting; - mSoftSetting = softSetting; - mHardSetting = hardSetting; - mSoftThreshold = defSoftThreshold; - mHardThreshold = defHardThreshold; - } - - void retrieveSettings(ContentResolver resolver) { - mSoftThreshold = Settings.Gservices.getInt( - resolver, mSoftSetting, mSoftThreshold); - mHardThreshold = Settings.Gservices.getInt( - resolver, mHardSetting, mHardThreshold); - mEnabled = Settings.Gservices.getInt( - resolver, mEnabledSetting, 0) != 0; - } - - boolean checkLocked(long curTime, int pid, int pss) { - mLastPss = pss; - if (mLastPss < mSoftThreshold) { - mState = STATE_OK; - } else if (mLastPss < mHardThreshold) { - mState = STATE_SOFT; - } else { - mState = STATE_HARD; - } - EventLog.writeEvent(EVENT_LOG_PROC_PSS_TAG, mProcessName, pid, mLastPss); - - if (mState == STATE_OK) { - // Memory is good, don't recover. - return false; - } - - if (mState == STATE_HARD) { - // Memory is really bad, kill right now. - EventLog.writeEvent(EVENT_LOG_HARD_RESET_TAG, mProcessName, pid, - mHardThreshold, mLastPss); - return mEnabled; - } - - // It is time to schedule a reset... - // Check if we are currently within the time to kill processes due - // to memory use. - computeMemcheckTimesLocked(curTime); - String skipReason = null; - if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) { - skipReason = "time"; - } else { - skipReason = shouldWeBeBrutalLocked(curTime); - } - EventLog.writeEvent(EVENT_LOG_SOFT_RESET_TAG, mProcessName, pid, - mSoftThreshold, mLastPss, skipReason != null ? skipReason : ""); - if (skipReason != null) { - mNeedScheduledCheck = true; - return false; - } - return mEnabled; - } - - void clear() { - mLastPss = 0; - mState = STATE_OK; - } - } - - /** - * Used for scheduling monitor callbacks and checking memory usage. - */ - final class HeartbeatHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case GLOBAL_PSS: { - if (mHaveGlobalPss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHaveGlobalPss = false; - if (localLOGV) Log.v(TAG, "Received global pss, logging."); - logGlobalMemory(); - } - } break; - - case MONITOR: { - if (mHavePss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHavePss = false; - if (localLOGV) Log.v(TAG, "Have pss, checking memory."); - checkMemory(); - } - - if (mHaveGlobalPss) { - // During the last pass we collected pss information, so - // now it is time to report it. - mHaveGlobalPss = false; - if (localLOGV) Log.v(TAG, "Have global pss, logging."); - logGlobalMemory(); - } - - long now = SystemClock.uptimeMillis(); - - // See if we should force a reboot. - int rebootInterval = mReqRebootInterval >= 0 - ? mReqRebootInterval : Settings.Gservices.getInt( - mResolver, Settings.Gservices.REBOOT_INTERVAL, - REBOOT_DEFAULT_INTERVAL); - if (mRebootInterval != rebootInterval) { - mRebootInterval = rebootInterval; - // We have been running long enough that a reboot can - // be considered... - checkReboot(false); - } - - // See if we should check memory conditions. - long memCheckInterval = Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_INTERVAL, - MEMCHECK_DEFAULT_INTERVAL) * 1000; - if ((mLastMemCheckTime+memCheckInterval) < now) { - // It is now time to collect pss information. This - // is async so we won't report it now. And to keep - // things simple, we will assume that everyone has - // reported back by the next MONITOR message. - mLastMemCheckTime = now; - if (localLOGV) Log.v(TAG, "Collecting memory usage."); - collectMemory(); - mHavePss = true; - - long memCheckRealtimeInterval = Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_LOG_REALTIME_INTERVAL, - MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000; - long realtimeNow = SystemClock.elapsedRealtime(); - if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) { - mLastMemCheckRealtime = realtimeNow; - if (localLOGV) Log.v(TAG, "Collecting global memory usage."); - collectGlobalMemory(); - mHaveGlobalPss = true; - } - } - - final int size = mMonitors.size(); - for (int i = 0 ; i < size ; i++) { - mCurrentMonitor = mMonitors.get(i); - mCurrentMonitor.monitor(); - } - - synchronized (Watchdog.this) { - mCompleted = true; - mCurrentMonitor = null; - } - } break; - } - } - } - - final class GlobalPssCollected implements Runnable { - public void run() { - mHandler.sendEmptyMessage(GLOBAL_PSS); - } - } - - final class CheckupReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context c, Intent intent) { - if (localLOGV) Log.v(TAG, "Alarm went off, checking memory."); - checkMemory(); - } - } - - final class RebootReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context c, Intent intent) { - if (localLOGV) Log.v(TAG, "Alarm went off, checking reboot."); - checkReboot(true); - } - } - - final class RebootRequestReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context c, Intent intent) { - mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0; - mReqRebootInterval = intent.getIntExtra("interval", -1); - mReqRebootStartTime = intent.getIntExtra("startTime", -1); - mReqRebootWindow = intent.getIntExtra("window", -1); - mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1); - mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1); - mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1); - EventLog.writeEvent(EVENT_LOG_REQUESTED_REBOOT_TAG, - mReqRebootNoWait ? 1 : 0, mReqRebootInterval, - mReqRecheckInterval, mReqRebootStartTime, - mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm); - checkReboot(true); - } - } - - public interface Monitor { - void monitor(); - } - - public interface PssRequestor { - void requestPss(); - } - - public class PssStats { - public int mEmptyPss; - public int mEmptyCount; - public int mBackgroundPss; - public int mBackgroundCount; - public int mServicePss; - public int mServiceCount; - public int mVisiblePss; - public int mVisibleCount; - public int mForegroundPss; - public int mForegroundCount; - - public int mNoPssCount; - - public int mProcDeaths[] = new int[10]; - } - - public static Watchdog getInstance() { - if (sWatchdog == null) { - sWatchdog = new Watchdog(); - } - - return sWatchdog; - } - - private Watchdog() { - super("watchdog"); - mHandler = new HeartbeatHandler(); - mGlobalPssCollected = new GlobalPssCollected(); - } - - public void init(Context context, BatteryService battery, - PowerManagerService power, AlarmManagerService alarm, - ActivityManagerService activity) { - mResolver = context.getContentResolver(); - mBattery = battery; - mPower = power; - mAlarm = alarm; - mActivity = activity; - - context.registerReceiver(new CheckupReceiver(), - new IntentFilter(CHECKUP_ACTION)); - mCheckupIntent = PendingIntent.getBroadcast(context, - 0, new Intent(CHECKUP_ACTION), 0); - - context.registerReceiver(new RebootReceiver(), - new IntentFilter(REBOOT_ACTION)); - mRebootIntent = PendingIntent.getBroadcast(context, - 0, new Intent(REBOOT_ACTION), 0); - - context.registerReceiver(new RebootRequestReceiver(), - new IntentFilter(Intent.ACTION_REBOOT), - android.Manifest.permission.REBOOT, null); - - mBootTime = System.currentTimeMillis(); - } - - public void processStarted(PssRequestor req, String name, int pid) { - synchronized (this) { - if ("com.android.phone".equals(name)) { - mPhoneReq = req; - mPhonePid = pid; - mPhonePss = 0; - } - } - } - - public void reportPss(PssRequestor req, String name, int pss) { - synchronized (this) { - if (mPhoneReq == req) { - mPhonePss = pss; - } - } - } - - public void addMonitor(Monitor monitor) { - synchronized (this) { - if (isAlive()) { - throw new RuntimeException("Monitors can't be added while the Watchdog is running"); - } - mMonitors.add(monitor); - } - } - - /** - * Retrieve memory usage information from specific processes being - * monitored. This is an async operation, so must be done before doing - * memory checks. - */ - void collectMemory() { - synchronized (this) { - if (mPhoneReq != null) { - mPhoneReq.requestPss(); - } - } - } - - /** - * Retrieve memory usage over all application processes. This is an - * async operation, so must be done before doing memory checks. - */ - void collectGlobalMemory() { - mActivity.requestPss(mGlobalPssCollected); - } - - /** - * Check memory usage in the system, scheduling kills/reboots as needed. - * This always runs on the mHandler thread. - */ - void checkMemory() { - boolean needScheduledCheck; - long curTime; - long nextTime = 0; - - long recheckInterval = Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL, - MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000; - - mSystemMemMonitor.retrieveSettings(mResolver); - mPhoneMemMonitor.retrieveSettings(mResolver); - retrieveBrutalityAmount(); - - synchronized (this) { - curTime = System.currentTimeMillis(); - mNeedScheduledCheck = false; - - // How is the system doing? - if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(), - (int)Process.getPss(Process.myPid()))) { - // Not good! Time to suicide. - mForceKillSystem = true; - notifyAll(); - return; - } - - // How is the phone process doing? - if (mPhoneReq != null) { - if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid, - mPhonePss)) { - // Just kill the phone process and let it restart. - Process.killProcess(mPhonePid); - } - } else { - mPhoneMemMonitor.clear(); - } - - needScheduledCheck = mNeedScheduledCheck; - if (needScheduledCheck) { - // Something is going bad, but now is not a good time to - // tear things down... schedule an alarm to check again soon. - nextTime = curTime + recheckInterval; - if (nextTime < mMemcheckExecStartTime) { - nextTime = mMemcheckExecStartTime; - } else if (nextTime >= mMemcheckExecEndTime){ - // Need to check during next exec time... so that needs - // to be computed. - if (localLOGV) Log.v(TAG, "Computing next time range"); - computeMemcheckTimesLocked(nextTime); - nextTime = mMemcheckExecStartTime; - } - - if (localLOGV) { - mCalendar.setTimeInMillis(nextTime); - Log.v(TAG, "Next Alarm Time: " + mCalendar); - } - } - } - - if (needScheduledCheck) { - if (localLOGV) Log.v(TAG, "Scheduling next memcheck alarm for " - + ((nextTime-curTime)/1000/60) + "m from now"); - mAlarm.remove(mCheckupIntent); - mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent); - } else { - if (localLOGV) Log.v(TAG, "No need to schedule a memcheck alarm!"); - mAlarm.remove(mCheckupIntent); - } - } - - final PssStats mPssStats = new PssStats(); - final String[] mMemInfoFields = new String[] { - "MemFree:", "Buffers:", "Cached:", - "Active:", "Inactive:", - "AnonPages:", "Mapped:", "Slab:", - "SReclaimable:", "SUnreclaim:", "PageTables:" }; - final long[] mMemInfoSizes = new long[mMemInfoFields.length]; - final String[] mVMStatFields = new String[] { - "pgfree ", "pgactivate ", "pgdeactivate ", - "pgfault ", "pgmajfault " }; - final long[] mVMStatSizes = new long[mVMStatFields.length]; - final long[] mPrevVMStatSizes = new long[mVMStatFields.length]; - long mLastLogGlobalMemoryTime; - - void logGlobalMemory() { - PssStats stats = mPssStats; - mActivity.collectPss(stats); - EventLog.writeEvent(EVENT_LOG_PSS_STATS_TAG, - stats.mEmptyPss, stats.mEmptyCount, - stats.mBackgroundPss, stats.mBackgroundCount, - stats.mServicePss, stats.mServiceCount, - stats.mVisiblePss, stats.mVisibleCount, - stats.mForegroundPss, stats.mForegroundCount, - stats.mNoPssCount); - EventLog.writeEvent(EVENT_LOG_PROC_STATS_TAG, - stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2], - stats.mProcDeaths[3], stats.mProcDeaths[4]); - Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes); - for (int i=0; i<mMemInfoSizes.length; i++) { - mMemInfoSizes[i] *= 1024; - } - EventLog.writeEvent(EVENT_LOG_MEMINFO_TAG, - (int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2], - (int)mMemInfoSizes[3], (int)mMemInfoSizes[4], - (int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7], - (int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]); - long now = SystemClock.uptimeMillis(); - long dur = now - mLastLogGlobalMemoryTime; - mLastLogGlobalMemoryTime = now; - Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes); - for (int i=0; i<mVMStatSizes.length; i++) { - long v = mVMStatSizes[i]; - mVMStatSizes[i] -= mPrevVMStatSizes[i]; - mPrevVMStatSizes[i] = v; - } - EventLog.writeEvent(EVENT_LOG_VMSTAT_TAG, dur, - (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2], - (int)mVMStatSizes[3], (int)mVMStatSizes[4]); - } - - void checkReboot(boolean fromAlarm) { - int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval - : Settings.Gservices.getInt( - mResolver, Settings.Gservices.REBOOT_INTERVAL, - REBOOT_DEFAULT_INTERVAL); - mRebootInterval = rebootInterval; - if (rebootInterval <= 0) { - // No reboot interval requested. - if (localLOGV) Log.v(TAG, "No need to schedule a reboot alarm!"); - mAlarm.remove(mRebootIntent); - return; - } - - long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime - : Settings.Gservices.getLong( - mResolver, Settings.Gservices.REBOOT_START_TIME, - REBOOT_DEFAULT_START_TIME); - long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow - : Settings.Gservices.getLong( - mResolver, Settings.Gservices.REBOOT_WINDOW, - REBOOT_DEFAULT_WINDOW)) * 1000; - long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval - : Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL, - MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000; - - retrieveBrutalityAmount(); - - long realStartTime; - long now; - - synchronized (this) { - now = System.currentTimeMillis(); - realStartTime = computeCalendarTime(mCalendar, now, - rebootStartTime); - - long rebootIntervalMillis = rebootInterval*24*60*60*1000; - if (DB || mReqRebootNoWait || - (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) { - if (fromAlarm && rebootWindowMillis <= 0) { - // No reboot window -- just immediately reboot. - EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now, - (int)rebootIntervalMillis, (int)rebootStartTime*1000, - (int)rebootWindowMillis, ""); - rebootSystem("Checkin scheduled forced"); - return; - } - - // Are we within the reboot window? - if (now < realStartTime) { - // Schedule alarm for next check interval. - realStartTime = computeCalendarTime(mCalendar, - now, rebootStartTime); - } else if (now < (realStartTime+rebootWindowMillis)) { - String doit = shouldWeBeBrutalLocked(now); - EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now, - (int)rebootInterval, (int)rebootStartTime*1000, - (int)rebootWindowMillis, doit != null ? doit : ""); - if (doit == null) { - rebootSystem("Checked scheduled range"); - return; - } - - // Schedule next alarm either within the window or in the - // next interval. - if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) { - realStartTime = computeCalendarTime(mCalendar, - now + rebootIntervalMillis, rebootStartTime); - } else { - realStartTime = now + recheckInterval; - } - } else { - // Schedule alarm for next check interval. - realStartTime = computeCalendarTime(mCalendar, - now + rebootIntervalMillis, rebootStartTime); - } - } - } - - if (localLOGV) Log.v(TAG, "Scheduling next reboot alarm for " - + ((realStartTime-now)/1000/60) + "m from now"); - mAlarm.remove(mRebootIntent); - mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent); - } - - /** - * Perform a full reboot of the system. - */ - void rebootSystem(String reason) { - Log.i(TAG, "Rebooting system because: " + reason); - try { - android.os.Power.reboot(reason); - } catch (IOException e) { - Log.e(TAG, "Reboot failed!", e); - } - } - - /** - * Load the current Gservices settings for when - * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen. - * Must not be called with the lock held. - */ - void retrieveBrutalityAmount() { - mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff - : Settings.Gservices.getInt( - mResolver, Settings.Gservices.MEMCHECK_MIN_SCREEN_OFF, - MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000; - mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm - : Settings.Gservices.getInt( - mResolver, Settings.Gservices.MEMCHECK_MIN_ALARM, - MEMCHECK_DEFAULT_MIN_ALARM)) * 1000; - } - - /** - * Determine whether it is a good time to kill, crash, or otherwise - * plunder the current situation for the overall long-term benefit of - * the world. - * - * @param curTime The current system time. - * @return Returns null if this is a good time, else a String with the - * text of why it is not a good time. - */ - String shouldWeBeBrutalLocked(long curTime) { - if (mBattery == null || !mBattery.isPowered()) { - return "battery"; - } - - if (mMinScreenOff >= 0 && (mPower == null || - mPower.timeSinceScreenOn() < mMinScreenOff)) { - return "screen"; - } - - if (mMinAlarm >= 0 && (mAlarm == null || - mAlarm.timeToNextAlarm() < mMinAlarm)) { - return "alarm"; - } - - return null; - } - - /** - * Compute the times during which we next would like to perform process - * restarts. - * - * @param curTime The current system time. - */ - void computeMemcheckTimesLocked(long curTime) { - if (mMemcheckLastTime == curTime) { - return; - } - - mMemcheckLastTime = curTime; - - long memcheckExecStartTime = Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_EXEC_START_TIME, - MEMCHECK_DEFAULT_EXEC_START_TIME); - long memcheckExecEndTime = Settings.Gservices.getLong( - mResolver, Settings.Gservices.MEMCHECK_EXEC_END_TIME, - MEMCHECK_DEFAULT_EXEC_END_TIME); - - mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime, - memcheckExecEndTime); - if (mMemcheckExecEndTime < curTime) { - memcheckExecStartTime += 24*60*60; - memcheckExecEndTime += 24*60*60; - mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime, - memcheckExecEndTime); - } - mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime, - memcheckExecStartTime); - - if (localLOGV) { - mCalendar.setTimeInMillis(curTime); - Log.v(TAG, "Current Time: " + mCalendar); - mCalendar.setTimeInMillis(mMemcheckExecStartTime); - Log.v(TAG, "Start Check Time: " + mCalendar); - mCalendar.setTimeInMillis(mMemcheckExecEndTime); - Log.v(TAG, "End Check Time: " + mCalendar); - } - } - - static long computeCalendarTime(Calendar c, long curTime, - long secondsSinceMidnight) { - - // start with now - c.setTimeInMillis(curTime); - - int val = (int)secondsSinceMidnight / (60*60); - c.set(Calendar.HOUR_OF_DAY, val); - secondsSinceMidnight -= val * (60*60); - val = (int)secondsSinceMidnight / 60; - c.set(Calendar.MINUTE, val); - c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60)); - c.set(Calendar.MILLISECOND, 0); - - long newTime = c.getTimeInMillis(); - if (newTime < curTime) { - // The given time (in seconds since midnight) has already passed for today, so advance - // by one day (due to daylight savings, etc., the delta may differ from 24 hours). - c.add(Calendar.DAY_OF_MONTH, 1); - newTime = c.getTimeInMillis(); - } - - return newTime; - } - - @Override - public void run() { - while (true) { - mCompleted = false; - mHandler.sendEmptyMessage(MONITOR); - - synchronized (this) { - long timeout = TIME_TO_WAIT; - - // NOTE: We use uptimeMillis() here because we do not want to increment the time we - // wait while asleep. If the device is asleep then the thing that we are waiting - // to timeout on is asleep as well and won't have a chance to run. Causing a false - // positive on when to kill things. - long start = SystemClock.uptimeMillis(); - do { - try { - wait(timeout); - } catch (InterruptedException e) { - if (SystemProperties.getBoolean("ro.secure", false)) { - // If this is a secure build, just log the error. - Log.e("WatchDog", "Woof! Woof! Interrupter!"); - } else { - throw new AssertionError("Someone interrupted the watchdog"); - } - } - timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start); - } while (timeout > 0 && !mForceKillSystem); - - if (mCompleted && !mForceKillSystem) { - // The monitors have returned. - continue; - } - } - - // If we got here, that means that the system is most likely hung. - // First send a SIGQUIT so that we can see where it was hung. Then - // kill this process so that the system will restart. - String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; - EventLog.writeEvent(EVENT_LOG_TAG, name); - Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT); - - // Wait a bit longer before killing so we can make sure that the stacks are captured. - try { - Thread.sleep(10*1000); - } catch (InterruptedException e) { - } - - // Only kill the process if the debugger is not attached. - if (!Debug.isDebuggerConnected()) { - Process.killProcess(Process.myPid()); - } - } - } -} diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java deleted file mode 100644 index eece581..0000000 --- a/services/java/com/android/server/WifiService.java +++ /dev/null @@ -1,1844 +0,0 @@ -/* - * 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 static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; -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; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.wifi.IWifiManager; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiNative; -import android.net.wifi.WifiStateTracker; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.NetworkStateTracker; -import android.net.DhcpInfo; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.provider.Settings; -import android.util.Log; -import android.text.TextUtils; - -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * WifiService handles remote WiFi operation requests by implementing - * the IWifiManager interface. It also creates a WifiMonitor to listen - * for Wifi-related events. - * - * @hide - */ -public class WifiService extends IWifiManager.Stub { - private static final String TAG = "WifiService"; - private static final boolean DBG = false; - private static final Pattern scanResultPattern = Pattern.compile("\t+"); - private final WifiStateTracker mWifiStateTracker; - - private Context mContext; - private int mWifiState; - - private AlarmManager mAlarmManager; - private PendingIntent mIdleIntent; - private static final int IDLE_REQUEST = 0; - private boolean mScreenOff; - private boolean mDeviceIdle; - private int mPluggedType; - - private final LockList mLocks = new LockList(); - /** - * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a - * Settings.Gservices value is not present. This timeout value is chosen as - * the approximate point at which the battery drain caused by Wi-Fi - * being enabled but not active exceeds the battery drain caused by - * re-establishing a connection to the mobile data network. - */ - private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */ - - private static final String WAKELOCK_TAG = "WifiService"; - - /** - * The maximum amount of time to hold the wake lock after a disconnect - * caused by stopping the driver. Establishing an EDGE connection has been - * observed to take about 5 seconds under normal circumstances. This - * provides a bit of extra margin. - * <p> - * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. - * This is the default value if a Settings.Secure value is not present. - */ - private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000; - - // Wake lock used by driver-stop operation - private static PowerManager.WakeLock sDriverStopWakeLock; - // Wake lock used by other operations - private static PowerManager.WakeLock sWakeLock; - - private static final int MESSAGE_ENABLE_WIFI = 0; - private static final int MESSAGE_DISABLE_WIFI = 1; - private static final int MESSAGE_STOP_WIFI = 2; - private static final int MESSAGE_START_WIFI = 3; - private static final int MESSAGE_RELEASE_WAKELOCK = 4; - - private final WifiHandler mWifiHandler; - - /* - * Map used to keep track of hidden networks presence, which - * is needed to switch between active and passive scan modes. - * If there is at least one hidden network that is currently - * present (enabled), we want to do active scans instead of - * passive. - */ - private final Map<Integer, Boolean> mIsHiddenNetworkPresent; - /* - * The number of currently present hidden networks. When this - * counter goes from 0 to 1 or from 1 to 0, we change the - * scan mode to active or passive respectively. Initially, we - * set the counter to 0 and we increment it every time we add - * a new present (enabled) hidden network. - */ - private int mNumHiddenNetworkPresent; - /* - * Whether we change the scan mode is due to a hidden network - * (in this class, this is always the case) - */ - private final static boolean SET_DUE_TO_A_HIDDEN_NETWORK = true; - - /* - * Cache of scan results objects (size is somewhat arbitrary) - */ - private static final int SCAN_RESULT_CACHE_SIZE = 80; - private final LinkedHashMap<String, ScanResult> mScanResultCache; - - /* - * Character buffer used to parse scan results (optimization) - */ - private static final int SCAN_RESULT_BUFFER_SIZE = 512; - private char[] mScanResultBuffer; - private boolean mNeedReconfig; - - /** - * Number of allowed radio frequency channels in various regulatory domains. - * This list is sufficient for 802.11b/g networks (2.4GHz range). - */ - private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14}; - - private static final String ACTION_DEVICE_IDLE = - "com.android.server.WifiManager.action.DEVICE_IDLE"; - - WifiService(Context context, WifiStateTracker tracker) { - mContext = context; - mWifiStateTracker = tracker; - - /* - * Initialize the hidden-networks state - */ - mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>(); - mNumHiddenNetworkPresent = 0; - - mScanResultCache = new LinkedHashMap<String, ScanResult>( - SCAN_RESULT_CACHE_SIZE, 0.75f, true) { - /* - * Limit the cache size by SCAN_RESULT_CACHE_SIZE - * elements - */ - public boolean removeEldestEntry(Map.Entry eldest) { - return SCAN_RESULT_CACHE_SIZE < this.size(); - } - }; - - mScanResultBuffer = new char [SCAN_RESULT_BUFFER_SIZE]; - - HandlerThread wifiThread = new HandlerThread("WifiService"); - wifiThread.start(); - mWifiHandler = new WifiHandler(wifiThread.getLooper()); - - mWifiState = WIFI_STATE_DISABLED; - boolean wifiEnabled = getPersistedWifiEnabled(); - - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); - mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); - - PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); - sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); - mWifiStateTracker.setReleaseWakeLockCallback( - new Runnable() { - public void run() { - mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK); - synchronized (sDriverStopWakeLock) { - if (sDriverStopWakeLock.isHeld()) { - sDriverStopWakeLock.release(); - } - } - } - } - ); - - 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); - } - - /** - * Initializes the hidden networks state. Must be called when we - * enable Wi-Fi. - */ - private synchronized void initializeHiddenNetworksState() { - // First, reset the state - resetHiddenNetworksState(); - - // ... then add networks that are marked as hidden - List<WifiConfiguration> networks = getConfiguredNetworks(); - if (!networks.isEmpty()) { - for (WifiConfiguration config : networks) { - if (config != null && config.hiddenSSID) { - addOrUpdateHiddenNetwork( - config.networkId, - config.status != WifiConfiguration.Status.DISABLED); - } - } - - } - } - - /** - * Resets the hidden networks state. - */ - private synchronized void resetHiddenNetworksState() { - mNumHiddenNetworkPresent = 0; - mIsHiddenNetworkPresent.clear(); - } - - /** - * Marks all but netId network as not present. - */ - private synchronized void markAllHiddenNetworksButOneAsNotPresent(int netId) { - for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) { - if (entry != null) { - Integer networkId = entry.getKey(); - if (networkId != netId) { - updateNetworkIfHidden( - networkId, false); - } - } - } - } - - /** - * Updates the netId network presence status if netId is an existing - * hidden network. - */ - private synchronized void updateNetworkIfHidden(int netId, boolean present) { - if (isHiddenNetwork(netId)) { - addOrUpdateHiddenNetwork(netId, present); - } - } - - /** - * Updates the netId network presence status if netId is an existing - * hidden network. If the network does not exist, adds the network. - */ - private synchronized void addOrUpdateHiddenNetwork(int netId, boolean present) { - if (0 <= netId) { - - // If we are adding a new entry or modifying an existing one - Boolean isPresent = mIsHiddenNetworkPresent.get(netId); - if (isPresent == null || isPresent != present) { - if (present) { - incrementHiddentNetworkPresentCounter(); - } else { - // If we add a new hidden network, no need to change - // the counter (it must be 0) - if (isPresent != null) { - decrementHiddentNetworkPresentCounter(); - } - } - mIsHiddenNetworkPresent.put(netId, present); - } - } else { - Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!"); - } - } - - /** - * Removes the netId network if it is hidden (being kept track of). - */ - private synchronized void removeNetworkIfHidden(int netId) { - if (isHiddenNetwork(netId)) { - removeHiddenNetwork(netId); - } - } - - /** - * Removes the netId network. For the call to be successful, the network - * must be hidden. - */ - private synchronized void removeHiddenNetwork(int netId) { - if (0 <= netId) { - Boolean isPresent = - mIsHiddenNetworkPresent.remove(netId); - if (isPresent != null) { - // If we remove an existing hidden network that is not - // present, no need to change the counter - if (isPresent) { - decrementHiddentNetworkPresentCounter(); - } - } else { - if (DBG) { - Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!"); - } - } - } else { - Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!"); - } - } - - /** - * Returns true if netId is an existing hidden network. - */ - private synchronized boolean isHiddenNetwork(int netId) { - return mIsHiddenNetworkPresent.containsKey(netId); - } - - /** - * Increments the present (enabled) hidden networks counter. If the - * counter value goes from 0 to 1, changes the scan mode to active. - */ - private void incrementHiddentNetworkPresentCounter() { - ++mNumHiddenNetworkPresent; - if (1 == mNumHiddenNetworkPresent) { - // Switch the scan mode to "active" - mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK); - } - } - - /** - * Decrements the present (enabled) hidden networks counter. If the - * counter goes from 1 to 0, changes the scan mode back to passive. - */ - private void decrementHiddentNetworkPresentCounter() { - if (0 < mNumHiddenNetworkPresent) { - --mNumHiddenNetworkPresent; - if (0 == mNumHiddenNetworkPresent) { - // Switch the scan mode to "passive" - mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK); - } - } else { - Log.e(TAG, "Hidden-network counter invariant violation!"); - } - } - - private boolean getPersistedWifiEnabled() { - final ContentResolver cr = mContext.getContentResolver(); - try { - return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1; - } catch (Settings.SettingNotFoundException e) { - Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0); - return false; - } - } - - private void persistWifiEnabled(boolean enabled) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0); - } - - NetworkStateTracker getNetworkStateTracker() { - return mWifiStateTracker; - } - - /** - * see {@link android.net.wifi.WifiManager#pingSupplicant()} - * @return {@code true} if the operation succeeds - */ - public boolean pingSupplicant() { - enforceChangePermission(); - synchronized (mWifiStateTracker) { - return WifiNative.pingCommand(); - } - } - - /** - * see {@link android.net.wifi.WifiManager#startScan()} - * @return {@code true} if the operation succeeds - */ - public boolean startScan() { - enforceChangePermission(); - synchronized (mWifiStateTracker) { - switch (mWifiStateTracker.getSupplicantState()) { - case DISCONNECTED: - case INACTIVE: - case SCANNING: - case DORMANT: - break; - default: - WifiNative.setScanResultHandlingCommand( - WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY); - break; - } - return WifiNative.scanCommand(); - } - } - - /** - * 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. - */ - public boolean setWifiEnabled(boolean enable) { - enforceChangePermission(); - if (mWifiHandler == null) return false; - - synchronized (mWifiHandler) { - sWakeLock.acquire(); - sendEnableMessage(enable, true); - } - - return true; - } - - /** - * Enables/disables Wi-Fi synchronously. - * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. - * @param persist {@code true} if the setting should be persisted. - * @return {@code true} if the operation succeeds (or if the existing state - * is the same as the requested state) - */ - private boolean setWifiEnabledBlocking(boolean enable, boolean persist) { - final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED; - - if (mWifiState == eventualWifiState) { - return true; - } - if (enable && isAirplaneModeOn()) { - return false; - } - - setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING); - - if (enable) { - if (!WifiNative.loadDriver()) { - Log.e(TAG, "Failed to load Wi-Fi driver."); - setWifiEnabledState(WIFI_STATE_UNKNOWN); - return false; - } - if (!WifiNative.startSupplicant()) { - WifiNative.unloadDriver(); - Log.e(TAG, "Failed to start supplicant daemon."); - setWifiEnabledState(WIFI_STATE_UNKNOWN); - return false; - } - registerForBroadcasts(); - mWifiStateTracker.startEventLoop(); - } else { - - 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."); - 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) { - setWifiEnabledState(WIFI_STATE_UNKNOWN); - failedToStopSupplicantOrUnloadDriver = true; - } - } - if (failedToStopSupplicantOrUnloadDriver) { - return false; - } - } - - // Success! - - if (persist) { - persistWifiEnabled(enable); - } - setWifiEnabledState(eventualWifiState); - - /* - * Initialize the hidden networks state and the number of allowed - * radio channels if Wi-Fi is being turned on. - */ - if (enable) { - mWifiStateTracker.setNumAllowedChannels(); - initializeHiddenNetworksState(); - } - - return true; - } - - private void setWifiEnabledState(int wifiState) { - final int previousWifiState = mWifiState; - - // Update state - mWifiState = wifiState; - - // 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); - } - - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, - "WifiService"); - } - - private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, - "WifiService"); - - } - - /** - * see {@link WifiManager#getWifiState()} - * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, - * {@link WifiManager#WIFI_STATE_DISABLING}, - * {@link WifiManager#WIFI_STATE_ENABLED}, - * {@link WifiManager#WIFI_STATE_ENABLING}, - * {@link WifiManager#WIFI_STATE_UNKNOWN} - */ - public int getWifiEnabledState() { - enforceAccessPermission(); - return mWifiState; - } - - /** - * see {@link android.net.wifi.WifiManager#disconnect()} - * @return {@code true} if the operation succeeds - */ - public boolean disconnect() { - enforceChangePermission(); - synchronized (mWifiStateTracker) { - return WifiNative.disconnectCommand(); - } - } - - /** - * see {@link android.net.wifi.WifiManager#reconnect()} - * @return {@code true} if the operation succeeds - */ - public boolean reconnect() { - enforceChangePermission(); - synchronized (mWifiStateTracker) { - return WifiNative.reconnectCommand(); - } - } - - /** - * see {@link android.net.wifi.WifiManager#reassociate()} - * @return {@code true} if the operation succeeds - */ - public boolean reassociate() { - enforceChangePermission(); - synchronized (mWifiStateTracker) { - return WifiNative.reassociateCommand(); - } - } - - /** - * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} - * @return the list of configured networks - */ - public List<WifiConfiguration> getConfiguredNetworks() { - enforceAccessPermission(); - String listStr; - /* - * We don't cache the list, because we want to allow - * for the possibility that the configuration file - * has been modified through some external means, - * such as the wpa_cli command line program. - */ - synchronized (mWifiStateTracker) { - listStr = WifiNative.listNetworksCommand(); - } - List<WifiConfiguration> networks = - new ArrayList<WifiConfiguration>(); - if (listStr == null) - return networks; - - String[] lines = listStr.split("\n"); - // Skip the first line, which is a header - for (int i = 1; i < lines.length; i++) { - String[] result = lines[i].split("\t"); - // network-id | ssid | bssid | flags - WifiConfiguration config = new WifiConfiguration(); - try { - config.networkId = Integer.parseInt(result[0]); - } catch(NumberFormatException e) { - continue; - } - if (result.length > 3) { - if (result[3].indexOf("[CURRENT]") != -1) - config.status = WifiConfiguration.Status.CURRENT; - else if (result[3].indexOf("[DISABLED]") != -1) - config.status = WifiConfiguration.Status.DISABLED; - else - config.status = WifiConfiguration.Status.ENABLED; - } else - config.status = WifiConfiguration.Status.ENABLED; - synchronized (mWifiStateTracker) { - readNetworkVariables(config); - } - networks.add(config); - } - - return networks; - } - - /** - * Read the variables from the supplicant daemon that are needed to - * fill in the WifiConfiguration object. - * <p/> - * The caller must hold the synchronization monitor. - * @param config the {@link WifiConfiguration} object to be filled in. - */ - private static void readNetworkVariables(WifiConfiguration config) { - - int netId = config.networkId; - if (netId < 0) - return; - - /* - * TODO: maybe should have a native method that takes an array of - * variable names and returns an array of values. But we'd still - * be doing a round trip to the supplicant daemon for each variable. - */ - String value; - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName); - if (!TextUtils.isEmpty(value)) { - config.SSID = value; - } else { - config.SSID = null; - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName); - if (!TextUtils.isEmpty(value)) { - config.BSSID = value; - } else { - config.BSSID = null; - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); - config.priority = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.priority = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName); - config.hiddenSSID = false; - if (!TextUtils.isEmpty(value)) { - try { - config.hiddenSSID = Integer.parseInt(value) != 0; - } catch (NumberFormatException ignore) { - } - } - - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName); - config.wepTxKeyIndex = -1; - if (!TextUtils.isEmpty(value)) { - try { - config.wepTxKeyIndex = Integer.parseInt(value); - } catch (NumberFormatException ignore) { - } - } - - /* - * Get up to 4 WEP keys. Note that the actual keys are not passed back, - * just a "*" if the key is set, or the null string otherwise. - */ - for (int i = 0; i < 4; i++) { - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepKeyVarNames[i]); - if (!TextUtils.isEmpty(value)) { - config.wepKeys[i] = value; - } else { - config.wepKeys[i] = null; - } - } - - /* - * Get the private shared key. Note that the actual keys are not passed back, - * just a "*" if the key is set, or the null string otherwise. - */ - value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName); - if (!TextUtils.isEmpty(value)) { - config.preSharedKey = value; - } else { - config.preSharedKey = null; - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.Protocol.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.Protocol.strings); - if (0 <= index) { - config.allowedProtocols.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.KeyMgmt.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.KeyMgmt.strings); - if (0 <= index) { - config.allowedKeyManagement.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.AuthAlgorithm.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.AuthAlgorithm.strings); - if (0 <= index) { - config.allowedAuthAlgorithms.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.PairwiseCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.PairwiseCipher.strings); - if (0 <= index) { - config.allowedPairwiseCiphers.set(index); - } - } - } - - value = WifiNative.getNetworkVariableCommand(config.networkId, - WifiConfiguration.GroupCipher.varName); - if (!TextUtils.isEmpty(value)) { - String vals[] = value.split(" "); - for (String val : vals) { - int index = - lookupString(val, WifiConfiguration.GroupCipher.strings); - if (0 <= index) { - config.allowedGroupCiphers.set(index); - } - } - } - } - - /** - * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} - * @return the supplicant-assigned identifier for the new or updated - * network if the operation succeeds, or {@code -1} if it fails - */ - public synchronized int addOrUpdateNetwork(WifiConfiguration config) { - enforceChangePermission(); - /* - * If the supplied networkId is -1, we create a new empty - * network configuration. Otherwise, the networkId should - * refer to an existing configuration. - */ - int netId = config.networkId; - boolean newNetwork = netId == -1; - boolean doReconfig; - int currentPriority; - // networkId of -1 means we want to create a new network - if (newNetwork) { - netId = WifiNative.addNetworkCommand(); - if (netId < 0) { - if (DBG) { - Log.d(TAG, "Failed to add a network!"); - } - return -1; - } - doReconfig = true; - } else { - String priorityVal = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); - currentPriority = -1; - if (!TextUtils.isEmpty(priorityVal)) { - try { - currentPriority = Integer.parseInt(priorityVal); - } catch (NumberFormatException ignore) { - } - } - doReconfig = currentPriority != config.priority; - } - mNeedReconfig = mNeedReconfig || doReconfig; - - /* - * If we have hidden networks, we may have to change the scan mode - */ - if (config.hiddenSSID) { - // Mark the network as present unless it is disabled - addOrUpdateHiddenNetwork( - netId, config.status != WifiConfiguration.Status.DISABLED); - } - - setVariables: { - /* - * Note that if a networkId for a non-existent network - * was supplied, then the first setNetworkVariableCommand() - * will fail, so we don't bother to make a separate check - * for the validity of the ID up front. - */ - - if (config.SSID != null && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.ssidVarName, - config.SSID)) { - if (DBG) { - Log.d(TAG, "failed to set SSID: "+config.SSID); - } - break setVariables; - } - - if (config.BSSID != null && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.bssidVarName, - config.BSSID)) { - if (DBG) { - Log.d(TAG, "failed to set BSSID: "+config.BSSID); - } - break setVariables; - } - - String allowedKeyManagementString = - makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); - if (config.allowedKeyManagement.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.KeyMgmt.varName, - allowedKeyManagementString)) { - if (DBG) { - Log.d(TAG, "failed to set key_mgmt: "+ - allowedKeyManagementString); - } - break setVariables; - } - - String allowedProtocolsString = - makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); - if (config.allowedProtocols.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.Protocol.varName, - allowedProtocolsString)) { - if (DBG) { - Log.d(TAG, "failed to set proto: "+ - allowedProtocolsString); - } - break setVariables; - } - - String allowedAuthAlgorithmsString = - makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); - if (config.allowedAuthAlgorithms.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.AuthAlgorithm.varName, - allowedAuthAlgorithmsString)) { - if (DBG) { - Log.d(TAG, "failed to set auth_alg: "+ - allowedAuthAlgorithmsString); - } - break setVariables; - } - - String allowedPairwiseCiphersString = - makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings); - if (config.allowedPairwiseCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.PairwiseCipher.varName, - allowedPairwiseCiphersString)) { - if (DBG) { - Log.d(TAG, "failed to set pairwise: "+ - allowedPairwiseCiphersString); - } - break setVariables; - } - - String allowedGroupCiphersString = - makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); - if (config.allowedGroupCiphers.cardinality() != 0 && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.GroupCipher.varName, - allowedGroupCiphersString)) { - if (DBG) { - Log.d(TAG, "failed to set group: "+ - allowedGroupCiphersString); - } - break setVariables; - } - - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.preSharedKey != null && !config.preSharedKey.equals("*") && - !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.pskVarName, - config.preSharedKey)) { - if (DBG) { - Log.d(TAG, "failed to set psk: "+config.preSharedKey); - } - break setVariables; - } - - boolean hasSetKey = false; - if (config.wepKeys != null) { - for (int i = 0; i < config.wepKeys.length; i++) { - // Prevent client screw-up by passing in a WifiConfiguration we gave it - // by preventing "*" as a key. - if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.wepKeyVarNames[i], - config.wepKeys[i])) { - if (DBG) { - Log.d(TAG, - "failed to set wep_key"+i+": " + - config.wepKeys[i]); - } - break setVariables; - } - hasSetKey = true; - } - } - } - - if (hasSetKey) { - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.wepTxKeyIdxVarName, - Integer.toString(config.wepTxKeyIndex))) { - if (DBG) { - Log.d(TAG, - "failed to set wep_tx_keyidx: "+ - config.wepTxKeyIndex); - } - break setVariables; - } - } - - if (!WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.priorityVarName, - Integer.toString(config.priority))) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set priority: " - +config.priority); - } - break setVariables; - } - - if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.hiddenSSIDVarName, - Integer.toString(config.hiddenSSID ? 1 : 0))) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+ - config.hiddenSSID); - } - break setVariables; - } - - return netId; - } - - /* - * For an update, if one of the setNetworkVariable operations fails, - * we might want to roll back all the changes already made. But the - * chances are that if anything is going to go wrong, it'll happen - * the first time we try to set one of the variables. - */ - if (newNetwork) { - removeNetwork(netId); - if (DBG) { - Log.d(TAG, - "Failed to set a network variable, removed network: " - + netId); - } - } - return -1; - } - - private static String makeString(BitSet set, String[] strings) { - StringBuffer buf = new StringBuffer(); - int nextSetBit = -1; - - /* Make sure all set bits are in [0, strings.length) to avoid - * going out of bounds on strings. (Shouldn't happen, but...) */ - set = set.get(0, strings.length); - - while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { - buf.append(strings[nextSetBit].replace('_', '-')).append(' '); - } - - // remove trailing space - if (set.cardinality() > 0) { - buf.setLength(buf.length() - 1); - } - - return buf.toString(); - } - - private static int lookupString(String string, String[] strings) { - int size = strings.length; - - string = string.replace('-', '_'); - - for (int i = 0; i < size; i++) - if (string.equals(strings[i])) - return i; - - if (DBG) { - // if we ever get here, we should probably add the - // value to WifiConfiguration to reflect that it's - // supported by the WPA supplicant - Log.w(TAG, "Failed to look-up a string: " + string); - } - - return -1; - } - - /** - * See {@link android.net.wifi.WifiManager#removeNetwork(int)} - * @param netId the integer that identifies the network configuration - * to the supplicant - * @return {@code true} if the operation succeeded - */ - public boolean removeNetwork(int netId) { - enforceChangePermission(); - - /* - * If we have hidden networks, we may have to change the scan mode - */ - removeNetworkIfHidden(netId); - - return mWifiStateTracker.removeNetwork(netId); - } - - /** - * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} - * @param netId the integer that identifies the network configuration - * to the supplicant - * @param disableOthers if true, disable all other networks. - * @return {@code true} if the operation succeeded - */ - public boolean enableNetwork(int netId, boolean disableOthers) { - enforceChangePermission(); - - /* - * If we have hidden networks, we may have to change the scan mode - */ - synchronized(this) { - if (disableOthers) { - markAllHiddenNetworksButOneAsNotPresent(netId); - } - updateNetworkIfHidden(netId, true); - } - - synchronized (mWifiStateTracker) { - return WifiNative.enableNetworkCommand(netId, disableOthers); - } - } - - /** - * See {@link android.net.wifi.WifiManager#disableNetwork(int)} - * @param netId the integer that identifies the network configuration - * to the supplicant - * @return {@code true} if the operation succeeded - */ - public boolean disableNetwork(int netId) { - enforceChangePermission(); - - /* - * If we have hidden networks, we may have to change the scan mode - */ - updateNetworkIfHidden(netId, false); - - synchronized (mWifiStateTracker) { - return WifiNative.disableNetworkCommand(netId); - } - } - - /** - * See {@link android.net.wifi.WifiManager#getConnectionInfo()} - * @return the Wi-Fi information, contained in {@link WifiInfo}. - */ - public WifiInfo getConnectionInfo() { - enforceAccessPermission(); - /* - * Make sure we have the latest information, by sending - * a status request to the supplicant. - */ - return mWifiStateTracker.requestConnectionInfo(); - } - - /** - * Return the results of the most recent access point scan, in the form of - * a list of {@link ScanResult} objects. - * @return the list of results - */ - public List<ScanResult> getScanResults() { - enforceAccessPermission(); - String reply; - synchronized (mWifiStateTracker) { - reply = WifiNative.scanResultsCommand(); - } - if (reply == null) { - return null; - } - - List<ScanResult> scanList = new ArrayList<ScanResult>(); - - int lineCount = 0; - - int replyLen = reply.length(); - // Parse the result string, keeping in mind that the last line does - // not end with a newline. - for (int lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) { - if (lineEnd == replyLen || reply.charAt(lineEnd) == '\n') { - ++lineCount; - /* - * Skip the first line, which is a header - */ - if (lineCount == 1) { - lineBeg = lineEnd + 1; - continue; - } - int lineLen = lineEnd - lineBeg; - if (0 < lineLen && lineLen <= SCAN_RESULT_BUFFER_SIZE) { - int scanResultLevel = 0; - /* - * At most one thread should have access to the buffer at a time! - */ - synchronized(mScanResultBuffer) { - boolean parsingScanResultLevel = false; - for (int i = lineBeg; i < lineEnd; ++i) { - char ch = reply.charAt(i); - /* - * Assume that the signal level starts with a '-' - */ - if (ch == '-') { - /* - * Skip whatever instances of '-' we may have - * after we parse the signal level - */ - parsingScanResultLevel = (scanResultLevel == 0); - } else if (parsingScanResultLevel) { - int digit = Character.digit(ch, 10); - if (0 <= digit) { - scanResultLevel = - 10 * scanResultLevel + digit; - /* - * Replace the signal level number in - * the string with 0's for caching - */ - ch = '0'; - } else { - /* - * Reset the flag if we meet a non-digit - * character - */ - parsingScanResultLevel = false; - } - } - mScanResultBuffer[i - lineBeg] = ch; - } - if (scanResultLevel != 0) { - ScanResult scanResult = parseScanResult( - new String(mScanResultBuffer, 0, lineLen)); - if (scanResult != null) { - scanResult.level = -scanResultLevel; - scanList.add(scanResult); - } - } else if (DBG) { - Log.w(TAG, - "ScanResult.level=0: misformatted scan result?"); - } - } - } else if (0 < lineLen) { - if (DBG) { - Log.w(TAG, "Scan result line is too long: " + - (lineEnd - lineBeg) + ", skipping the line!"); - } - } - lineBeg = lineEnd + 1; - } - } - mWifiStateTracker.setScanResultsList(scanList); - return scanList; - } - - /** - * Parse the scan result line passed to us by wpa_supplicant (helper). - * @param line the line to parse - * @return the {@link ScanResult} object - */ - private ScanResult parseScanResult(String line) { - ScanResult scanResult = null; - if (line != null) { - /* - * Cache implementation (LinkedHashMap) is not synchronized, thus, - * must synchronized here! - */ - synchronized (mScanResultCache) { - scanResult = mScanResultCache.get(line); - if (scanResult == null) { - String[] result = scanResultPattern.split(line); - if (3 <= result.length && result.length <= 5) { - // bssid | frequency | level | flags | ssid - int frequency; - int level; - try { - frequency = Integer.parseInt(result[1]); - level = Integer.parseInt(result[2]); - } catch (NumberFormatException e) { - frequency = 0; - level = 0; - } - - /* - * The formatting of the results returned by - * wpa_supplicant is intended to make the fields - * line up nicely when printed, - * not to make them easy to parse. So we have to - * apply some heuristics to figure out which field - * is the SSID and which field is the flags. - */ - String ssid; - String flags; - if (result.length == 4) { - if (result[3].charAt(0) == '[') { - flags = result[3]; - ssid = ""; - } else { - flags = ""; - ssid = result[3]; - } - } else if (result.length == 5) { - flags = result[3]; - ssid = result[4]; - } else { - // Here, we must have 3 fields: no flags and ssid - // set - flags = ""; - ssid = ""; - } - - // Do not add scan results that have no SSID set - if (0 < ssid.trim().length()) { - scanResult = - new ScanResult( - ssid, result[0], flags, level, frequency); - mScanResultCache.put(line, scanResult); - } - } else { - Log.w(TAG, "Misformatted scan result text with " + - result.length + " fields: " + line); - } - } - } - } - - return scanResult; - } - - /** - * Parse the "flags" field passed back in a scan result by wpa_supplicant, - * and construct a {@code WifiConfiguration} that describes the encryption, - * key management, and authenticaion capabilities of the access point. - * @param flags the string returned by wpa_supplicant - * @return the {@link WifiConfiguration} object, filled in - */ - WifiConfiguration parseScanFlags(String flags) { - WifiConfiguration config = new WifiConfiguration(); - - if (flags.length() == 0) { - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - } - // ... to be implemented - return config; - } - - /** - * Tell the supplicant to persist the current list of configured networks. - * @return {@code true} if the operation succeeded - */ - public boolean saveConfiguration() { - boolean result; - enforceChangePermission(); - synchronized (mWifiStateTracker) { - result = WifiNative.saveConfigCommand(); - if (result && mNeedReconfig) { - mNeedReconfig = false; - result = WifiNative.reloadConfigCommand(); - - if (result) { - Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION); - mContext.sendBroadcast(intent); - } - } - } - return result; - } - - /** - * Set the number of radio frequency channels that are allowed to be used - * in the current regulatory domain. This method should be used only - * if the correct number of channels cannot be determined automatically - * for some reason. If the operation is successful, the new value is - * persisted as a Secure setting. - * @param numChannels the number of allowed channels. Must be greater than 0 - * and less than or equal to 16. - * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., - * {@code numChannels} is outside the valid range. - */ - public boolean setNumAllowedChannels(int numChannels) { - enforceChangePermission(); - /* - * Validate the argument. We'd like to let the Wi-Fi driver do this, - * but if Wi-Fi isn't currently enabled, that's not possible, and - * we want to persist the setting anyway,so that it will take - * effect when Wi-Fi does become enabled. - */ - boolean found = false; - for (int validChan : sValidRegulatoryChannelCounts) { - if (validChan == numChannels) { - found = true; - break; - } - } - if (!found) { - return false; - } - - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, - numChannels); - mWifiStateTracker.setNumAllowedChannels(numChannels); - return true; - } - - /** - * Return the number of frequency channels that are allowed - * to be used in the current regulatory domain. - * @return the number of allowed channels, or {@code -1} if an error occurs - */ - public int getNumAllowedChannels() { - int numChannels; - - enforceAccessPermission(); - synchronized (mWifiStateTracker) { - /* - * If we can't get the value from the driver (e.g., because - * Wi-Fi is not currently enabled), get the value from - * Settings. - */ - numChannels = WifiNative.getNumAllowedChannelsCommand(); - if (numChannels < 0) { - numChannels = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, - -1); - } - } - return numChannels; - } - - /** - * Return the list of valid values for the number of allowed radio channels - * for various regulatory domains. - * @return the list of channel counts - */ - public int[] getValidChannelCounts() { - enforceAccessPermission(); - return sValidRegulatoryChannelCounts; - } - - /** - * Return the DHCP-assigned addresses from the last successful DHCP request, - * if any. - * @return the DHCP information - */ - public DhcpInfo getDhcpInfo() { - enforceAccessPermission(); - return mWifiStateTracker.getDhcpInfo(); - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(), - Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS); - int stayAwakeConditions = - Settings.System.getInt(mContext.getContentResolver(), - Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0); - if (action.equals(Intent.ACTION_SCREEN_ON)) { - mAlarmManager.cancel(mIdleIntent); - mDeviceIdle = false; - mScreenOff = false; - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mScreenOff = true; - /* - * Set a timer to put Wi-Fi to sleep, but only if the screen is off - * AND the "stay on while plugged in" setting doesn't match the - * current power conditions (i.e, not plugged in, plugged in to USB, - * or plugged in to AC). - */ - if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { - long triggerTime = System.currentTimeMillis() + idleMillis; - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); - } - /* we can return now -- there's nothing to do until we get the idle intent back */ - return; - } else if (action.equals(ACTION_DEVICE_IDLE)) { - mDeviceIdle = true; - } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - /* - * Set a timer to put Wi-Fi to sleep, but only if the screen is off - * AND we are transitioning from a state in which the device was supposed - * to stay awake to a state in which it is not supposed to stay awake. - * If "stay awake" state is not changing, we do nothing, to avoid resetting - * the already-set timer. - */ - int pluggedType = intent.getIntExtra("plugged", 0); - if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && - !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) { - long triggerTime = System.currentTimeMillis() + idleMillis; - mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); - mPluggedType = pluggedType; - return; - } - mPluggedType = pluggedType; - } else { - return; - } - - updateWifiState(); - } - - /** - * Determines whether the Wi-Fi chipset should stay awake or be put to - * sleep. Looks at the setting for the sleep policy and the current - * conditions. - * - * @see #shouldDeviceStayAwake(int, int) - */ - private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) { - int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT); - - if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) { - // Never sleep - return true; - } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && - (pluggedType != 0)) { - // Never sleep while plugged, and we're plugged - return true; - } else { - // Default - return shouldDeviceStayAwake(stayAwakeConditions, pluggedType); - } - } - - /** - * Determine whether the bit value corresponding to {@code pluggedType} is set in - * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value - * of {@code 0} isn't really a plugged type, but rather an indication that the - * device isn't plugged in at all, there is no bit value corresponding to a - * {@code pluggedType} value of {@code 0}. That is why we shift by - * {@code pluggedType — 1} instead of by {@code pluggedType}. - * @param stayAwakeConditions a bit string specifying which "plugged types" should - * keep the device (and hence Wi-Fi) awake. - * @param pluggedType the type of plug (USB, AC, or none) for which the check is - * being made - * @return {@code true} if {@code pluggedType} indicates that the device is - * supposed to stay awake, {@code false} otherwise. - */ - private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) { - return (stayAwakeConditions & pluggedType) != 0; - } - }; - - private void sendEnableMessage(boolean enable, boolean persist) { - Message msg = Message.obtain(mWifiHandler, - (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI), - (persist ? 1 : 0), 0); - msg.sendToTarget(); - } - - private void sendStartMessage(boolean scanOnlyMode) { - Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget(); - } - - private void updateWifiState() { - boolean wifiEnabled = getPersistedWifiEnabled(); - boolean airplaneMode = isAirplaneModeOn(); - boolean lockHeld = mLocks.hasLocks(); - int strongestLockMode; - boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode; - boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld; - if (mDeviceIdle && lockHeld) { - strongestLockMode = mLocks.getStrongestLockMode(); - } else { - strongestLockMode = WifiManager.WIFI_MODE_FULL; - } - - synchronized (mWifiHandler) { - if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) { - return; - } - if (wifiShouldBeEnabled) { - if (wifiShouldBeStarted) { - sWakeLock.acquire(); - sendEnableMessage(true, false); - sWakeLock.acquire(); - sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); - } else { - int wakeLockTimeout = - Settings.Secure.getInt( - 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); - } - } else { - sWakeLock.acquire(); - sendEnableMessage(false, false); - } - } - } - - private void registerForBroadcasts() { - IntentFilter intentFilter = new IntentFilter(); - if (isAirplaneSensitive()) { - intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); - } - 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() { - String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_RADIOS); - return airplaneModeRadios == null - || airplaneModeRadios.contains(Settings.System.RADIO_WIFI); - } - - /** - * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is - * currently on. - * @return {@code true} if airplane mode is on. - */ - private boolean isAirplaneModeOn() { - return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, 0) == 1; - } - - /** - * Handler that allows posting to the WifiThread. - */ - private class WifiHandler extends Handler { - public WifiHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - - case MESSAGE_ENABLE_WIFI: - setWifiEnabledBlocking(true, msg.arg1 == 1); - sWakeLock.release(); - break; - - case MESSAGE_START_WIFI: - mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0); - mWifiStateTracker.restart(); - sWakeLock.release(); - break; - - case MESSAGE_DISABLE_WIFI: - // a non-zero msg.arg1 value means the "enabled" setting - // should be persisted - setWifiEnabledBlocking(false, msg.arg1 == 1); - sWakeLock.release(); - break; - - case MESSAGE_STOP_WIFI: - mWifiStateTracker.disconnectAndStop(); - // don't release wakelock - break; - - case MESSAGE_RELEASE_WAKELOCK: - synchronized (sDriverStopWakeLock) { - if (sDriverStopWakeLock.isHeld()) { - sDriverStopWakeLock.release(); - } - } - break; - } - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump WifiService from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - pw.println("Wi-Fi is " + stateName(mWifiState)); - 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<ScanResult> scanResults = mWifiStateTracker.getScanResultsList(); - if (scanResults != null && scanResults.size() != 0) { - pw.println(" BSSID Frequency RSSI Flags SSID"); - for (ScanResult r : scanResults) { - pw.printf(" %17s %9d %5d %-16s %s%n", - r.BSSID, - r.frequency, - r.level, - r.capabilities, - r.SSID == null ? "" : r.SSID); - } - } - pw.println(); - pw.println("Locks held:"); - mLocks.dump(pw); - } - - private static String stateName(int wifiState) { - switch (wifiState) { - case WIFI_STATE_DISABLING: - return "disabling"; - case WIFI_STATE_DISABLED: - return "disabled"; - case WIFI_STATE_ENABLING: - return "enabling"; - case WIFI_STATE_ENABLED: - return "enabled"; - case WIFI_STATE_UNKNOWN: - return "unknown state"; - default: - return "[invalid state]"; - } - } - - private class WifiLock implements IBinder.DeathRecipient { - String mTag; - int mLockMode; - IBinder mBinder; - - WifiLock(int lockMode, String tag, IBinder binder) { - super(); - mTag = tag; - mLockMode = lockMode; - mBinder = binder; - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - - public void binderDied() { - synchronized (mLocks) { - releaseWifiLockLocked(mBinder); - } - } - - public String toString() { - return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}"; - } - } - - private class LockList { - private List<WifiLock> mList; - - private LockList() { - mList = new ArrayList<WifiLock>(); - } - - private synchronized boolean hasLocks() { - return !mList.isEmpty(); - } - - private synchronized int getStrongestLockMode() { - if (mList.isEmpty()) { - return WifiManager.WIFI_MODE_FULL; - } - for (WifiLock l : mList) { - if (l.mLockMode == WifiManager.WIFI_MODE_FULL) { - return WifiManager.WIFI_MODE_FULL; - } - } - return WifiManager.WIFI_MODE_SCAN_ONLY; - } - - private void addLock(WifiLock lock) { - if (findLockByBinder(lock.mBinder) < 0) { - mList.add(lock); - } - } - - private WifiLock removeLock(IBinder binder) { - int index = findLockByBinder(binder); - if (index >= 0) { - return mList.remove(index); - } else { - return null; - } - } - - private int findLockByBinder(IBinder binder) { - int size = mList.size(); - for (int i = size - 1; i >= 0; i--) - if (mList.get(i).mBinder == binder) - return i; - return -1; - } - - private void dump(PrintWriter pw) { - for (WifiLock l : mList) { - pw.print(" "); - pw.println(l); - } - } - } - - public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) { - return false; - } - WifiLock wifiLock = new WifiLock(lockMode, tag, binder); - synchronized (mLocks) { - return acquireWifiLockLocked(wifiLock); - } - } - - private boolean acquireWifiLockLocked(WifiLock wifiLock) { - mLocks.addLock(wifiLock); - updateWifiState(); - return true; - } - - public boolean releaseWifiLock(IBinder lock) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); - synchronized (mLocks) { - return releaseWifiLockLocked(lock); - } - } - - private boolean releaseWifiLockLocked(IBinder lock) { - boolean result; - result = (mLocks.removeLock(lock) != null); - updateWifiState(); - return result; - } -} diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java deleted file mode 100644 index fe97b93..0000000 --- a/services/java/com/android/server/WifiWatchdogService.java +++ /dev/null @@ -1,1332 +0,0 @@ -/* - * 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.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import android.net.NetworkInfo; -import android.net.DhcpInfo; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiStateTracker; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.List; -import java.util.Random; - -/** - * {@link WifiWatchdogService} monitors the initial connection to a Wi-Fi - * network with multiple access points. After the framework successfully - * connects to an access point, the watchdog verifies whether the DNS server is - * reachable. If not, the watchdog blacklists the current access point, leading - * to a connection on another access point within the same network. - * <p> - * The watchdog has a few safeguards: - * <ul> - * <li>Only monitor networks with multiple access points - * <li>Only check at most {@link #getMaxApChecks()} different access points - * within the network before giving up - * <p> - * The watchdog checks for connectivity on an access point by ICMP pinging the - * DNS. There are settings that allow disabling the watchdog, or tweaking the - * acceptable packet loss (and other various parameters). - * <p> - * The core logic of the watchdog is done on the main watchdog thread. Wi-Fi - * callbacks can come in on other threads, so we must queue messages to the main - * watchdog thread's handler. Most (if not all) state is only written to from - * the main thread. - * - * {@hide} - */ -public class WifiWatchdogService { - private static final String TAG = "WifiWatchdogService"; - private static final boolean V = false || Config.LOGV; - private static final boolean D = true || Config.LOGD; - - /* - * When this was "net.dns1", sometimes the mobile data's DNS was seen - * instead due to a race condition. All we really care about is the - * DHCP-replied DNS server anyway. - */ - /** The system property whose value provides the current DNS address. */ - private static final String SYSTEMPROPERTY_KEY_DNS = "dhcp.tiwlan0.dns1"; - - private Context mContext; - private ContentResolver mContentResolver; - private WifiStateTracker mWifiStateTracker; - private WifiManager mWifiManager; - - /** - * The main watchdog thread. - */ - private WifiWatchdogThread mThread; - /** - * The handler for the main watchdog thread. - */ - private WifiWatchdogHandler mHandler; - - /** - * The current watchdog state. Only written from the main thread! - */ - private WatchdogState mState = WatchdogState.IDLE; - /** - * The SSID of the network that the watchdog is currently monitoring. Only - * touched in the main thread! - */ - private String mSsid; - /** - * The number of access points in the current network ({@link #mSsid}) that - * have been checked. Only touched in the main thread! - */ - private int mNumApsChecked; - /** Whether the current AP check should be canceled. */ - private boolean mShouldCancel; - - WifiWatchdogService(Context context, WifiStateTracker wifiStateTracker) { - mContext = context; - mContentResolver = context.getContentResolver(); - mWifiStateTracker = wifiStateTracker; - mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - - createThread(); - - // The content observer to listen needs a handler, which createThread creates - registerForSettingsChanges(); - if (isWatchdogEnabled()) { - registerForWifiBroadcasts(); - } - - if (V) { - myLogV("WifiWatchdogService: Created"); - } - } - - /** - * Observes the watchdog on/off setting, and takes action when changed. - */ - private void registerForSettingsChanges() { - ContentResolver contentResolver = mContext.getContentResolver(); - contentResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - if (isWatchdogEnabled()) { - registerForWifiBroadcasts(); - } else { - unregisterForWifiBroadcasts(); - if (mHandler != null) { - mHandler.disableWatchdog(); - } - } - } - }); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON - */ - private boolean isWatchdogEnabled() { - return Settings.Secure.getInt(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1; - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT - */ - private int getApCount() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_AP_COUNT, 2); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT - */ - private int getInitialIgnoredPingCount() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT - */ - private int getPingCount() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_PING_COUNT, 4); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS - */ - private int getPingTimeoutMs() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS - */ - private int getPingDelayMs() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, 250); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE - */ - private int getAcceptablePacketLossPercentage() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS - */ - private int getMaxApChecks() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS, 7); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED - */ - private boolean isBackgroundCheckEnabled() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1) == 1; - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS - */ - private int getBackgroundCheckDelayMs() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 60000); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS - */ - private int getBackgroundCheckTimeoutMs() { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000); - } - - /** - * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WATCH_LIST - * @return the comma-separated list of SSIDs - */ - private String getWatchList() { - return Settings.Secure.getString(mContentResolver, - Settings.Secure.WIFI_WATCHDOG_WATCH_LIST); - } - - /** - * Registers to receive the necessary Wi-Fi broadcasts. - */ - private void registerForWifiBroadcasts() { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mContext.registerReceiver(mReceiver, intentFilter); - } - - /** - * Unregisters from receiving the Wi-Fi broadcasts. - */ - private void unregisterForWifiBroadcasts() { - mContext.unregisterReceiver(mReceiver); - } - - /** - * Creates the main watchdog thread, including waiting for the handler to be - * created. - */ - private void createThread() { - mThread = new WifiWatchdogThread(); - mThread.start(); - waitForHandlerCreation(); - } - - /** - * Waits for the main watchdog thread to create the handler. - */ - private void waitForHandlerCreation() { - synchronized(this) { - while (mHandler == null) { - try { - // Wait for the handler to be set by the other thread - wait(); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted while waiting on handler."); - } - } - } - } - - // Utility methods - - /** - * Logs with the current thread. - */ - private static void myLogV(String message) { - Log.v(TAG, "(" + Thread.currentThread().getName() + ") " + message); - } - - private static void myLogD(String message) { - Log.d(TAG, "(" + Thread.currentThread().getName() + ") " + message); - } - - /** - * Gets the DNS of the current AP. - * - * @return The DNS of the current AP. - */ - private int getDns() { - DhcpInfo addressInfo = mWifiManager.getDhcpInfo(); - if (addressInfo != null) { - return addressInfo.dns1; - } else { - return -1; - } - } - - /** - * Checks whether the DNS can be reached using multiple attempts according - * to the current setting values. - * - * @return Whether the DNS is reachable - */ - private boolean checkDnsConnectivity() { - int dns = getDns(); - if (dns == -1) { - if (V) { - myLogV("checkDnsConnectivity: Invalid DNS, returning false"); - } - return false; - } - - if (V) { - myLogV("checkDnsConnectivity: Checking 0x" + - Integer.toHexString(Integer.reverseBytes(dns)) + " for connectivity"); - } - - int numInitialIgnoredPings = getInitialIgnoredPingCount(); - int numPings = getPingCount(); - int pingDelay = getPingDelayMs(); - int acceptableLoss = getAcceptablePacketLossPercentage(); - - /** See {@link Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */ - int ignoredPingCounter = 0; - int pingCounter = 0; - int successCounter = 0; - - // No connectivity check needed - if (numPings == 0) { - return true; - } - - // Do the initial pings that we ignore - for (; ignoredPingCounter < numInitialIgnoredPings; ignoredPingCounter++) { - if (shouldCancel()) return false; - - boolean dnsAlive = DnsPinger.isDnsReachable(dns, getPingTimeoutMs()); - if (dnsAlive) { - /* - * Successful "ignored" pings are *not* ignored (they count in the total number - * of pings), but failures are really ignored. - */ - pingCounter++; - successCounter++; - } - - if (V) { - Log.v(TAG, (dnsAlive ? " +" : " Ignored: -")); - } - - if (shouldCancel()) return false; - - try { - Thread.sleep(pingDelay); - } catch (InterruptedException e) { - Log.w(TAG, "Interrupted while pausing between pings", e); - } - } - - // Do the pings that we use to measure packet loss - for (; pingCounter < numPings; pingCounter++) { - if (shouldCancel()) return false; - - if (DnsPinger.isDnsReachable(dns, getPingTimeoutMs())) { - successCounter++; - if (V) { - Log.v(TAG, " +"); - } - } else { - if (V) { - Log.v(TAG, " -"); - } - } - - if (shouldCancel()) return false; - - try { - Thread.sleep(pingDelay); - } catch (InterruptedException e) { - Log.w(TAG, "Interrupted while pausing between pings", e); - } - } - - int packetLossPercentage = 100 * (numPings - successCounter) / numPings; - if (D) { - Log.d(TAG, packetLossPercentage - + "% packet loss (acceptable is " + acceptableLoss + "%)"); - } - - return !shouldCancel() && (packetLossPercentage <= acceptableLoss); - } - - private boolean backgroundCheckDnsConnectivity() { - int dns = getDns(); - if (false && V) { - myLogV("backgroundCheckDnsConnectivity: Background checking " + dns + - " for connectivity"); - } - - if (dns == -1) { - if (V) { - myLogV("backgroundCheckDnsConnectivity: DNS is empty, returning false"); - } - return false; - } - - return DnsPinger.isDnsReachable(dns, getBackgroundCheckTimeoutMs()); - } - - /** - * Signals the current action to cancel. - */ - private void cancelCurrentAction() { - mShouldCancel = true; - } - - /** - * Helper to check whether to cancel. - * - * @return Whether to cancel processing the action. - */ - private boolean shouldCancel() { - if (V && mShouldCancel) { - myLogV("shouldCancel: Cancelling"); - } - - return mShouldCancel; - } - - // Wi-Fi initiated callbacks (could be executed in another thread) - - /** - * Called when connected to an AP (this can be the next AP in line, or - * it can be a completely different network). - * - * @param ssid The SSID of the access point. - * @param bssid The BSSID of the access point. - */ - private void onConnected(String ssid, String bssid) { - if (V) { - myLogV("onConnected: SSID: " + ssid + ", BSSID: " + bssid); - } - - /* - * The current action being processed by the main watchdog thread is now - * stale, so cancel it. - */ - cancelCurrentAction(); - - if ((mSsid == null) || !mSsid.equals(ssid)) { - /* - * This is a different network than what the main watchdog thread is - * processing, dispatch the network change message on the main thread. - */ - mHandler.dispatchNetworkChanged(ssid); - } - - if (requiresWatchdog(ssid, bssid)) { - if (D) { - myLogD(ssid + " (" + bssid + ") requires the watchdog"); - } - - // This access point requires a watchdog, so queue the check on the main thread - mHandler.checkAp(new AccessPoint(ssid, bssid)); - - } else { - if (D) { - myLogD(ssid + " (" + bssid + ") does not require the watchdog"); - } - - // This access point does not require a watchdog, so queue idle on the main thread - mHandler.idle(); - } - } - - /** - * Called when Wi-Fi is enabled. - */ - private void onEnabled() { - cancelCurrentAction(); - // Queue a hard-reset of the state on the main thread - mHandler.reset(); - } - - /** - * Called when disconnected (or some other event similar to being disconnected). - */ - private void onDisconnected() { - if (V) { - myLogV("onDisconnected"); - } - - /* - * Disconnected from an access point, the action being processed by the - * watchdog thread is now stale, so cancel it. - */ - cancelCurrentAction(); - // Dispatch the disconnected to the main watchdog thread - mHandler.dispatchDisconnected(); - // Queue the action to go idle - mHandler.idle(); - } - - /** - * Checks whether an access point requires watchdog monitoring. - * - * @param ssid The SSID of the access point. - * @param bssid The BSSID of the access point. - * @return Whether the access point/network should be monitored by the - * watchdog. - */ - private boolean requiresWatchdog(String ssid, String bssid) { - if (V) { - myLogV("requiresWatchdog: SSID: " + ssid + ", BSSID: " + bssid); - } - - WifiInfo info = null; - if (ssid == null) { - /* - * This is called from a Wi-Fi callback, so assume the WifiInfo does - * not have stale data. - */ - info = mWifiManager.getConnectionInfo(); - ssid = info.getSSID(); - if (ssid == null) { - // It's still null, give up - if (V) { - Log.v(TAG, " Invalid SSID, returning false"); - } - return false; - } - } - - if (TextUtils.isEmpty(bssid)) { - // Similar as above - if (info == null) { - info = mWifiManager.getConnectionInfo(); - } - bssid = info.getBSSID(); - if (TextUtils.isEmpty(bssid)) { - // It's still null, give up - if (V) { - Log.v(TAG, " Invalid BSSID, returning false"); - } - return false; - } - } - - if (!isOnWatchList(ssid)) { - if (V) { - Log.v(TAG, " SSID not on watch list, returning false"); - } - return false; - } - - // The watchdog only monitors networks with multiple APs - if (!hasRequiredNumberOfAps(ssid)) { - return false; - } - - return true; - } - - private boolean isOnWatchList(String ssid) { - String watchList; - - if (ssid == null || (watchList = getWatchList()) == null) { - return false; - } - - String[] list = watchList.split(" *, *"); - - for (String name : list) { - if (ssid.equals(name)) { - return true; - } - } - - return false; - } - - /** - * Checks if the current scan results have multiple access points with an SSID. - * - * @param ssid The SSID to check. - * @return Whether the SSID has multiple access points. - */ - private boolean hasRequiredNumberOfAps(String ssid) { - List<ScanResult> results = mWifiManager.getScanResults(); - if (results == null) { - if (V) { - myLogV("hasRequiredNumberOfAps: Got null scan results, returning false"); - } - return false; - } - - int numApsRequired = getApCount(); - int numApsFound = 0; - int resultsSize = results.size(); - for (int i = 0; i < resultsSize; i++) { - ScanResult result = results.get(i); - if (result == null) continue; - if (result.SSID == null) continue; - - if (result.SSID.equals(ssid)) { - numApsFound++; - - if (numApsFound >= numApsRequired) { - if (V) { - myLogV("hasRequiredNumberOfAps: SSID: " + ssid + ", returning true"); - } - return true; - } - } - } - - if (V) { - myLogV("hasRequiredNumberOfAps: SSID: " + ssid + ", returning false"); - } - return false; - } - - // Watchdog logic (assume all of these methods will be in our main thread) - - /** - * Handles a Wi-Fi network change (for example, from networkA to networkB). - */ - private void handleNetworkChanged(String ssid) { - // Set the SSID being monitored to the new SSID - mSsid = ssid; - // Set various state to that when being idle - setIdleState(true); - } - - /** - * Handles checking whether an AP is a "good" AP. If not, it will be blacklisted. - * - * @param ap The access point to check. - */ - private void handleCheckAp(AccessPoint ap) { - // Reset the cancel state since this is the entry point of this action - mShouldCancel = false; - - if (V) { - myLogV("handleCheckAp: AccessPoint: " + ap); - } - - // Make sure we are not sleeping - if (mState == WatchdogState.SLEEP) { - if (V) { - Log.v(TAG, " Sleeping (in " + mSsid + "), so returning"); - } - return; - } - - mState = WatchdogState.CHECKING_AP; - - /* - * Checks to make sure we haven't exceeded the max number of checks - * we're allowed per network - */ - mNumApsChecked++; - if (mNumApsChecked > getMaxApChecks()) { - if (V) { - Log.v(TAG, " Passed the max attempts (" + getMaxApChecks() - + "), going to sleep for " + mSsid); - } - mHandler.sleep(mSsid); - return; - } - - // Do the check - boolean isApAlive = checkDnsConnectivity(); - - if (V) { - Log.v(TAG, " Is it alive: " + isApAlive); - } - - // Take action based on results - if (isApAlive) { - handleApAlive(ap); - } else { - handleApUnresponsive(ap); - } - } - - /** - * Handles the case when an access point is alive. - * - * @param ap The access point. - */ - private void handleApAlive(AccessPoint ap) { - // Check whether we are stale and should cancel - if (shouldCancel()) return; - // We're satisfied with this AP, so go idle - setIdleState(false); - - if (D) { - myLogD("AP is alive: " + ap.toString()); - } - - // Queue the next action to be a background check - mHandler.backgroundCheckAp(ap); - } - - /** - * Handles an unresponsive AP by blacklisting it. - * - * @param ap The access point. - */ - private void handleApUnresponsive(AccessPoint ap) { - // Check whether we are stale and should cancel - if (shouldCancel()) return; - // This AP is "bad", switch to another - mState = WatchdogState.SWITCHING_AP; - - if (D) { - myLogD("AP is dead: " + ap.toString()); - } - - // Black list this "bad" AP, this will cause an attempt to connect to another - blacklistAp(ap.bssid); - } - - private void blacklistAp(String bssid) { - if (TextUtils.isEmpty(bssid)) { - return; - } - - // Before taking action, make sure we should not cancel our processing - if (shouldCancel()) return; - - if (!mWifiStateTracker.addToBlacklist(bssid)) { - // There's a known bug where this method returns failure on success - //Log.e(TAG, "Blacklisting " + bssid + " failed"); - } - - if (D) { - myLogD("Blacklisting " + bssid); - } - } - - /** - * Handles a single background check. If it fails, it should trigger a - * normal check. If it succeeds, it should queue another background check. - * - * @param ap The access point to do a background check for. If this is no - * longer the current AP, it is okay to return without any - * processing. - */ - private void handleBackgroundCheckAp(AccessPoint ap) { - // Reset the cancel state since this is the entry point of this action - mShouldCancel = false; - - if (false && V) { - myLogV("handleBackgroundCheckAp: AccessPoint: " + ap); - } - - // Make sure we are not sleeping - if (mState == WatchdogState.SLEEP) { - if (V) { - Log.v(TAG, " handleBackgroundCheckAp: Sleeping (in " + mSsid + "), so returning"); - } - return; - } - - // Make sure the AP we're supposed to be background checking is still the active one - WifiInfo info = mWifiManager.getConnectionInfo(); - if (info.getSSID() == null || !info.getSSID().equals(ap.ssid)) { - if (V) { - myLogV("handleBackgroundCheckAp: We are no longer connected to " - + ap + ", and instead are on " + info); - } - return; - } - - if (info.getBSSID() == null || !info.getBSSID().equals(ap.bssid)) { - if (V) { - myLogV("handleBackgroundCheckAp: We are no longer connected to " - + ap + ", and instead are on " + info); - } - return; - } - - // Do the check - boolean isApAlive = backgroundCheckDnsConnectivity(); - - if (V && !isApAlive) { - Log.v(TAG, " handleBackgroundCheckAp: Is it alive: " + isApAlive); - } - - if (shouldCancel()) { - return; - } - - // Take action based on results - if (isApAlive) { - // Queue another background check - mHandler.backgroundCheckAp(ap); - - } else { - if (D) { - myLogD("Background check failed for " + ap.toString()); - } - - // Queue a normal check, so it can take proper action - mHandler.checkAp(ap); - } - } - - /** - * Handles going to sleep for this network. Going to sleep means we will not - * monitor this network anymore. - * - * @param ssid The network that will not be monitored anymore. - */ - private void handleSleep(String ssid) { - // Make sure the network we're trying to sleep in is still the current network - if (ssid != null && ssid.equals(mSsid)) { - mState = WatchdogState.SLEEP; - - if (D) { - myLogD("Going to sleep for " + ssid); - } - - /* - * Before deciding to go to sleep, we may have checked a few APs - * (and blacklisted them). Clear the blacklist so the AP with best - * signal is chosen. - */ - if (!mWifiStateTracker.clearBlacklist()) { - // There's a known bug where this method returns failure on success - //Log.e(TAG, "Clearing blacklist failed"); - } - - if (V) { - myLogV("handleSleep: Set state to SLEEP and cleared blacklist"); - } - } - } - - /** - * Handles an access point disconnection. - */ - private void handleDisconnected() { - /* - * We purposefully do not change mSsid to null. This is to handle - * disconnected followed by connected better (even if there is some - * duration in between). For example, if the watchdog went to sleep in a - * network, and then the phone goes to sleep, when the phone wakes up we - * still want to be in the sleeping state. When the phone went to sleep, - * we would have gotten a disconnected event which would then set mSsid - * = null. This is bad, since the following connect would cause us to do - * the "network is good?" check all over again. */ - - /* - * Set the state as if we were idle (don't come out of sleep, only - * hard reset and network changed should do that. - */ - setIdleState(false); - } - - /** - * Handles going idle. Idle means we are satisfied with the current state of - * things, but if a new connection occurs we'll re-evaluate. - */ - private void handleIdle() { - // Reset the cancel state since this is the entry point for this action - mShouldCancel = false; - - if (V) { - myLogV("handleSwitchToIdle"); - } - - // If we're sleeping, don't do anything - if (mState == WatchdogState.SLEEP) { - Log.v(TAG, " Sleeping (in " + mSsid + "), so returning"); - return; - } - - // Set the idle state - setIdleState(false); - - if (V) { - Log.v(TAG, " Set state to IDLE"); - } - } - - /** - * Sets the state as if we are going idle. - */ - private void setIdleState(boolean forceIdleState) { - // Setting idle state does not kick us out of sleep unless the forceIdleState is set - if (forceIdleState || (mState != WatchdogState.SLEEP)) { - mState = WatchdogState.IDLE; - } - mNumApsChecked = 0; - } - - /** - * Handles a hard reset. A hard reset is rarely used, but when used it - * should revert anything done by the watchdog monitoring. - */ - private void handleReset() { - mWifiStateTracker.clearBlacklist(); - setIdleState(true); - } - - // Inner classes - - /** - * Possible states for the watchdog to be in. - */ - private static enum WatchdogState { - /** The watchdog is currently idle, but it is still responsive to future AP checks in this network. */ - IDLE, - /** The watchdog is sleeping, so it will not try any AP checks for the network. */ - SLEEP, - /** The watchdog is currently checking an AP for connectivity. */ - CHECKING_AP, - /** The watchdog is switching to another AP in the network. */ - SWITCHING_AP - } - - /** - * The main thread for the watchdog monitoring. This will be turned into a - * {@link Looper} thread. - */ - private class WifiWatchdogThread extends Thread { - WifiWatchdogThread() { - super("WifiWatchdogThread"); - } - - @Override - public void run() { - // Set this thread up so the handler will work on it - Looper.prepare(); - - synchronized(WifiWatchdogService.this) { - mHandler = new WifiWatchdogHandler(); - - // Notify that the handler has been created - WifiWatchdogService.this.notify(); - } - - // Listen for messages to the handler - Looper.loop(); - } - } - - /** - * The main thread's handler. There are 'actions', and just general - * 'messages'. There should only ever be one 'action' in the queue (aside - * from the one being processed, if any). There may be multiple messages in - * the queue. So, actions are replaced by more recent actions, where as - * messages will be executed for sure. Messages end up being used to just - * change some state, and not really take any action. - * <p> - * There is little logic inside this class, instead methods of the form - * "handle___" are called in the main {@link WifiWatchdogService}. - */ - private class WifiWatchdogHandler extends Handler { - /** Check whether the AP is "good". The object will be an {@link AccessPoint}. */ - static final int ACTION_CHECK_AP = 1; - /** Go into the idle state. */ - static final int ACTION_IDLE = 2; - /** - * Performs a periodic background check whether the AP is still "good". - * The object will be an {@link AccessPoint}. - */ - static final int ACTION_BACKGROUND_CHECK_AP = 3; - - /** - * Go to sleep for the current network. We are conservative with making - * this a message rather than action. We want to make sure our main - * thread sees this message, but if it were an action it could be - * removed from the queue and replaced by another action. The main - * thread will ensure when it sees the message that the state is still - * valid for going to sleep. - * <p> - * For an explanation of sleep, see {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS}. - */ - static final int MESSAGE_SLEEP = 101; - /** Disables the watchdog. */ - static final int MESSAGE_DISABLE_WATCHDOG = 102; - /** The network has changed. */ - static final int MESSAGE_NETWORK_CHANGED = 103; - /** The current access point has disconnected. */ - static final int MESSAGE_DISCONNECTED = 104; - /** Performs a hard-reset on the watchdog state. */ - static final int MESSAGE_RESET = 105; - - void checkAp(AccessPoint ap) { - removeAllActions(); - sendMessage(obtainMessage(ACTION_CHECK_AP, ap)); - } - - void backgroundCheckAp(AccessPoint ap) { - if (!isBackgroundCheckEnabled()) return; - - removeAllActions(); - sendMessageDelayed(obtainMessage(ACTION_BACKGROUND_CHECK_AP, ap), - getBackgroundCheckDelayMs()); - } - - void idle() { - removeAllActions(); - sendMessage(obtainMessage(ACTION_IDLE)); - } - - void sleep(String ssid) { - removeAllActions(); - sendMessage(obtainMessage(MESSAGE_SLEEP, ssid)); - } - - void disableWatchdog() { - removeAllActions(); - sendMessage(obtainMessage(MESSAGE_DISABLE_WATCHDOG)); - } - - void dispatchNetworkChanged(String ssid) { - removeAllActions(); - sendMessage(obtainMessage(MESSAGE_NETWORK_CHANGED, ssid)); - } - - void dispatchDisconnected() { - removeAllActions(); - sendMessage(obtainMessage(MESSAGE_DISCONNECTED)); - } - - void reset() { - removeAllActions(); - sendMessage(obtainMessage(MESSAGE_RESET)); - } - - private void removeAllActions() { - removeMessages(ACTION_CHECK_AP); - removeMessages(ACTION_IDLE); - removeMessages(ACTION_BACKGROUND_CHECK_AP); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_NETWORK_CHANGED: - handleNetworkChanged((String) msg.obj); - break; - case ACTION_CHECK_AP: - handleCheckAp((AccessPoint) msg.obj); - break; - case ACTION_BACKGROUND_CHECK_AP: - handleBackgroundCheckAp((AccessPoint) msg.obj); - break; - case MESSAGE_SLEEP: - handleSleep((String) msg.obj); - break; - case ACTION_IDLE: - handleIdle(); - break; - case MESSAGE_DISABLE_WATCHDOG: - handleIdle(); - break; - case MESSAGE_DISCONNECTED: - handleDisconnected(); - break; - case MESSAGE_RESET: - handleReset(); - break; - } - } - } - - /** - * Receives Wi-Fi broadcasts. - * <p> - * There is little logic in this class, instead methods of the form "on___" - * are called in the {@link WifiWatchdogService}. - */ - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - handleNetworkStateChanged( - (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)); - } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { - handleSupplicantConnectionChanged( - intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN)); - } - } - - private void handleNetworkStateChanged(NetworkInfo info) { - if (V) { - myLogV("Receiver.handleNetworkStateChanged: NetworkInfo: " - + info); - } - - switch (info.getState()) { - case CONNECTED: - WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) { - if (V) { - myLogV("handleNetworkStateChanged: Got connected event but SSID or BSSID are null. SSID: " - + wifiInfo.getSSID() - + ", BSSID: " - + wifiInfo.getBSSID() + ", ignoring event"); - } - return; - } - onConnected(wifiInfo.getSSID(), wifiInfo.getBSSID()); - break; - - case DISCONNECTED: - onDisconnected(); - break; - } - } - - private void handleSupplicantConnectionChanged(boolean connected) { - if (!connected) { - onDisconnected(); - } - } - - private void handleWifiStateChanged(int wifiState) { - if (wifiState == WifiManager.WIFI_STATE_DISABLED) { - onDisconnected(); - } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) { - onEnabled(); - } - } - }; - - /** - * Describes an access point by its SSID and BSSID. - */ - private static class AccessPoint { - String ssid; - String bssid; - - AccessPoint(String ssid, String bssid) { - this.ssid = ssid; - this.bssid = bssid; - } - - private boolean hasNull() { - return ssid == null || bssid == null; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof AccessPoint)) return false; - AccessPoint otherAp = (AccessPoint) o; - boolean iHaveNull = hasNull(); - // Either we both have a null, or our SSIDs and BSSIDs are equal - return (iHaveNull && otherAp.hasNull()) || - (otherAp.bssid != null && ssid.equals(otherAp.ssid) - && bssid.equals(otherAp.bssid)); - } - - @Override - public int hashCode() { - if (ssid == null || bssid == null) return 0; - return ssid.hashCode() + bssid.hashCode(); - } - - @Override - public String toString() { - return ssid + " (" + bssid + ")"; - } - } - - /** - * Performs a simple DNS "ping" by sending a "server status" query packet to - * the DNS server. As long as the server replies, we consider it a success. - * <p> - * We do not use a simple hostname lookup because that could be cached and - * the API may not differentiate between a time out and a failure lookup - * (which we really care about). - */ - private static class DnsPinger { - - /** Number of bytes for the query */ - private static final int DNS_QUERY_BASE_SIZE = 33; - - /** The DNS port */ - private static final int DNS_PORT = 53; - - /** Used to generate IDs */ - private static Random sRandom = new Random(); - - static boolean isDnsReachable(int dns, int timeout) { - try { - DatagramSocket socket = new DatagramSocket(); - - // Set some socket properties - socket.setSoTimeout(timeout); - - byte[] buf = new byte[DNS_QUERY_BASE_SIZE]; - fillQuery(buf); - - // Send the DNS query - byte parts[] = new byte[4]; - parts[0] = (byte)(dns & 0xff); - parts[1] = (byte)((dns >> 8) & 0xff); - parts[2] = (byte)((dns >> 16) & 0xff); - parts[3] = (byte)((dns >> 24) & 0xff); - - InetAddress dnsAddress = InetAddress.getByAddress(parts); - DatagramPacket packet = new DatagramPacket(buf, - buf.length, dnsAddress, DNS_PORT); - socket.send(packet); - - // Wait for reply (blocks for the above timeout) - DatagramPacket replyPacket = new DatagramPacket(buf, buf.length); - socket.receive(replyPacket); - - // If a timeout occurred, an exception would have been thrown. We got a reply! - return true; - - } catch (SocketException e) { - if (V) { - Log.v(TAG, "DnsPinger.isReachable received SocketException", e); - } - return false; - - } catch (UnknownHostException e) { - if (V) { - Log.v(TAG, "DnsPinger.isReachable is unable to resolve the DNS host", e); - } - return false; - - } catch (SocketTimeoutException e) { - return false; - - } catch (IOException e) { - if (V) { - Log.v(TAG, "DnsPinger.isReachable got an IOException", e); - } - return false; - - } catch (Exception e) { - if (V || Config.LOGD) { - Log.d(TAG, "DnsPinger.isReachable got an unknown exception", e); - } - return false; - } - } - - private static void fillQuery(byte[] buf) { - - /* - * See RFC2929 (though the bit tables in there are misleading for - * us. For example, the recursion desired bit is the 0th bit for us, - * but looking there it would appear as the 7th bit of the byte - */ - - // Make sure it's all zeroed out - for (int i = 0; i < buf.length; i++) buf[i] = 0; - - // Form a query for www.android.com - - // [0-1] bytes are an ID, generate random ID for this query - buf[0] = (byte) sRandom.nextInt(256); - buf[1] = (byte) sRandom.nextInt(256); - - // [2-3] bytes are for flags. - buf[2] = 1; // Recursion desired - - // [4-5] bytes are for the query count - buf[5] = 1; // One query - - // [6-7] [8-9] [10-11] are all counts of other fields we don't use - - // [12-15] for www - writeString(buf, 12, "www"); - - // [16-23] for android - writeString(buf, 16, "android"); - - // [24-27] for com - writeString(buf, 24, "com"); - - // [29-30] bytes are for QTYPE, set to 1 - buf[30] = 1; - - // [31-32] bytes are for QCLASS, set to 1 - buf[32] = 1; - } - - private static void writeString(byte[] buf, int startPos, String string) { - int pos = startPos; - - // Write the length first - buf[pos++] = (byte) string.length(); - for (int i = 0; i < string.length(); i++) { - buf[pos++] = (byte) string.charAt(i); - } - } - } -} diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java deleted file mode 100644 index 10a2d29..0000000 --- a/services/java/com/android/server/WindowManagerService.java +++ /dev/null @@ -1,8657 +0,0 @@ -/* - * Copyright (C) 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; - -import static android.os.LocalPowerManager.CHEEK_EVENT; -import static android.os.LocalPowerManager.OTHER_EVENT; -import static android.os.LocalPowerManager.TOUCH_EVENT; -import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; -import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; -import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; -import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; -import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU; -import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE; -import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; - -import com.android.internal.app.IBatteryStats; -import com.android.internal.policy.PolicyManager; -import com.android.internal.view.IInputContext; -import com.android.internal.view.IInputMethodClient; -import com.android.internal.view.IInputMethodManager; -import com.android.server.KeyInputQueue.QueuedEvent; -import com.android.server.am.BatteryStatsService; - -import android.Manifest; -import android.app.ActivityManagerNative; -import android.app.IActivityManager; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.Region; -import android.os.BatteryStats; -import android.os.Binder; -import android.os.Debug; -import android.os.Handler; -import android.os.IBinder; -import android.os.LocalPowerManager; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.Power; -import android.os.PowerManager; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.TokenWatcher; -import android.provider.Settings; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.util.SparseIntArray; -import android.view.Display; -import android.view.Gravity; -import android.view.IApplicationToken; -import android.view.IOnKeyguardExitResult; -import android.view.IRotationWatcher; -import android.view.IWindow; -import android.view.IWindowManager; -import android.view.IWindowSession; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.RawInputEvent; -import android.view.Surface; -import android.view.SurfaceSession; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.WindowManager; -import android.view.WindowManagerImpl; -import android.view.WindowManagerPolicy; -import android.view.WindowManager.LayoutParams; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.animation.Transformation; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.Socket; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -/** {@hide} */ -public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { - static final String TAG = "WindowManager"; - 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; - static final boolean DEBUG_STARTING_WINDOW = false; - static final boolean DEBUG_REORDER = false; - static final boolean SHOW_TRANSACTIONS = false; - - static final boolean PROFILE_ORIENTATION = false; - static final boolean BLUR = true; - static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - - static final int LOG_WM_NO_SURFACE_MEMORY = 31000; - - /** How long to wait for first key repeat, in milliseconds */ - static final int KEY_REPEAT_FIRST_DELAY = 750; - - /** How long to wait for subsequent key repeats, in milliseconds */ - static final int KEY_REPEAT_DELAY = 50; - - /** How much to multiply the policy's type layer, to reserve room - * for multiple windows of the same type and Z-ordering adjustment - * with TYPE_LAYER_OFFSET. */ - static final int TYPE_LAYER_MULTIPLIER = 10000; - - /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above - * or below others in the same layer. */ - static final int TYPE_LAYER_OFFSET = 1000; - - /** How much to increment the layer for each window, to reserve room - * for effect surfaces between them. - */ - static final int WINDOW_LAYER_MULTIPLIER = 5; - - /** The maximum length we will accept for a loaded animation duration: - * this is 10 seconds. - */ - static final int MAX_ANIMATION_DURATION = 10*1000; - - /** Amount of time (in milliseconds) to animate the dim surface from one - * value to another, when no window animation is driving it. - */ - static final int DEFAULT_DIM_DURATION = 200; - - /** Adjustment to time to perform a dim, to make it more dramatic. - */ - static final int DIM_DURATION_MULTIPLIER = 6; - - static final int UPDATE_FOCUS_NORMAL = 0; - static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1; - static final int UPDATE_FOCUS_PLACING_SURFACES = 2; - static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3; - - private static final String SYSTEM_SECURE = "ro.secure"; - - /** - * Condition waited on by {@link #reenableKeyguard} to know the call to - * the window policy has finished. - */ - private boolean mWaitingUntilKeyguardReenabled = false; - - - final TokenWatcher mKeyguardDisabled = new TokenWatcher( - new Handler(), "WindowManagerService.mKeyguardDisabled") { - public void acquired() { - mPolicy.enableKeyguard(false); - } - public void released() { - synchronized (mKeyguardDisabled) { - mPolicy.enableKeyguard(true); - mWaitingUntilKeyguardReenabled = false; - mKeyguardDisabled.notifyAll(); - } - } - }; - - final Context mContext; - - final boolean mHaveInputMethods; - - final boolean mLimitedAlphaCompositing; - - final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); - - final IActivityManager mActivityManager; - - final IBatteryStats mBatteryStats; - - /** - * All currently active sessions with clients. - */ - final HashSet<Session> mSessions = new HashSet<Session>(); - - /** - * Mapping from an IWindow IBinder to the server's Window object. - * This is also used as the lock for all of our state. - */ - final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>(); - - /** - * Mapping from a token IBinder to a WindowToken object. - */ - final HashMap<IBinder, WindowToken> mTokenMap = - new HashMap<IBinder, WindowToken>(); - - /** - * The same tokens as mTokenMap, stored in a list for efficient iteration - * over them. - */ - final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>(); - - /** - * Window tokens that are in the process of exiting, but still - * on screen for animations. - */ - final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>(); - - /** - * Z-ordered (bottom-most first) list of all application tokens, for - * controlling the ordering of windows in different applications. This - * contains WindowToken objects. - */ - final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>(); - - /** - * Application tokens that are in the process of exiting, but still - * on screen for animations. - */ - final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>(); - - /** - * List of window tokens that have finished starting their application, - * and now need to have the policy remove their windows. - */ - final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>(); - - /** - * Z-ordered (bottom-most first) list of all Window objects. - */ - final ArrayList mWindows = new ArrayList(); - - /** - * Windows that are being resized. Used so we can tell the client about - * the resize after closing the transaction in which we resized the - * underlying surface. - */ - final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>(); - - /** - * Windows whose animations have ended and now must be removed. - */ - final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>(); - - /** - * Windows whose surface should be destroyed. - */ - final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>(); - - /** - * Windows that have lost input focus and are waiting for the new - * focus window to be displayed before they are told about this. - */ - ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>(); - - /** - * This is set when we have run out of memory, and will either be an empty - * list or contain windows that need to be force removed. - */ - ArrayList<WindowState> mForceRemoves; - - IInputMethodManager mInputMethodManager; - - SurfaceSession mFxSession; - Surface mDimSurface; - boolean mDimShown; - float mDimCurrentAlpha; - float mDimTargetAlpha; - float mDimDeltaPerMs; - long mLastDimAnimTime; - Surface mBlurSurface; - boolean mBlurShown; - - int mTransactionSequence = 0; - - final float[] mTmpFloats = new float[9]; - - boolean mSafeMode; - boolean mDisplayEnabled = false; - boolean mSystemBooted = false; - int mRotation = 0; - int mRequestedRotation = 0; - int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - ArrayList<IRotationWatcher> mRotationWatchers - = new ArrayList<IRotationWatcher>(); - - boolean mLayoutNeeded = true; - boolean mAnimationPending = false; - boolean mDisplayFrozen = false; - boolean mWindowsFreezingScreen = false; - long mFreezeGcPending = 0; - int mAppsFreezingScreen = 0; - - // This is held as long as we have the screen frozen, to give us time to - // perform a rotation animation when turning off shows the lock screen which - // changes the orientation. - PowerManager.WakeLock mScreenFrozenLock; - - // State management of app transitions. When we are preparing for a - // transition, mNextAppTransition will be the kind of transition to - // perform or TRANSIT_NONE if we are not waiting. If we are waiting, - // mOpeningApps and mClosingApps are the lists of tokens that will be - // made visible or hidden at the next transition. - int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE; - boolean mAppTransitionReady = false; - boolean mAppTransitionTimeout = false; - boolean mStartingIconInTransition = false; - boolean mSkipAppTransitionAnimation = false; - final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>(); - final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>(); - - //flag to detect fat touch events - boolean mFatTouch = false; - Display mDisplay; - - H mH = new H(); - - WindowState mCurrentFocus = null; - WindowState mLastFocus = null; - - // This just indicates the window the input method is on top of, not - // necessarily the window its input is going to. - WindowState mInputMethodTarget = null; - WindowState mUpcomingInputMethodTarget = null; - boolean mInputMethodTargetWaitingAnim; - int mInputMethodAnimLayerAdjustment; - - WindowState mInputMethodWindow = null; - final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>(); - - AppWindowToken mFocusedApp = null; - - PowerManagerService mPowerManager; - - float mWindowAnimationScale = 1.0f; - float mTransitionAnimationScale = 1.0f; - - final KeyWaiter mKeyWaiter = new KeyWaiter(); - final KeyQ mQueue; - final InputDispatcherThread mInputThread; - - // Who is holding the screen on. - Session mHoldingScreenOn; - - /** - * Whether the UI is currently running in touch mode (not showing - * navigational focus because the user is directly pressing the screen). - */ - boolean mInTouchMode = false; - - private ViewServer mViewServer; - - final Rect mTempRect = new Rect(); - - public static WindowManagerService main(Context context, - PowerManagerService pm, boolean haveInputMethods) { - WMThread thr = new WMThread(context, pm, haveInputMethods); - thr.start(); - - synchronized (thr) { - while (thr.mService == null) { - try { - thr.wait(); - } catch (InterruptedException e) { - } - } - } - - return thr.mService; - } - - static class WMThread extends Thread { - WindowManagerService mService; - - private final Context mContext; - private final PowerManagerService mPM; - private final boolean mHaveInputMethods; - - public WMThread(Context context, PowerManagerService pm, - boolean haveInputMethods) { - super("WindowManager"); - mContext = context; - mPM = pm; - mHaveInputMethods = haveInputMethods; - } - - public void run() { - Looper.prepare(); - WindowManagerService s = new WindowManagerService(mContext, mPM, - mHaveInputMethods); - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_DISPLAY); - - synchronized (this) { - mService = s; - notifyAll(); - } - - Looper.loop(); - } - } - - static class PolicyThread extends Thread { - private final WindowManagerPolicy mPolicy; - private final WindowManagerService mService; - private final Context mContext; - private final PowerManagerService mPM; - boolean mRunning = false; - - public PolicyThread(WindowManagerPolicy policy, - WindowManagerService service, Context context, - PowerManagerService pm) { - super("WindowManagerPolicy"); - mPolicy = policy; - mService = service; - mContext = context; - mPM = pm; - } - - public void run() { - Looper.prepare(); - //Looper.myLooper().setMessageLogging(new LogPrinter( - // Log.VERBOSE, "WindowManagerPolicy")); - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND); - mPolicy.init(mContext, mService, mPM); - - synchronized (this) { - mRunning = true; - notifyAll(); - } - - Looper.loop(); - } - } - - private WindowManagerService(Context context, PowerManagerService pm, - boolean haveInputMethods) { - mContext = context; - mHaveInputMethods = haveInputMethods; - mLimitedAlphaCompositing = context.getResources().getBoolean( - com.android.internal.R.bool.config_sf_limitedAlpha); - - mPowerManager = pm; - mPowerManager.setPolicy(mPolicy); - PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, - "SCREEN_FROZEN"); - mScreenFrozenLock.setReferenceCounted(false); - - mActivityManager = ActivityManagerNative.getDefault(); - mBatteryStats = BatteryStatsService.getService(); - - // Get persisted window scale setting - mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(), - Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); - mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(), - Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); - - mQueue = new KeyQ(); - - mInputThread = new InputDispatcherThread(); - - PolicyThread thr = new PolicyThread(mPolicy, this, context, pm); - thr.start(); - - synchronized (thr) { - while (!thr.mRunning) { - try { - thr.wait(); - } catch (InterruptedException e) { - } - } - } - - mInputThread.start(); - - // Add ourself to the Watchdog monitors. - Watchdog.getInstance().addMonitor(this); - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - // The window manager only throws security exceptions, so let's - // log all others. - if (!(e instanceof SecurityException)) { - Log.e(TAG, "Window Manager Crash", e); - } - throw e; - } - } - - private void placeWindowAfter(Object pos, WindowState window) { - final int i = mWindows.indexOf(pos); - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Adding window " + window + " at " - + (i+1) + " of " + mWindows.size() + " (after " + pos + ")"); - mWindows.add(i+1, window); - } - - private void placeWindowBefore(Object pos, WindowState window) { - final int i = mWindows.indexOf(pos); - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Adding window " + window + " at " - + i + " of " + mWindows.size() + " (before " + pos + ")"); - mWindows.add(i, window); - } - - //This method finds out the index of a window that has the same app token as - //win. used for z ordering the windows in mWindows - private int findIdxBasedOnAppTokens(WindowState win) { - //use a local variable to cache mWindows - ArrayList localmWindows = mWindows; - int jmax = localmWindows.size(); - if(jmax == 0) { - return -1; - } - for(int j = (jmax-1); j >= 0; j--) { - WindowState wentry = (WindowState)localmWindows.get(j); - if(wentry.mAppToken == win.mAppToken) { - return j; - } - } - return -1; - } - - private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) { - final IWindow client = win.mClient; - final WindowToken token = win.mToken; - final ArrayList localmWindows = mWindows; - - final int N = localmWindows.size(); - final WindowState attached = win.mAttachedWindow; - int i; - if (attached == null) { - int tokenWindowsPos = token.windows.size(); - if (token.appWindowToken != null) { - int index = tokenWindowsPos-1; - if (index >= 0) { - // If this application has existing windows, we - // simply place the new window on top of them... but - // keep the starting window on top. - if (win.mAttrs.type == TYPE_BASE_APPLICATION) { - // Base windows go behind everything else. - placeWindowBefore(token.windows.get(0), win); - tokenWindowsPos = 0; - } else { - AppWindowToken atoken = win.mAppToken; - if (atoken != null && - token.windows.get(index) == atoken.startingWindow) { - placeWindowBefore(token.windows.get(index), win); - tokenWindowsPos--; - } else { - int newIdx = findIdxBasedOnAppTokens(win); - if(newIdx != -1) { - //there is a window above this one associated with the same - //apptoken note that the window could be a floating window - //that was created later or a window at the top of the list of - //windows associated with this token. - localmWindows.add(newIdx+1, win); - } - } - } - } else { - if (localLOGV) Log.v( - TAG, "Figuring out where to add app window " - + client.asBinder() + " (token=" + token + ")"); - // Figure out where the window should go, based on the - // order of applications. - final int NA = mAppTokens.size(); - Object pos = null; - for (i=NA-1; i>=0; i--) { - AppWindowToken t = mAppTokens.get(i); - if (t == token) { - i--; - break; - } - if (t.windows.size() > 0) { - pos = t.windows.get(0); - } - } - // We now know the index into the apps. If we found - // an app window above, that gives us the position; else - // we need to look some more. - if (pos != null) { - // Move behind any windows attached to this one. - WindowToken atoken = - mTokenMap.get(((WindowState)pos).mClient.asBinder()); - if (atoken != null) { - final int NC = atoken.windows.size(); - if (NC > 0) { - WindowState bottom = atoken.windows.get(0); - if (bottom.mSubLayer < 0) { - pos = bottom; - } - } - } - placeWindowBefore(pos, win); - } else { - while (i >= 0) { - AppWindowToken t = mAppTokens.get(i); - final int NW = t.windows.size(); - if (NW > 0) { - pos = t.windows.get(NW-1); - break; - } - i--; - } - if (pos != null) { - // Move in front of any windows attached to this - // one. - WindowToken atoken = - mTokenMap.get(((WindowState)pos).mClient.asBinder()); - if (atoken != null) { - final int NC = atoken.windows.size(); - if (NC > 0) { - WindowState top = atoken.windows.get(NC-1); - if (top.mSubLayer >= 0) { - pos = top; - } - } - } - placeWindowAfter(pos, win); - } else { - // Just search for the start of this layer. - final int myLayer = win.mBaseLayer; - for (i=0; i<N; i++) { - WindowState w = (WindowState)localmWindows.get(i); - if (w.mBaseLayer > myLayer) { - break; - } - } - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Adding window " + win + " at " - + i + " of " + N); - localmWindows.add(i, win); - } - } - } - } else { - // Figure out where window should go, based on layer. - final int myLayer = win.mBaseLayer; - for (i=N-1; i>=0; i--) { - if (((WindowState)localmWindows.get(i)).mBaseLayer <= myLayer) { - i++; - break; - } - } - if (i < 0) i = 0; - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Adding window " + win + " at " - + i + " of " + N); - localmWindows.add(i, win); - } - if (addToToken) { - token.windows.add(tokenWindowsPos, win); - } - - } else { - // Figure out this window's ordering relative to the window - // it is attached to. - final int NA = token.windows.size(); - final int sublayer = win.mSubLayer; - int largestSublayer = Integer.MIN_VALUE; - WindowState windowWithLargestSublayer = null; - for (i=0; i<NA; i++) { - WindowState w = token.windows.get(i); - final int wSublayer = w.mSubLayer; - if (wSublayer >= largestSublayer) { - largestSublayer = wSublayer; - windowWithLargestSublayer = w; - } - if (sublayer < 0) { - // For negative sublayers, we go below all windows - // in the same sublayer. - if (wSublayer >= sublayer) { - if (addToToken) { - token.windows.add(i, win); - } - placeWindowBefore( - wSublayer >= 0 ? attached : w, win); - break; - } - } else { - // For positive sublayers, we go above all windows - // in the same sublayer. - if (wSublayer > sublayer) { - if (addToToken) { - token.windows.add(i, win); - } - placeWindowBefore(w, win); - break; - } - } - } - if (i >= NA) { - if (addToToken) { - token.windows.add(win); - } - if (sublayer < 0) { - placeWindowBefore(attached, win); - } else { - placeWindowAfter(largestSublayer >= 0 - ? windowWithLargestSublayer - : attached, - win); - } - } - } - - if (win.mAppToken != null && addToToken) { - win.mAppToken.allAppWindows.add(win); - } - } - - static boolean canBeImeTarget(WindowState w) { - final int fl = w.mAttrs.flags - & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); - if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) { - return w.isVisibleOrAdding(); - } - return false; - } - - int findDesiredInputMethodWindowIndexLocked(boolean willMove) { - final ArrayList localmWindows = mWindows; - final int N = localmWindows.size(); - WindowState w = null; - int i = N; - while (i > 0) { - i--; - w = (WindowState)localmWindows.get(i); - - //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x" - // + Integer.toHexString(w.mAttrs.flags)); - if (canBeImeTarget(w)) { - //Log.i(TAG, "Putting input method here!"); - - // Yet more tricksyness! If this window is a "starting" - // window, we do actually want to be on top of it, but - // it is not -really- where input will go. So if the caller - // is not actually looking to move the IME, look down below - // for a real window to target... - if (!willMove - && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING - && i > 0) { - WindowState wb = (WindowState)localmWindows.get(i-1); - if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { - i--; - w = wb; - } - } - break; - } - } - - mUpcomingInputMethodTarget = w; - - 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) { - - // Now some fun for dealing with window animations that - // modify the Z order. We need to look at all windows below - // the current target that are in this app, finding the highest - // visible one in layering. - AppWindowToken token = curTarget.mAppToken; - WindowState highestTarget = null; - int highestPos = 0; - if (token.animating || token.animation != null) { - int pos = 0; - pos = localmWindows.indexOf(curTarget); - while (pos >= 0) { - WindowState win = (WindowState)localmWindows.get(pos); - if (win.mAppToken != token) { - break; - } - if (!win.mRemoved) { - if (highestTarget == null || win.mAnimLayer > - highestTarget.mAnimLayer) { - highestTarget = win; - highestPos = pos; - } - } - pos--; - } - } - - if (highestTarget != null) { - if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition=" - + mNextAppTransition + " " + highestTarget - + " animating=" + highestTarget.isAnimating() - + " layer=" + highestTarget.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; - mInputMethodTarget = highestTarget; - return highestPos + 1; - } else if (highestTarget.isAnimating() && - highestTarget.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. - mInputMethodTarget = highestTarget; - return highestPos + 1; - } - } - } - } - - //Log.i(TAG, "Placing input method @" + (i+1)); - if (w != null) { - 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; - } - 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(true); - if (pos >= 0) { - win.mTargetAppToken = mInputMethodTarget.mAppToken; - mWindows.add(pos, win); - moveInputMethodDialogsLocked(pos+1); - return; - } - win.mTargetAppToken = null; - addWindowToListInOrderLocked(win, true); - 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) { - if (wpos < interestingPos) interestingPos--; - mWindows.remove(wpos); - int NC = win.mChildWindows.size(); - while (NC > 0) { - NC--; - WindowState cw = (WindowState)win.mChildWindows.get(NC); - int cpos = mWindows.indexOf(cw); - if (cpos >= 0) { - if (cpos < interestingPos) interestingPos--; - mWindows.remove(cpos); - } - } - } - return interestingPos; - } - - private void reAddWindowToListInOrderLocked(WindowState win) { - addWindowToListInOrderLocked(win, false); - // This is a hack to get all of the child windows added as well - // at the right position. Child windows should be rare and - // this case should be rare, so it shouldn't be that big a deal. - int wpos = mWindows.indexOf(win); - if (wpos >= 0) { - mWindows.remove(wpos); - reAddWindowLocked(wpos, win); - } - } - - void logWindowList(String prefix) { - int N = mWindows.size(); - while (N > 0) { - N--; - Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N)); - } - } - - void moveInputMethodDialogsLocked(int pos) { - ArrayList<WindowState> dialogs = mInputMethodDialogs; - - final int N = dialogs.size(); - if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos); - for (int i=0; i<N; i++) { - pos = tmpRemoveWindowLocked(pos, dialogs.get(i)); - } - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "Window list w/pos=" + pos); - logWindowList(" "); - } - - if (pos >= 0) { - final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken; - if (pos < mWindows.size()) { - WindowState wp = (WindowState)mWindows.get(pos); - if (wp == mInputMethodWindow) { - pos++; - } - } - if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos); - for (int i=0; i<N; i++) { - WindowState win = dialogs.get(i); - win.mTargetAppToken = targetAppToken; - pos = reAddWindowLocked(pos, win); - } - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "Final window list:"); - logWindowList(" "); - } - return; - } - for (int i=0; i<N; i++) { - WindowState win = dialogs.get(i); - win.mTargetAppToken = null; - reAddWindowToListInOrderLocked(win); - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "No IM target, final list:"); - logWindowList(" "); - } - } - } - - boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) { - final WindowState imWin = mInputMethodWindow; - final int DN = mInputMethodDialogs.size(); - if (imWin == null && DN == 0) { - return false; - } - - int imPos = findDesiredInputMethodWindowIndexLocked(true); - if (imPos >= 0) { - // In this case, the input method windows are to be placed - // immediately above the window they are targeting. - - // First check to see if the input method windows are already - // located here, and contiguous. - final int N = mWindows.size(); - WindowState firstImWin = imPos < N - ? (WindowState)mWindows.get(imPos) : null; - - // Figure out the actual input method window that should be - // at the bottom of their stack. - WindowState baseImWin = imWin != null - ? imWin : mInputMethodDialogs.get(0); - if (baseImWin.mChildWindows.size() > 0) { - WindowState cw = (WindowState)baseImWin.mChildWindows.get(0); - if (cw.mSubLayer < 0) baseImWin = cw; - } - - if (firstImWin == baseImWin) { - // The windows haven't moved... but are they still contiguous? - // First find the top IM window. - int pos = imPos+1; - while (pos < N) { - if (!((WindowState)mWindows.get(pos)).mIsImWindow) { - break; - } - pos++; - } - pos++; - // Now there should be no more input method windows above. - while (pos < N) { - if (((WindowState)mWindows.get(pos)).mIsImWindow) { - break; - } - pos++; - } - if (pos >= N) { - // All is good! - return false; - } - } - - if (imWin != null) { - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "Moving IM from " + imPos); - logWindowList(" "); - } - imPos = tmpRemoveWindowLocked(imPos, imWin); - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "List after moving with new pos " + imPos + ":"); - logWindowList(" "); - } - imWin.mTargetAppToken = mInputMethodTarget.mAppToken; - reAddWindowLocked(imPos, imWin); - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "List after moving IM to " + imPos + ":"); - logWindowList(" "); - } - if (DN > 0) moveInputMethodDialogsLocked(imPos+1); - } else { - moveInputMethodDialogsLocked(imPos); - } - - } else { - // In this case, the input method windows go in a fixed layer, - // because they aren't currently associated with a focus window. - - if (imWin != null) { - if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos); - tmpRemoveWindowLocked(0, imWin); - imWin.mTargetAppToken = null; - reAddWindowToListInOrderLocked(imWin); - if (DEBUG_INPUT_METHOD) { - Log.v(TAG, "List with no IM target:"); - logWindowList(" "); - } - if (DN > 0) moveInputMethodDialogsLocked(-1);; - } else { - moveInputMethodDialogsLocked(-1);; - } - - } - - if (needAssignLayers) { - assignLayersLocked(); - } - - return true; - } - - void adjustInputMethodDialogsLocked() { - moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true)); - } - - public int addWindow(Session session, IWindow client, - WindowManager.LayoutParams attrs, int viewVisibility, - Rect outContentInsets) { - int res = mPolicy.checkAddPermission(attrs); - if (res != WindowManagerImpl.ADD_OKAY) { - return res; - } - - boolean reportNewConfig = false; - WindowState attachedWindow = null; - WindowState win = null; - - synchronized(mWindowMap) { - // Instantiating a Display requires talking with the simulator, - // so don't do it until we know the system is mostly up and - // running. - if (mDisplay == null) { - WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); - mDisplay = wm.getDefaultDisplay(); - mQueue.setDisplay(mDisplay); - reportNewConfig = true; - } - - if (mWindowMap.containsKey(client.asBinder())) { - Log.w(TAG, "Window " + client + " is already added"); - return WindowManagerImpl.ADD_DUPLICATE_ADD; - } - - if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) { - attachedWindow = windowForClientLocked(null, attrs.token); - if (attachedWindow == null) { - Log.w(TAG, "Attempted to add window with token that is not a window: " - + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; - } - if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW - && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) { - Log.w(TAG, "Attempted to add window with token that is a sub-window: " - + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; - } - } - - boolean addToken = false; - WindowToken token = mTokenMap.get(attrs.token); - if (token == null) { - if (attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW) { - Log.w(TAG, "Attempted to add application window with unknown token " - + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; - } - if (attrs.type == TYPE_INPUT_METHOD) { - Log.w(TAG, "Attempted to add input method window with unknown token " - + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; - } - token = new WindowToken(attrs.token, -1, false); - addToken = true; - } else if (attrs.type >= FIRST_APPLICATION_WINDOW - && attrs.type <= LAST_APPLICATION_WINDOW) { - AppWindowToken atoken = token.appWindowToken; - if (atoken == null) { - Log.w(TAG, "Attempted to add window with non-application token " - + token + ". Aborting."); - return WindowManagerImpl.ADD_NOT_APP_TOKEN; - } else if (atoken.removed) { - Log.w(TAG, "Attempted to add window with exiting application token " - + token + ". Aborting."); - return WindowManagerImpl.ADD_APP_EXITING; - } - if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) { - // No need for this guy! - if (localLOGV) Log.v( - TAG, "**** NO NEED TO START: " + attrs.getTitle()); - return WindowManagerImpl.ADD_STARTING_NOT_NEEDED; - } - } else if (attrs.type == TYPE_INPUT_METHOD) { - if (token.windowType != TYPE_INPUT_METHOD) { - Log.w(TAG, "Attempted to add input method window with bad token " - + attrs.token + ". Aborting."); - return WindowManagerImpl.ADD_BAD_APP_TOKEN; - } - } - - win = new WindowState(session, client, token, - attachedWindow, attrs, viewVisibility); - if (win.mDeathRecipient == null) { - // Client has apparently died, so there is no reason to - // continue. - Log.w(TAG, "Adding window client " + client.asBinder() - + " that is dead, aborting."); - return WindowManagerImpl.ADD_APP_EXITING; - } - - mPolicy.adjustWindowParamsLw(win.mAttrs); - - res = mPolicy.prepareAddWindowLw(win, attrs); - if (res != WindowManagerImpl.ADD_OKAY) { - return res; - } - - // From now on, no exceptions or errors allowed! - - res = WindowManagerImpl.ADD_OKAY; - - final long origId = Binder.clearCallingIdentity(); - - if (addToken) { - mTokenMap.put(attrs.token, token); - mTokenList.add(token); - } - win.attach(); - mWindowMap.put(client.asBinder(), win); - - if (attrs.type == TYPE_APPLICATION_STARTING && - token.appWindowToken != null) { - token.appWindowToken.startingWindow = win; - } - - boolean imMayMove = true; - - if (attrs.type == TYPE_INPUT_METHOD) { - mInputMethodWindow = win; - addInputMethodWindowToListLocked(win); - imMayMove = false; - } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) { - mInputMethodDialogs.add(win); - addWindowToListInOrderLocked(win, true); - adjustInputMethodDialogsLocked(); - imMayMove = false; - } else { - addWindowToListInOrderLocked(win, true); - } - - win.mEnterAnimationPending = true; - - mPolicy.getContentInsetHintLw(attrs, outContentInsets); - - if (mInTouchMode) { - res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE; - } - if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) { - res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE; - } - - if (win.canReceiveKeys()) { - if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS)) { - imMayMove = false; - } - } - - if (imMayMove) { - moveInputMethodWindowsIfNeededLocked(false); - } - - assignLayersLocked(); - // Don't do layout here, the window must call - // relayout to be displayed, so we'll do it there. - - //dump(); - - if (localLOGV) Log.v( - TAG, "New client " + client.asBinder() - + ": 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) { - sendNewConfiguration(); - } 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; - } - - public void removeWindow(Session session, IWindow client) { - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); - if (win == null) { - return; - } - removeWindowLocked(session, win); - } - } - - public void removeWindowLocked(Session session, WindowState win) { - - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Remove " + win + " client=" - + Integer.toHexString(System.identityHashCode( - win.mClient.asBinder())) - + ", surface=" + win.mSurface); - - final long origId = Binder.clearCallingIdentity(); - - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Remove " + win + ": mSurface=" + win.mSurface - + " mExiting=" + win.mExiting - + " isAnimating=" + win.isAnimating() - + " app-animation=" - + (win.mAppToken != null ? win.mAppToken.animation : null) - + " 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 - // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen) { - // If we are not currently running the exit animation, we - // need to see about starting one. - if (wasVisible=win.isWinVisibleLw()) { - - int transit = WindowManagerPolicy.TRANSIT_EXIT; - if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { - transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; - } - // Try starting an animation. - if (applyAnimationLocked(win, transit, false)) { - win.mExiting = true; - } - } - if (win.mExiting || win.isAnimating()) { - // The exit animation is running... wait for it! - //Log.i(TAG, "*** Running exit animation..."); - win.mExiting = true; - win.mRemoveOnExit = true; - mLayoutNeeded = true; - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); - performLayoutAndPlaceSurfacesLocked(); - if (win.mAppToken != null) { - win.mAppToken.updateReportedVisibilityLocked(); - } - //dump(); - Binder.restoreCallingIdentity(origId); - return; - } - } - - 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); - } - - private void removeWindowInnerLocked(Session session, WindowState win) { - mKeyWaiter.releasePendingPointerLocked(win.mSession); - mKeyWaiter.releasePendingTrackballLocked(win.mSession); - - win.mRemoved = true; - - if (mInputMethodTarget == win) { - moveInputMethodWindowsIfNeededLocked(false); - } - - mPolicy.removeWindowLw(win); - win.removeLocked(); - - mWindowMap.remove(win.mClient.asBinder()); - mWindows.remove(win); - - if (mInputMethodWindow == win) { - mInputMethodWindow = null; - } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { - mInputMethodDialogs.remove(win); - } - - final WindowToken token = win.mToken; - final AppWindowToken atoken = win.mAppToken; - token.windows.remove(win); - if (atoken != null) { - atoken.allAppWindows.remove(win); - } - if (localLOGV) Log.v( - TAG, "**** Removing window " + win + ": count=" - + token.windows.size()); - if (token.windows.size() == 0) { - if (!token.explicit) { - mTokenMap.remove(token.token); - mTokenList.remove(token); - } else if (atoken != null) { - atoken.firstWindowDrawn = false; - } - } - - if (atoken != null) { - if (atoken.startingWindow == win) { - atoken.startingWindow = null; - } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) { - // If this is the last window and we had requested a starting - // transition window, well there is no point now. - atoken.startingData = null; - } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) { - // If this is the last window except for a starting transition - // window, we need to get rid of the starting transition. - if (DEBUG_STARTING_WINDOW) { - Log.v(TAG, "Schedule remove starting " + token - + ": no more real windows"); - } - Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken); - mH.sendMessage(m); - } - } - - if (!mInLayout) { - assignLayersLocked(); - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - if (win.mAppToken != null) { - win.mAppToken.updateReportedVisibilityLocked(); - } - } - } - - private void setTransparentRegionWindow(Session session, IWindow client, Region region) { - long origId = Binder.clearCallingIdentity(); - try { - synchronized (mWindowMap) { - WindowState w = windowForClientLocked(session, client); - if ((w != null) && (w.mSurface != null)) { - Surface.openTransaction(); - try { - w.mSurface.setTransparentRegionHint(region); - } finally { - Surface.closeTransaction(); - } - } - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - void setInsetsWindow(Session session, IWindow client, - int touchableInsets, Rect contentInsets, - Rect visibleInsets) { - long origId = Binder.clearCallingIdentity(); - try { - synchronized (mWindowMap) { - WindowState w = windowForClientLocked(session, client); - if (w != null) { - w.mGivenInsetsPending = false; - w.mGivenContentInsets.set(contentInsets); - w.mGivenVisibleInsets.set(visibleInsets); - w.mTouchableInsets = touchableInsets; - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - public void getWindowDisplayFrame(Session session, IWindow client, - Rect outDisplayFrame) { - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); - if (win == null) { - outDisplayFrame.setEmpty(); - return; - } - outDisplayFrame.set(win.mDisplayFrame); - } - } - - public int relayoutWindow(Session session, IWindow client, - WindowManager.LayoutParams attrs, int requestedWidth, - int requestedHeight, int viewVisibility, boolean insetsPending, - Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, - Surface outSurface) { - boolean displayed = false; - boolean inTouchMode; - Configuration newConfig = null; - long origId = Binder.clearCallingIdentity(); - - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); - if (win == null) { - return 0; - } - win.mRequestedWidth = requestedWidth; - win.mRequestedHeight = requestedHeight; - - if (attrs != null) { - mPolicy.adjustWindowParamsLw(attrs); - } - - int attrChanges = 0; - int flagChanges = 0; - if (attrs != null) { - flagChanges = win.mAttrs.flags ^= attrs.flags; - attrChanges = win.mAttrs.copyFrom(attrs); - } - - if (localLOGV) Log.v( - TAG, "Relayout given client " + client.asBinder() - + " (" + win.mAttrs.getTitle() + ")"); - - - if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { - win.mAlpha = attrs.alpha; - } - - final boolean scaledWindow = - ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0); - - if (scaledWindow) { - // requested{Width|Height} Surface's physical size - // attrs.{width|height} Size on screen - win.mHScale = (attrs.width != requestedWidth) ? - (attrs.width / (float)requestedWidth) : 1.0f; - win.mVScale = (attrs.height != requestedHeight) ? - (attrs.height / (float)requestedHeight) : 1.0f; - } - - boolean imMayMove = (flagChanges&( - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0; - - boolean focusMayChange = win.mViewVisibility != viewVisibility - || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0) - || (!win.mRelayoutCalled); - - win.mRelayoutCalled = true; - final int oldVisibility = win.mViewVisibility; - win.mViewVisibility = viewVisibility; - if (viewVisibility == View.VISIBLE && - (win.mAppToken == null || !win.mAppToken.clientHidden)) { - displayed = !win.isVisibleLw(); - if (win.mExiting) { - win.mExiting = false; - win.mAnimation = null; - } - if (win.mDestroying) { - win.mDestroying = false; - mDestroySurface.remove(win); - } - if (oldVisibility == View.GONE) { - win.mEnterAnimationPending = true; - } - if (displayed && win.mSurface != null && !win.mDrawPending - && !win.mCommitDrawPending && !mDisplayFrozen) { - applyEnterAnimationLocked(win); - } - if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) { - // To change the format, we need to re-build the surface. - win.destroySurfaceLocked(); - displayed = true; - } - try { - Surface surface = win.createSurfaceLocked(); - if (surface != null) { - outSurface.copyFrom(surface); - } else { - outSurface.clear(); - } - } catch (Exception e) { - Log.w(TAG, "Exception thrown when creating surface for client " - + client + " (" + win.mAttrs.getTitle() + ")", - e); - Binder.restoreCallingIdentity(origId); - return 0; - } - if (displayed) { - focusMayChange = true; - } - if (win.mAttrs.type == TYPE_INPUT_METHOD - && mInputMethodWindow == null) { - mInputMethodWindow = win; - imMayMove = true; - } - } else { - win.mEnterAnimationPending = false; - if (win.mSurface != null) { - // If we are not currently running the exit animation, we - // need to see about starting one. - if (!win.mExiting) { - // Try starting an animation; if there isn't one, we - // can destroy the surface right away. - int transit = WindowManagerPolicy.TRANSIT_EXIT; - if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { - transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; - } - if (win.isWinVisibleLw() && - applyAnimationLocked(win, transit, false)) { - win.mExiting = true; - mKeyWaiter.finishedKey(session, client, true, - KeyWaiter.RETURN_NOTHING); - } else if (win.isAnimating()) { - // Currently in a hide animation... turn this into - // an exit. - win.mExiting = true; - } else { - if (mInputMethodWindow == win) { - mInputMethodWindow = null; - } - win.destroySurfaceLocked(); - } - } - } - outSurface.clear(); - } - - boolean assignLayers = false; - - if (focusMayChange) { - //System.out.println("Focus may change: " + win.mAttrs.getTitle()); - if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) { - assignLayers = true; - imMayMove = false; - } - //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); - } - - if (imMayMove) { - if (moveInputMethodWindowsIfNeededLocked(false)) { - assignLayers = true; - } - } - - mLayoutNeeded = true; - win.mGivenInsetsPending = insetsPending; - if (assignLayers) { - assignLayersLocked(); - } - newConfig = updateOrientationFromAppTokensLocked(null); - performLayoutAndPlaceSurfacesLocked(); - if (win.mAppToken != null) { - win.mAppToken.updateReportedVisibilityLocked(); - } - outFrame.set(win.mFrame); - outContentInsets.set(win.mContentInsets); - outVisibleInsets.set(win.mVisibleInsets); - if (localLOGV) Log.v( - TAG, "Relayout given client " + client.asBinder() - + ", requestedWidth=" + requestedWidth - + ", requestedHeight=" + requestedHeight - + ", viewVisibility=" + viewVisibility - + "\nRelayout returning frame=" + outFrame - + ", surface=" + outSurface); - - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange); - - inTouchMode = mInTouchMode; - } - - if (newConfig != null) { - sendNewConfiguration(); - } - - Binder.restoreCallingIdentity(origId); - - return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0) - | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0); - } - - public void finishDrawingWindow(Session session, IWindow client) { - final long origId = Binder.clearCallingIdentity(); - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(session, client); - if (win != null && win.finishDrawingLocked()) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } - Binder.restoreCallingIdentity(origId); - } - - private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { - if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package=" - + (lp != null ? lp.packageName : null) - + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); - if (lp != null && lp.windowAnimations != 0) { - // If this is a system resource, don't try to load it from the - // application resources. It is nice to avoid loading application - // resources if we can. - String packageName = lp.packageName != null ? lp.packageName : "android"; - int resId = lp.windowAnimations; - if ((resId&0xFF000000) == 0x01000000) { - packageName = "android"; - } - if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package=" - + packageName); - return AttributeCache.instance().get(packageName, resId, - com.android.internal.R.styleable.WindowAnimation); - } - return null; - } - - private void applyEnterAnimationLocked(WindowState win) { - int transit = WindowManagerPolicy.TRANSIT_SHOW; - if (win.mEnterAnimationPending) { - win.mEnterAnimationPending = false; - transit = WindowManagerPolicy.TRANSIT_ENTER; - } - - applyAnimationLocked(win, transit, true); - } - - private boolean applyAnimationLocked(WindowState win, - int transit, boolean isEntrance) { - if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) { - // If we are trying to apply an animation, but already running - // an animation of the same type, then just leave that one alone. - return true; - } - - // Only apply an animation if the display isn't frozen. If it is - // frozen, there is no reason to animate and it can cause strange - // artifacts when we unfreeze the display if some different animation - // is running. - if (!mDisplayFrozen) { - int anim = mPolicy.selectAnimationLw(win, transit); - int attr = -1; - Animation a = null; - if (anim != 0) { - a = AnimationUtils.loadAnimation(mContext, anim); - } else { - switch (transit) { - case WindowManagerPolicy.TRANSIT_ENTER: - attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation; - break; - case WindowManagerPolicy.TRANSIT_EXIT: - attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_SHOW: - attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation; - break; - case WindowManagerPolicy.TRANSIT_HIDE: - attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation; - break; - } - if (attr >= 0) { - a = loadAnimation(win.mAttrs, attr); - } - } - if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win - + " anim=" + anim + " attr=0x" + Integer.toHexString(attr) - + " mAnimation=" + win.mAnimation - + " isEntrance=" + isEntrance); - if (a != null) { - if (DEBUG_ANIM) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.v(TAG, "Loaded animation " + a + " for " + win, e); - } - win.setAnimation(a); - win.mAnimationIsEntrance = isEntrance; - } - } else { - win.clearAnimation(); - } - - return win.mAnimation != null; - } - - private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { - int anim = 0; - Context context = mContext; - if (animAttr >= 0) { - AttributeCache.Entry ent = getCachedAnimations(lp); - if (ent != null) { - context = ent.context; - anim = ent.array.getResourceId(animAttr, 0); - } - } - if (anim != 0) { - return AnimationUtils.loadAnimation(context, anim); - } - return null; - } - - private boolean applyAnimationLocked(AppWindowToken wtoken, - WindowManager.LayoutParams lp, int transit, boolean enter) { - // Only apply an animation if the display isn't frozen. If it is - // frozen, there is no reason to animate and it can cause strange - // artifacts when we unfreeze the display if some different animation - // is running. - if (!mDisplayFrozen) { - int animAttr = 0; - switch (transit) { - case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_TASK_OPEN: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_TASK_CLOSE: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: - animAttr = enter - ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation - : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; - break; - } - Animation a = loadAnimation(lp, animAttr); - if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken - + " anim=" + a - + " animAttr=0x" + Integer.toHexString(animAttr) - + " transit=" + transit); - if (a != null) { - if (DEBUG_ANIM) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e); - } - wtoken.setAnimation(a); - } - } else { - wtoken.clearAnimation(); - } - - return wtoken.animation != null; - } - - // ------------------------------------------------------------- - // Application Window Tokens - // ------------------------------------------------------------- - - public void validateAppTokens(List tokens) { - int v = tokens.size()-1; - int m = mAppTokens.size()-1; - while (v >= 0 && m >= 0) { - AppWindowToken wtoken = mAppTokens.get(m); - if (wtoken.removed) { - m--; - continue; - } - if (tokens.get(v) != wtoken.token) { - Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v) - + " @ " + v + ", internal is " + wtoken.token + " @ " + m); - } - v--; - m--; - } - while (v >= 0) { - Log.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v); - v--; - } - while (m >= 0) { - AppWindowToken wtoken = mAppTokens.get(m); - if (!wtoken.removed) { - Log.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m); - } - m--; - } - } - - boolean checkCallingPermission(String permission, String func) { - // Quick check: if the calling permission is me, it's all okay. - if (Binder.getCallingPid() == Process.myPid()) { - return true; - } - - if (mContext.checkCallingPermission(permission) - == PackageManager.PERMISSION_GRANTED) { - return true; - } - String msg = "Permission Denial: " + func + " from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + permission; - Log.w(TAG, msg); - return false; - } - - AppWindowToken findAppWindowToken(IBinder token) { - WindowToken wtoken = mTokenMap.get(token); - if (wtoken == null) { - return null; - } - return wtoken.appWindowToken; - } - - public void addWindowToken(IBinder token, int type) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "addWindowToken()")) { - return; - } - - synchronized(mWindowMap) { - WindowToken wtoken = mTokenMap.get(token); - if (wtoken != null) { - Log.w(TAG, "Attempted to add existing input method token: " + token); - return; - } - wtoken = new WindowToken(token, type, true); - mTokenMap.put(token, wtoken); - mTokenList.add(wtoken); - } - } - - public void removeWindowToken(IBinder token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "removeWindowToken()")) { - return; - } - - final long origId = Binder.clearCallingIdentity(); - synchronized(mWindowMap) { - WindowToken wtoken = mTokenMap.remove(token); - mTokenList.remove(wtoken); - if (wtoken != null) { - boolean delayed = false; - if (!wtoken.hidden) { - wtoken.hidden = true; - - final int N = wtoken.windows.size(); - boolean changed = false; - - for (int i=0; i<N; i++) { - WindowState win = wtoken.windows.get(i); - - if (win.isAnimating()) { - delayed = true; - } - - if (win.isVisibleNow()) { - applyAnimationLocked(win, - WindowManagerPolicy.TRANSIT_EXIT, false); - mKeyWaiter.finishedKey(win.mSession, win.mClient, true, - KeyWaiter.RETURN_NOTHING); - changed = true; - } - } - - if (changed) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); - } - - if (delayed) { - mExitingTokens.add(wtoken); - } - } - - } else { - Log.w(TAG, "Attempted to remove non-existing token: " + token); - } - } - Binder.restoreCallingIdentity(origId); - } - - public void addAppToken(int addPos, IApplicationToken token, - int groupId, int requestedOrientation, boolean fullscreen) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "addAppToken()")) { - return; - } - - synchronized(mWindowMap) { - AppWindowToken wtoken = findAppWindowToken(token.asBinder()); - if (wtoken != null) { - Log.w(TAG, "Attempted to add existing app token: " + token); - return; - } - wtoken = new AppWindowToken(token); - wtoken.groupId = groupId; - wtoken.appFullscreen = fullscreen; - wtoken.requestedOrientation = requestedOrientation; - mAppTokens.add(addPos, wtoken); - if (Config.LOGV) Log.v(TAG, "Adding new app token: " + wtoken); - mTokenMap.put(token.asBinder(), wtoken); - mTokenList.add(wtoken); - - // Application tokens start out hidden. - wtoken.hidden = true; - wtoken.hiddenRequested = true; - - //dump(); - } - } - - public void setAppGroupId(IBinder token, int groupId) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppStartingIcon()")) { - return; - } - - synchronized(mWindowMap) { - AppWindowToken wtoken = findAppWindowToken(token); - if (wtoken == null) { - Log.w(TAG, "Attempted to set group id of non-existing app token: " + token); - return; - } - wtoken.groupId = groupId; - } - } - - 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 curGroup = 0; - int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - boolean haveGroup = false; - while (pos >= 0) { - AppWindowToken wtoken = mAppTokens.get(pos); - pos--; - if (!haveGroup) { - // We ignore any hidden applications on the top. - if (wtoken.hiddenRequested || wtoken.willBeHidden) { - continue; - } - haveGroup = true; - curGroup = wtoken.groupId; - lastOrientation = wtoken.requestedOrientation; - } else if (curGroup != wtoken.groupId) { - // If we have hit a new application group, and the bottom - // of the previous group didn't explicitly say to use - // the orientation behind it, then we'll stick with the - // user's orientation. - if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { - return lastOrientation; - } - } - int or = wtoken.requestedOrientation; - // If this application is fullscreen, then just take whatever - // orientation it has and ignores whatever is under it. - if (wtoken.appFullscreen) { - return or; - } - // If this application has requested an explicit orientation, - // then use it. - if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || - or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || - or == ActivityInfo.SCREEN_ORIENTATION_SENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR || - or == ActivityInfo.SCREEN_ORIENTATION_USER) { - 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; - //send a message to Policy indicating orientation change to take - //action like disabling/enabling sensors etc., - mPolicy.setCurrentOrientation(req); - } - - if (changed) { - changed = setRotationUncheckedLocked( - WindowManagerPolicy.USE_LAST_ROTATION); - if (changed) { - if (freezeThisOneIfNeeded != null) { - AppWindowToken wtoken = findAppWindowToken( - freezeThisOneIfNeeded); - if (wtoken != null) { - startAppFreezingScreenLocked(wtoken, - ActivityInfo.CONFIG_ORIENTATION); - } - } - return computeNewConfiguration(); - } - } - } finally { - Binder.restoreCallingIdentity(ident); - } - - return null; - } - - public void setAppOrientation(IApplicationToken token, int requestedOrientation) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppOrientation()")) { - return; - } - - synchronized(mWindowMap) { - AppWindowToken wtoken = findAppWindowToken(token.asBinder()); - if (wtoken == null) { - Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token); - return; - } - - wtoken.requestedOrientation = requestedOrientation; - } - } - - public int getAppOrientation(IApplicationToken token) { - synchronized(mWindowMap) { - AppWindowToken wtoken = findAppWindowToken(token.asBinder()); - if (wtoken == null) { - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - } - - return wtoken.requestedOrientation; - } - } - - public void setFocusedApp(IBinder token, boolean moveFocusNow) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setFocusedApp()")) { - return; - } - - synchronized(mWindowMap) { - boolean changed = false; - if (token == null) { - if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp); - changed = mFocusedApp != null; - mFocusedApp = null; - mKeyWaiter.tickle(); - } else { - AppWindowToken newFocus = findAppWindowToken(token); - if (newFocus == null) { - Log.w(TAG, "Attempted to set focus to non-existing app token: " + token); - return; - } - changed = mFocusedApp != newFocus; - mFocusedApp = newFocus; - if (DEBUG_FOCUS) Log.v(TAG, "Set focused app to: " + mFocusedApp); - mKeyWaiter.tickle(); - } - - if (moveFocusNow && changed) { - final long origId = Binder.clearCallingIdentity(); - updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); - Binder.restoreCallingIdentity(origId); - } - } - } - - public void prepareAppTransition(int transit) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "prepareAppTransition()")) { - return; - } - - synchronized(mWindowMap) { - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Prepare app transition: transit=" + transit - + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen) { - if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { - mNextAppTransition = transit; - } - mAppTransitionReady = false; - mAppTransitionTimeout = false; - mStartingIconInTransition = false; - mSkipAppTransitionAnimation = false; - mH.removeMessages(H.APP_TRANSITION_TIMEOUT); - mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT), - 5000); - } - } - } - - public int getPendingAppTransition() { - return mNextAppTransition; - } - - public void executeAppTransition() { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "executeAppTransition()")) { - return; - } - - synchronized(mWindowMap) { - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition); - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { - mAppTransitionReady = true; - final long origId = Binder.clearCallingIdentity(); - performLayoutAndPlaceSurfacesLocked(); - Binder.restoreCallingIdentity(origId); - } - } - } - - public void setAppStartingWindow(IBinder token, String pkg, - int theme, CharSequence nonLocalizedLabel, int labelRes, int icon, - IBinder transferFrom, boolean createIfNeeded) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppStartingIcon()")) { - return; - } - - synchronized(mWindowMap) { - if (DEBUG_STARTING_WINDOW) Log.v( - TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg - + " transferFrom=" + transferFrom); - - AppWindowToken wtoken = findAppWindowToken(token); - if (wtoken == null) { - Log.w(TAG, "Attempted to set icon of non-existing app token: " + token); - return; - } - - // If the display is frozen, we won't do anything until the - // actual window is displayed so there is no reason to put in - // the starting window. - if (mDisplayFrozen) { - return; - } - - if (wtoken.startingData != null) { - return; - } - - if (transferFrom != null) { - AppWindowToken ttoken = findAppWindowToken(transferFrom); - if (ttoken != null) { - WindowState startingWindow = ttoken.startingWindow; - if (startingWindow != null) { - if (mStartingIconInTransition) { - // In this case, the starting icon has already - // been displayed, so start letting windows get - // shown immediately without any more transitions. - mSkipAppTransitionAnimation = true; - } - if (DEBUG_STARTING_WINDOW) Log.v(TAG, - "Moving existing starting from " + ttoken - + " to " + wtoken); - final long origId = Binder.clearCallingIdentity(); - - // Transfer the starting window over to the new - // token. - wtoken.startingData = ttoken.startingData; - wtoken.startingView = ttoken.startingView; - wtoken.startingWindow = startingWindow; - ttoken.startingData = null; - ttoken.startingView = null; - ttoken.startingWindow = null; - ttoken.startingMoved = true; - startingWindow.mToken = wtoken; - startingWindow.mAppToken = wtoken; - mWindows.remove(startingWindow); - ttoken.windows.remove(startingWindow); - ttoken.allAppWindows.remove(startingWindow); - addWindowToListInOrderLocked(startingWindow, true); - wtoken.allAppWindows.add(startingWindow); - - // Propagate other interesting state between the - // tokens. If the old token is displayed, we should - // immediately force the new one to be displayed. If - // it is animating, we need to move that animation to - // the new one. - if (ttoken.allDrawn) { - wtoken.allDrawn = true; - } - if (ttoken.firstWindowDrawn) { - wtoken.firstWindowDrawn = true; - } - if (!ttoken.hidden) { - wtoken.hidden = false; - wtoken.hiddenRequested = false; - wtoken.willBeHidden = false; - } - if (wtoken.clientHidden != ttoken.clientHidden) { - wtoken.clientHidden = ttoken.clientHidden; - wtoken.sendAppVisibilityToClients(); - } - if (ttoken.animation != null) { - wtoken.animation = ttoken.animation; - wtoken.animating = ttoken.animating; - wtoken.animLayerAdjustment = ttoken.animLayerAdjustment; - ttoken.animation = null; - ttoken.animLayerAdjustment = 0; - wtoken.updateLayers(); - ttoken.updateLayers(); - } - - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); - assignLayersLocked(); - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - Binder.restoreCallingIdentity(origId); - return; - } else if (ttoken.startingData != null) { - // The previous app was getting ready to show a - // starting window, but hasn't yet done so. Steal it! - if (DEBUG_STARTING_WINDOW) Log.v(TAG, - "Moving pending starting from " + ttoken - + " to " + wtoken); - wtoken.startingData = ttoken.startingData; - ttoken.startingData = null; - ttoken.startingMoved = true; - Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); - // Note: we really want to do sendMessageAtFrontOfQueue() because we - // want to process the message ASAP, before any other queued - // messages. - mH.sendMessageAtFrontOfQueue(m); - return; - } - } - } - - // There is no existing starting window, and the caller doesn't - // want us to create one, so that's it! - if (!createIfNeeded) { - return; - } - - mStartingIconInTransition = true; - wtoken.startingData = new StartingData( - pkg, theme, nonLocalizedLabel, - labelRes, icon); - Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); - // Note: we really want to do sendMessageAtFrontOfQueue() because we - // want to process the message ASAP, before any other queued - // messages. - mH.sendMessageAtFrontOfQueue(m); - } - } - - public void setAppWillBeHidden(IBinder token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppWillBeHidden()")) { - return; - } - - AppWindowToken wtoken; - - synchronized(mWindowMap) { - wtoken = findAppWindowToken(token); - if (wtoken == null) { - Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token); - return; - } - wtoken.willBeHidden = true; - } - } - - boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp, - boolean visible, int transit, boolean performLayout) { - boolean delayed = false; - - if (wtoken.clientHidden == visible) { - wtoken.clientHidden = !visible; - wtoken.sendAppVisibilityToClients(); - } - - wtoken.willBeHidden = false; - if (wtoken.hidden == visible) { - final int N = wtoken.allAppWindows.size(); - boolean changed = false; - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden - + " performLayout=" + performLayout); - - boolean runningAppAnimation = false; - - if (transit != WindowManagerPolicy.TRANSIT_NONE) { - if (wtoken.animation == sDummyAnimation) { - wtoken.animation = null; - } - applyAnimationLocked(wtoken, lp, transit, visible); - changed = true; - if (wtoken.animation != null) { - delayed = runningAppAnimation = true; - } - } - - for (int i=0; i<N; i++) { - WindowState win = wtoken.allAppWindows.get(i); - if (win == wtoken.startingWindow) { - continue; - } - - if (win.isAnimating()) { - delayed = true; - } - - //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible()); - //win.dump(" "); - if (visible) { - if (!win.isVisibleNow()) { - if (!runningAppAnimation) { - applyAnimationLocked(win, - WindowManagerPolicy.TRANSIT_ENTER, true); - } - changed = true; - } - } else if (win.isVisibleNow()) { - if (!runningAppAnimation) { - applyAnimationLocked(win, - WindowManagerPolicy.TRANSIT_EXIT, false); - } - mKeyWaiter.finishedKey(win.mSession, win.mClient, true, - KeyWaiter.RETURN_NOTHING); - changed = true; - } - } - - wtoken.hidden = wtoken.hiddenRequested = !visible; - if (!visible) { - unsetAppFreezingScreenLocked(wtoken, true, true); - } else { - // If we are being set visible, and the starting window is - // not yet displayed, then make sure it doesn't get displayed. - WindowState swin = wtoken.startingWindow; - if (swin != null && (swin.mDrawPending - || swin.mCommitDrawPending)) { - swin.mPolicyVisibility = false; - swin.mPolicyVisibilityAfterAnim = false; - } - } - - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken - + ": hidden=" + wtoken.hidden + " hiddenRequested=" - + wtoken.hiddenRequested); - - if (changed && performLayout) { - mLayoutNeeded = true; - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); - assignLayersLocked(); - performLayoutAndPlaceSurfacesLocked(); - } - } - - if (wtoken.animation != null) { - delayed = true; - } - - return delayed; - } - - public void setAppVisibility(IBinder token, boolean visible) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppVisibility()")) { - return; - } - - AppWindowToken wtoken; - - synchronized(mWindowMap) { - wtoken = findAppWindowToken(token); - if (wtoken == null) { - Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token); - return; - } - - if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.v(TAG, "setAppVisibility(" + token + ", " + visible - + "): mNextAppTransition=" + mNextAppTransition - + " hidden=" + wtoken.hidden - + " hiddenRequested=" + wtoken.hiddenRequested, e); - } - - // If we are preparing an app transition, then delay changing - // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { - // Already in requested state, don't do anything more. - if (wtoken.hiddenRequested != visible) { - return; - } - wtoken.hiddenRequested = !visible; - - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Setting dummy animation on: " + wtoken); - wtoken.setDummyAnimation(); - mOpeningApps.remove(wtoken); - mClosingApps.remove(wtoken); - wtoken.inPendingTransaction = true; - if (visible) { - mOpeningApps.add(wtoken); - wtoken.allDrawn = false; - wtoken.startingDisplayed = false; - wtoken.startingMoved = false; - - if (wtoken.clientHidden) { - // In the case where we are making an app visible - // but holding off for a transition, we still need - // to tell the client to make its windows visible so - // they get drawn. Otherwise, we will wait on - // performing the transition until all windows have - // been drawn, they never will be, and we are sad. - wtoken.clientHidden = false; - wtoken.sendAppVisibilityToClients(); - } - } else { - mClosingApps.add(wtoken); - } - return; - } - - final long origId = Binder.clearCallingIdentity(); - setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true); - wtoken.updateReportedVisibilityLocked(); - Binder.restoreCallingIdentity(origId); - } - } - - void unsetAppFreezingScreenLocked(AppWindowToken wtoken, - boolean unfreezeSurfaceNow, boolean force) { - if (wtoken.freezingScreen) { - if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken - + " force=" + force); - final int N = wtoken.allAppWindows.size(); - boolean unfrozeWindows = false; - for (int i=0; i<N; i++) { - WindowState w = wtoken.allAppWindows.get(i); - if (w.mAppFreezing) { - w.mAppFreezing = false; - if (w.mSurface != null && !w.mOrientationChanging) { - w.mOrientationChanging = true; - } - unfrozeWindows = true; - } - } - if (force || unfrozeWindows) { - if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken); - wtoken.freezingScreen = false; - mAppsFreezingScreen--; - } - if (unfreezeSurfaceNow) { - if (unfrozeWindows) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) { - stopFreezingDisplayLocked(); - } - } - } - } - - public void startAppFreezingScreenLocked(AppWindowToken wtoken, - int configChanges) { - if (DEBUG_ORIENTATION) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.i(TAG, "Set freezing of " + wtoken.appToken - + ": hidden=" + wtoken.hidden + " freezing=" - + wtoken.freezingScreen, e); - } - if (!wtoken.hiddenRequested) { - if (!wtoken.freezingScreen) { - wtoken.freezingScreen = true; - mAppsFreezingScreen++; - if (mAppsFreezingScreen == 1) { - startFreezingDisplayLocked(); - mH.removeMessages(H.APP_FREEZE_TIMEOUT); - mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT), - 5000); - } - } - final int N = wtoken.allAppWindows.size(); - for (int i=0; i<N; i++) { - WindowState w = wtoken.allAppWindows.get(i); - w.mAppFreezing = true; - } - } - } - - public void startAppFreezingScreen(IBinder token, int configChanges) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppFreezingScreen()")) { - return; - } - - synchronized(mWindowMap) { - if (configChanges == 0 && !mDisplayFrozen) { - if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token); - return; - } - - AppWindowToken wtoken = findAppWindowToken(token); - if (wtoken == null || wtoken.appToken == null) { - Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken); - return; - } - final long origId = Binder.clearCallingIdentity(); - startAppFreezingScreenLocked(wtoken, configChanges); - Binder.restoreCallingIdentity(origId); - } - } - - public void stopAppFreezingScreen(IBinder token, boolean force) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppFreezingScreen()")) { - return; - } - - synchronized(mWindowMap) { - AppWindowToken wtoken = findAppWindowToken(token); - if (wtoken == null || wtoken.appToken == null) { - return; - } - final long origId = Binder.clearCallingIdentity(); - if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token - + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen); - unsetAppFreezingScreenLocked(wtoken, true, force); - Binder.restoreCallingIdentity(origId); - } - } - - public void removeAppToken(IBinder token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "removeAppToken()")) { - return; - } - - AppWindowToken wtoken = null; - AppWindowToken startingToken = null; - boolean delayed = false; - - final long origId = Binder.clearCallingIdentity(); - synchronized(mWindowMap) { - WindowToken basewtoken = mTokenMap.remove(token); - mTokenList.remove(basewtoken); - if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) { - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken); - delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true); - wtoken.inPendingTransaction = false; - mOpeningApps.remove(wtoken); - if (mClosingApps.contains(wtoken)) { - delayed = true; - } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { - mClosingApps.add(wtoken); - delayed = true; - } - if (DEBUG_APP_TRANSITIONS) Log.v( - TAG, "Removing app " + wtoken + " delayed=" + delayed - + " animation=" + wtoken.animation - + " animating=" + wtoken.animating); - if (delayed) { - // set the token aside because it has an active animation to be finished - mExitingAppTokens.add(wtoken); - } - mAppTokens.remove(wtoken); - wtoken.removed = true; - if (wtoken.startingData != null) { - startingToken = wtoken; - } - unsetAppFreezingScreenLocked(wtoken, true, true); - if (mFocusedApp == wtoken) { - if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken); - mFocusedApp = null; - updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); - mKeyWaiter.tickle(); - } - } else { - Log.w(TAG, "Attempted to remove non-existing app token: " + token); - } - - if (!delayed && wtoken != null) { - wtoken.updateReportedVisibilityLocked(); - } - } - Binder.restoreCallingIdentity(origId); - - if (startingToken != null) { - if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting " - + startingToken + ": app token removed"); - Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken); - mH.sendMessage(m); - } - } - - private boolean tmpRemoveAppWindowsLocked(WindowToken token) { - final int NW = token.windows.size(); - for (int i=0; i<NW; i++) { - WindowState win = token.windows.get(i); - mWindows.remove(win); - int j = win.mChildWindows.size(); - while (j > 0) { - j--; - mWindows.remove(win.mChildWindows.get(j)); - } - } - return NW > 0; - } - - void dumpAppTokensLocked() { - for (int i=mAppTokens.size()-1; i>=0; i--) { - Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token); - } - } - - void dumpWindowsLocked() { - for (int i=mWindows.size()-1; i>=0; i--) { - Log.v(TAG, " #" + i + ": " + mWindows.get(i)); - } - } - - private int findWindowOffsetLocked(int tokenPos) { - final int NW = mWindows.size(); - - if (tokenPos >= mAppTokens.size()) { - int i = NW; - while (i > 0) { - i--; - WindowState win = (WindowState)mWindows.get(i); - if (win.getAppToken() != null) { - return i+1; - } - } - } - - while (tokenPos > 0) { - // Find the first app token below the new position that has - // a window displayed. - final AppWindowToken wtoken = mAppTokens.get(tokenPos-1); - if (DEBUG_REORDER) Log.v(TAG, "Looking for lower windows @ " - + tokenPos + " -- " + wtoken.token); - int i = wtoken.windows.size(); - while (i > 0) { - i--; - WindowState win = wtoken.windows.get(i); - int j = win.mChildWindows.size(); - while (j > 0) { - j--; - WindowState cwin = (WindowState)win.mChildWindows.get(j); - if (cwin.mSubLayer >= 0 ) { - for (int pos=NW-1; pos>=0; pos--) { - if (mWindows.get(pos) == cwin) { - if (DEBUG_REORDER) Log.v(TAG, - "Found child win @" + (pos+1)); - return pos+1; - } - } - } - } - for (int pos=NW-1; pos>=0; pos--) { - if (mWindows.get(pos) == win) { - if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1)); - return pos+1; - } - } - } - tokenPos--; - } - - return 0; - } - - private final int reAddWindowLocked(int index, WindowState win) { - final int NCW = win.mChildWindows.size(); - boolean added = false; - for (int j=0; j<NCW; j++) { - WindowState cwin = (WindowState)win.mChildWindows.get(j); - if (!added && cwin.mSubLayer >= 0) { - mWindows.add(index, win); - index++; - added = true; - } - mWindows.add(index, cwin); - index++; - } - if (!added) { - mWindows.add(index, win); - index++; - } - return index; - } - - private final int reAddAppWindowsLocked(int index, WindowToken token) { - final int NW = token.windows.size(); - for (int i=0; i<NW; i++) { - index = reAddWindowLocked(index, token.windows.get(i)); - } - return index; - } - - public void moveAppToken(int index, IBinder token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "moveAppToken()")) { - return; - } - - synchronized(mWindowMap) { - if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:"); - if (DEBUG_REORDER) dumpAppTokensLocked(); - final AppWindowToken wtoken = findAppWindowToken(token); - if (wtoken == null || !mAppTokens.remove(wtoken)) { - Log.w(TAG, "Attempting to reorder token that doesn't exist: " - + token + " (" + wtoken + ")"); - return; - } - mAppTokens.add(index, wtoken); - if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":"); - if (DEBUG_REORDER) dumpAppTokensLocked(); - - final long origId = Binder.clearCallingIdentity(); - if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":"); - if (DEBUG_REORDER) dumpWindowsLocked(); - if (tmpRemoveAppWindowsLocked(wtoken)) { - if (DEBUG_REORDER) Log.v(TAG, "Adding windows back in:"); - if (DEBUG_REORDER) dumpWindowsLocked(); - reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken); - if (DEBUG_REORDER) Log.v(TAG, "Final window list:"); - if (DEBUG_REORDER) dumpWindowsLocked(); - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); - assignLayersLocked(); - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - Binder.restoreCallingIdentity(origId); - } - } - - private void removeAppTokensLocked(List<IBinder> tokens) { - // XXX This should be done more efficiently! - // (take advantage of the fact that both lists should be - // ordered in the same way.) - int N = tokens.size(); - for (int i=0; i<N; i++) { - IBinder token = tokens.get(i); - final AppWindowToken wtoken = findAppWindowToken(token); - if (!mAppTokens.remove(wtoken)) { - Log.w(TAG, "Attempting to reorder token that doesn't exist: " - + token + " (" + wtoken + ")"); - i--; - N--; - } - } - } - - private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) { - // First remove all of the windows from the list. - final int N = tokens.size(); - int i; - for (i=0; i<N; i++) { - WindowToken token = mTokenMap.get(tokens.get(i)); - if (token != null) { - tmpRemoveAppWindowsLocked(token); - } - } - - // Where to start adding? - int pos = findWindowOffsetLocked(tokenPos); - - // And now add them back at the correct place. - for (i=0; i<N; i++) { - WindowToken token = mTokenMap.get(tokens.get(i)); - if (token != null) { - pos = reAddAppWindowsLocked(pos, token); - } - } - - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); - assignLayersLocked(); - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - - //dump(); - } - - public void moveAppTokensToTop(List<IBinder> tokens) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "moveAppTokensToTop()")) { - return; - } - - final long origId = Binder.clearCallingIdentity(); - synchronized(mWindowMap) { - removeAppTokensLocked(tokens); - final int N = tokens.size(); - for (int i=0; i<N; i++) { - AppWindowToken wt = findAppWindowToken(tokens.get(i)); - if (wt != null) { - mAppTokens.add(wt); - } - } - moveAppWindowsLocked(tokens, mAppTokens.size()); - } - Binder.restoreCallingIdentity(origId); - } - - public void moveAppTokensToBottom(List<IBinder> tokens) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "moveAppTokensToBottom()")) { - return; - } - - final long origId = Binder.clearCallingIdentity(); - synchronized(mWindowMap) { - removeAppTokensLocked(tokens); - final int N = tokens.size(); - int pos = 0; - for (int i=0; i<N; i++) { - AppWindowToken wt = findAppWindowToken(tokens.get(i)); - if (wt != null) { - mAppTokens.add(pos, wt); - pos++; - } - } - moveAppWindowsLocked(tokens, 0); - } - Binder.restoreCallingIdentity(origId); - } - - // ------------------------------------------------------------- - // Misc IWindowSession methods - // ------------------------------------------------------------- - - public void disableKeyguard(IBinder token, String tag) { - if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires DISABLE_KEYGUARD permission"); - } - mKeyguardDisabled.acquire(token, tag); - } - - public void reenableKeyguard(IBinder token) { - if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires DISABLE_KEYGUARD permission"); - } - synchronized (mKeyguardDisabled) { - mKeyguardDisabled.release(token); - - if (!mKeyguardDisabled.isAcquired()) { - // if we are the last one to reenable the keyguard wait until - // we have actaully finished reenabling until returning - mWaitingUntilKeyguardReenabled = true; - while (mWaitingUntilKeyguardReenabled) { - try { - mKeyguardDisabled.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - } - - /** - * @see android.app.KeyguardManager#exitKeyguardSecurely - */ - public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) { - if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires DISABLE_KEYGUARD permission"); - } - mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() { - public void onKeyguardExitResult(boolean success) { - try { - callback.onKeyguardExitResult(success); - } catch (RemoteException e) { - // Client has died, we don't care. - } - } - }); - } - - public boolean inKeyguardRestrictedInputMode() { - return mPolicy.inKeyguardRestrictedKeyInputMode(); - } - - static float fixScale(float scale) { - if (scale < 0) scale = 0; - else if (scale > 20) scale = 20; - return Math.abs(scale); - } - - public void setAnimationScale(int which, float scale) { - if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, - "setAnimationScale()")) { - return; - } - - if (scale < 0) scale = 0; - else if (scale > 20) scale = 20; - scale = Math.abs(scale); - switch (which) { - case 0: mWindowAnimationScale = fixScale(scale); break; - case 1: mTransitionAnimationScale = fixScale(scale); break; - } - - // Persist setting - mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget(); - } - - public void setAnimationScales(float[] scales) { - if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, - "setAnimationScale()")) { - return; - } - - if (scales != null) { - if (scales.length >= 1) { - mWindowAnimationScale = fixScale(scales[0]); - } - if (scales.length >= 2) { - mTransitionAnimationScale = fixScale(scales[1]); - } - } - - // Persist setting - mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget(); - } - - public float getAnimationScale(int which) { - switch (which) { - case 0: return mWindowAnimationScale; - case 1: return mTransitionAnimationScale; - } - return 0; - } - - public float[] getAnimationScales() { - return new float[] { mWindowAnimationScale, mTransitionAnimationScale }; - } - - public int getSwitchState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getSwitchState()")) { - return -1; - } - return KeyInputQueue.getSwitchState(sw); - } - - public int getSwitchStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getSwitchStateForDevice()")) { - return -1; - } - return KeyInputQueue.getSwitchState(devid, sw); - } - - public int getScancodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getScancodeState()")) { - return -1; - } - return KeyInputQueue.getScancodeState(sw); - } - - public int getScancodeStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getScancodeStateForDevice()")) { - return -1; - } - return KeyInputQueue.getScancodeState(devid, sw); - } - - public int getKeycodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getKeycodeState()")) { - return -1; - } - return KeyInputQueue.getKeycodeState(sw); - } - - public int getKeycodeStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getKeycodeStateForDevice()")) { - return -1; - } - return KeyInputQueue.getKeycodeState(devid, sw); - } - - public boolean hasKeys(int[] keycodes, boolean[] keyExists) { - return KeyInputQueue.hasKeys(keycodes, keyExists); - } - - public void enableScreenAfterBoot() { - synchronized(mWindowMap) { - if (mSystemBooted) { - return; - } - mSystemBooted = true; - } - - performEnableScreen(); - } - - public void enableScreenIfNeededLocked() { - if (mDisplayEnabled) { - return; - } - if (!mSystemBooted) { - return; - } - mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN)); - } - - public void performEnableScreen() { - synchronized(mWindowMap) { - if (mDisplayEnabled) { - return; - } - if (!mSystemBooted) { - return; - } - - // Don't enable the screen until all existing windows - // have been drawn. - final int N = mWindows.size(); - for (int i=0; i<N; i++) { - WindowState w = (WindowState)mWindows.get(i); - if (w.isVisibleLw() && !w.isDisplayedLw()) { - return; - } - } - - mDisplayEnabled = true; - if (false) { - Log.i(TAG, "ENABLING SCREEN!"); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - this.dump(null, pw, null); - Log.i(TAG, sw.toString()); - } - try { - IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); - if (surfaceFlinger != null) { - //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); - Parcel data = Parcel.obtain(); - data.writeInterfaceToken("android.ui.ISurfaceComposer"); - surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, - data, null, 0); - data.recycle(); - } - } catch (RemoteException ex) { - Log.e(TAG, "Boot completed: SurfaceFlinger is dead!"); - } - } - - mPolicy.enableScreenAfterBoot(); - - // Make sure the last requested orientation has been applied. - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false); - } - - public void setInTouchMode(boolean mode) { - synchronized(mWindowMap) { - mInTouchMode = mode; - } - } - - public void setRotation(int rotation, - boolean alwaysSendConfiguration) { - if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, - "setOrientation()")) { - return; - } - - setRotationUnchecked(rotation, alwaysSendConfiguration); - } - - public void setRotationUnchecked(int rotation, boolean alwaysSendConfiguration) { - if(DEBUG_ORIENTATION) Log.v(TAG, - "alwaysSendConfiguration set to "+alwaysSendConfiguration); - - long origId = Binder.clearCallingIdentity(); - boolean changed; - synchronized(mWindowMap) { - changed = setRotationUncheckedLocked(rotation); - } - - if (changed) { - sendNewConfiguration(); - synchronized(mWindowMap) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } else if (alwaysSendConfiguration) { - //update configuration ignoring orientation change - sendNewConfiguration(); - } - - Binder.restoreCallingIdentity(origId); - } - - public boolean setRotationUncheckedLocked(int rotation) { - boolean changed; - if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { - rotation = mRequestedRotation; - } else { - mRequestedRotation = 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) { - 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), - 2000); - startFreezingDisplayLocked(); - mQueue.setOrientation(rotation); - if (mDisplayEnabled) { - Surface.setOrientation(0, rotation); - } - for (int i=mWindows.size()-1; i>=0; i--) { - WindowState w = (WindowState)mWindows.get(i); - if (w.mSurface != null) { - w.mOrientationChanging = true; - } - } - for (int i=mRotationWatchers.size()-1; i>=0; i--) { - try { - mRotationWatchers.get(i).onRotationChanged(rotation); - } catch (RemoteException e) { - } - } - } //end if changed - - return changed; - } - - public int getRotation() { - return mRotation; - } - - public int watchRotation(IRotationWatcher watcher) { - final IBinder watcherBinder = watcher.asBinder(); - IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { - public void binderDied() { - synchronized (mWindowMap) { - for (int i=0; i<mRotationWatchers.size(); i++) { - if (watcherBinder == mRotationWatchers.get(i).asBinder()) { - mRotationWatchers.remove(i); - i--; - } - } - } - } - }; - - synchronized (mWindowMap) { - try { - watcher.asBinder().linkToDeath(dr, 0); - mRotationWatchers.add(watcher); - } catch (RemoteException e) { - // Client died, no cleanup needed. - } - - return mRotation; - } - } - - /** - * Starts the view server on the specified port. - * - * @param port The port to listener to. - * - * @return True if the server was successfully started, false otherwise. - * - * @see com.android.server.ViewServer - * @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT - */ - public boolean startViewServer(int port) { - if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) { - return false; - } - - if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) { - return false; - } - - if (port < 1024) { - return false; - } - - if (mViewServer != null) { - if (!mViewServer.isRunning()) { - try { - return mViewServer.start(); - } catch (IOException e) { - Log.w(TAG, "View server did not start"); - } - } - return false; - } - - try { - mViewServer = new ViewServer(this, port); - return mViewServer.start(); - } catch (IOException e) { - Log.w(TAG, "View server did not start"); - } - return false; - } - - /** - * Stops the view server if it exists. - * - * @return True if the server stopped, false if it wasn't started or - * couldn't be stopped. - * - * @see com.android.server.ViewServer - */ - public boolean stopViewServer() { - if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) { - return false; - } - - if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) { - return false; - } - - if (mViewServer != null) { - return mViewServer.stop(); - } - return false; - } - - /** - * Indicates whether the view server is running. - * - * @return True if the server is running, false otherwise. - * - * @see com.android.server.ViewServer - */ - public boolean isViewServerRunning() { - if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) { - return false; - } - - if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) { - return false; - } - - return mViewServer != null && mViewServer.isRunning(); - } - - /** - * Lists all availble windows in the system. The listing is written in the - * specified Socket's output stream with the following syntax: - * windowHashCodeInHexadecimal windowName - * Each line of the ouput represents a different window. - * - * @param client The remote client to send the listing to. - * @return False if an error occured, true otherwise. - */ - boolean viewServerListWindows(Socket client) { - if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) { - return false; - } - - boolean result = true; - - Object[] windows; - synchronized (mWindowMap) { - windows = new Object[mWindows.size()]; - //noinspection unchecked - windows = mWindows.toArray(windows); - } - - BufferedWriter out = null; - - // Any uncaught exception will crash the system process - try { - OutputStream clientStream = client.getOutputStream(); - out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); - - final int count = windows.length; - for (int i = 0; i < count; i++) { - final WindowState w = (WindowState) windows[i]; - out.write(Integer.toHexString(System.identityHashCode(w))); - out.write(' '); - out.append(w.mAttrs.getTitle()); - out.write('\n'); - } - - out.write("DONE.\n"); - out.flush(); - } catch (Exception e) { - result = false; - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - result = false; - } - } - } - - return result; - } - - /** - * Sends a command to a target window. The result of the command, if any, will be - * written in the output stream of the specified socket. - * - * The parameters must follow this syntax: - * windowHashcode extra - * - * Where XX is the length in characeters of the windowTitle. - * - * The first parameter is the target window. The window with the specified hashcode - * will be the target. If no target can be found, nothing happens. The extra parameters - * will be delivered to the target window and as parameters to the command itself. - * - * @param client The remote client to sent the result, if any, to. - * @param command The command to execute. - * @param parameters The command parameters. - * - * @return True if the command was successfully delivered, false otherwise. This does - * not indicate whether the command itself was successful. - */ - boolean viewServerWindowCommand(Socket client, String command, String parameters) { - if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) { - return false; - } - - boolean success = true; - Parcel data = null; - Parcel reply = null; - - // Any uncaught exception will crash the system process - try { - // Find the hashcode of the window - int index = parameters.indexOf(' '); - if (index == -1) { - index = parameters.length(); - } - final String code = parameters.substring(0, index); - int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16); - - // Extract the command's parameter after the window description - if (index < parameters.length()) { - parameters = parameters.substring(index + 1); - } else { - parameters = ""; - } - - final WindowManagerService.WindowState window = findWindow(hashCode); - if (window == null) { - return false; - } - - data = Parcel.obtain(); - data.writeInterfaceToken("android.view.IWindow"); - data.writeString(command); - data.writeString(parameters); - data.writeInt(1); - ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0); - - reply = Parcel.obtain(); - - final IBinder binder = window.mClient.asBinder(); - // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER - binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); - - reply.readException(); - - } catch (Exception e) { - Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e); - success = false; - } finally { - if (data != null) { - data.recycle(); - } - if (reply != null) { - reply.recycle(); - } - } - - return success; - } - - private WindowState findWindow(int hashCode) { - if (hashCode == -1) { - return getFocusedWindow(); - } - - synchronized (mWindowMap) { - final ArrayList windows = mWindows; - final int count = windows.size(); - - for (int i = 0; i < count; i++) { - WindowState w = (WindowState) windows.get(i); - if (System.identityHashCode(w) == hashCode) { - return w; - } - } - } - - return null; - } - - /* - * Instruct the Activity Manager to fetch the current configuration and broadcast - * that to config-changed listeners if appropriate. - */ - void sendNewConfiguration() { - try { - mActivityManager.updateConfiguration(null); - } catch (RemoteException e) { - } - } - - public Configuration computeNewConfiguration() { - synchronized (mWindowMap) { - if (mDisplay == null) { - return null; - } - Configuration config = new Configuration(); - mQueue.getInputConfiguration(config); - final int dw = mDisplay.getWidth(); - final int dh = mDisplay.getHeight(); - int orientation = Configuration.ORIENTATION_SQUARE; - if (dw < dh) { - orientation = Configuration.ORIENTATION_PORTRAIT; - } else if (dw > dh) { - orientation = Configuration.ORIENTATION_LANDSCAPE; - } - config.orientation = orientation; - config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; - config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; - mPolicy.adjustConfigurationLw(config); - Log.i(TAG, "Input configuration changed: " + config); - long now = SystemClock.uptimeMillis(); - //Log.i(TAG, "Config changing, gc pending: " + mFreezeGcPending + ", now " + now); - if (mFreezeGcPending != 0) { - if (now > (mFreezeGcPending+1000)) { - //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000)); - mH.removeMessages(H.FORCE_GC); - Runtime.getRuntime().gc(); - mFreezeGcPending = now; - } - } else { - mFreezeGcPending = now; - } - return config; - } - } - - // ------------------------------------------------------------- - // Input Events and Focus Management - // ------------------------------------------------------------- - - private final void wakeupIfNeeded(WindowState targetWin, int eventType) { - if (targetWin == null || - targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), false, eventType); - } - } - - // tells if it's a cheek event or not -- this function is stateful - private static final int EVENT_NONE = 0; - private static final int EVENT_UNKNOWN = 0; - private static final int EVENT_CHEEK = 0; - private static final int EVENT_IGNORE_DURATION = 300; // ms - private static final float CHEEK_THRESHOLD = 0.6f; - private int mEventState = EVENT_NONE; - private float mEventSize; - private int eventType(MotionEvent ev) { - float size = ev.getSize(); - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - mEventSize = size; - return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT; - case MotionEvent.ACTION_UP: - if (size > mEventSize) mEventSize = size; - return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : OTHER_EVENT; - case MotionEvent.ACTION_MOVE: - final int N = ev.getHistorySize(); - if (size > mEventSize) mEventSize = size; - if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT; - for (int i=0; i<N; i++) { - size = ev.getHistoricalSize(i); - if (size > mEventSize) mEventSize = size; - if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT; - } - if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) { - return TOUCH_EVENT; - } else { - return OTHER_EVENT; - } - default: - // not good - return OTHER_EVENT; - } - } - - /** - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - private boolean dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) { - if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG, - "dispatchPointer " + ev); - - Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev, - ev, true, false); - - int action = ev.getAction(); - - if (action == MotionEvent.ACTION_UP) { - // let go of our target - mKeyWaiter.mMotionTarget = null; - mPowerManager.logPointerUpEvent(); - } else if (action == MotionEvent.ACTION_DOWN) { - mPowerManager.logPointerDownEvent(); - } - - if (targetObj == null) { - // In this case we are either dropping the event, or have received - // a move or up without a down. It is common to receive move - // events in such a way, since this means the user is moving the - // pointer without actually pressing down. All other cases should - // be atypical, so let's log them. - if (ev.getAction() != MotionEvent.ACTION_MOVE) { - Log.w(TAG, "No window to dispatch pointer action " + ev.getAction()); - } - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return false; - } - if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) { - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return true; - } - - WindowState target = (WindowState)targetObj; - - final long eventTime = ev.getEventTime(); - - //Log.i(TAG, "Sending " + ev + " to " + target); - - if (uid != 0 && uid != target.mSession.mUid) { - if (mContext.checkPermission( - android.Manifest.permission.INJECT_EVENTS, pid, uid) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission denied: injecting pointer event from pid " - + pid + " uid " + uid + " to window " + target - + " owned by uid " + target.mSession.mUid); - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return false; - } - } - - if ((target.mAttrs.flags & - WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) { - //target wants to ignore fat touch events - boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev); - //explicit flag to return without processing event further - boolean returnFlag = false; - if((action == MotionEvent.ACTION_DOWN)) { - mFatTouch = false; - if(cheekPress) { - mFatTouch = true; - returnFlag = true; - } - } else { - if(action == MotionEvent.ACTION_UP) { - if(mFatTouch) { - //earlier even was invalid doesnt matter if current up is cheekpress or not - mFatTouch = false; - returnFlag = true; - } else if(cheekPress) { - //cancel the earlier event - ev.setAction(MotionEvent.ACTION_CANCEL); - action = MotionEvent.ACTION_CANCEL; - } - } else if(action == MotionEvent.ACTION_MOVE) { - if(mFatTouch) { - //two cases here - //an invalid down followed by 0 or moves(valid or invalid) - //a valid down, invalid move, more moves. want to ignore till up - returnFlag = true; - } else if(cheekPress) { - //valid down followed by invalid moves - //an invalid move have to cancel earlier action - ev.setAction(MotionEvent.ACTION_CANCEL); - action = MotionEvent.ACTION_CANCEL; - if (DEBUG_INPUT) Log.v(TAG, "Sending cancel for invalid ACTION_MOVE"); - //note that the subsequent invalid moves will not get here - mFatTouch = true; - } - } - } //else if action - if(returnFlag) { - //recycle que, ev - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return false; - } - } //end if target - - synchronized(mWindowMap) { - if (qev != null && action == MotionEvent.ACTION_MOVE) { - mKeyWaiter.bindTargetWindowLocked(target, - KeyWaiter.RETURN_PENDING_POINTER, qev); - ev = null; - } else { - if (action == MotionEvent.ACTION_DOWN) { - WindowState out = mKeyWaiter.mOutsideTouchTargets; - if (out != null) { - MotionEvent oev = MotionEvent.obtain(ev); - oev.setAction(MotionEvent.ACTION_OUTSIDE); - do { - final Rect frame = out.mFrame; - oev.offsetLocation(-(float)frame.left, -(float)frame.top); - try { - out.mClient.dispatchPointer(oev, eventTime); - } catch (android.os.RemoteException e) { - Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out); - } - oev.offsetLocation((float)frame.left, (float)frame.top); - out = out.mNextOutsideTouch; - } while (out != null); - mKeyWaiter.mOutsideTouchTargets = null; - } - } - final Rect frame = target.mFrame; - ev.offsetLocation(-(float)frame.left, -(float)frame.top); - mKeyWaiter.bindTargetWindowLocked(target); - } - } - - // finally offset the event to the target's coordinate system and - // dispatch the event. - try { - if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) { - Log.v(TAG, "Delivering pointer " + qev + " to " + target); - } - target.mClient.dispatchPointer(ev, eventTime); - return true; - } catch (android.os.RemoteException e) { - Log.i(TAG, "WINDOW DIED during motion dispatch: " + target); - mKeyWaiter.mMotionTarget = null; - try { - removeWindow(target.mSession, target.mClient); - } catch (java.util.NoSuchElementException ex) { - // This will happen if the window has already been - // removed. - } - } - return false; - } - - /** - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - private boolean dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) { - if (DEBUG_INPUT) Log.v( - TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">"); - - Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev, - ev, false, false); - if (focusObj == null) { - Log.w(TAG, "No focus window, dropping trackball: " + ev); - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return false; - } - if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) { - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return true; - } - - WindowState focus = (WindowState)focusObj; - - if (uid != 0 && uid != focus.mSession.mUid) { - if (mContext.checkPermission( - android.Manifest.permission.INJECT_EVENTS, pid, uid) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission denied: injecting key event from pid " - + pid + " uid " + uid + " to window " + focus - + " owned by uid " + focus.mSession.mUid); - if (qev != null) { - mQueue.recycleEvent(qev); - } - ev.recycle(); - return false; - } - } - - final long eventTime = ev.getEventTime(); - - synchronized(mWindowMap) { - if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) { - mKeyWaiter.bindTargetWindowLocked(focus, - KeyWaiter.RETURN_PENDING_TRACKBALL, qev); - // We don't deliver movement events to the client, we hold - // them and wait for them to call back. - ev = null; - } else { - mKeyWaiter.bindTargetWindowLocked(focus); - } - } - - try { - focus.mClient.dispatchTrackball(ev, eventTime); - return true; - } catch (android.os.RemoteException e) { - Log.i(TAG, "WINDOW DIED during key dispatch: " + focus); - try { - removeWindow(focus.mSession, focus.mClient); - } catch (java.util.NoSuchElementException ex) { - // This will happen if the window has already been - // removed. - } - } - - return false; - } - - /** - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - private boolean dispatchKey(KeyEvent event, int pid, int uid) { - if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event); - - Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null, - null, false, false); - if (focusObj == null) { - Log.w(TAG, "No focus window, dropping: " + event); - return false; - } - if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) { - return true; - } - - WindowState focus = (WindowState)focusObj; - - if (DEBUG_INPUT) Log.v( - TAG, "Dispatching to " + focus + ": " + event); - - if (uid != 0 && uid != focus.mSession.mUid) { - if (mContext.checkPermission( - android.Manifest.permission.INJECT_EVENTS, pid, uid) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission denied: injecting key event from pid " - + pid + " uid " + uid + " to window " + focus - + " owned by uid " + focus.mSession.mUid); - return false; - } - } - - synchronized(mWindowMap) { - mKeyWaiter.bindTargetWindowLocked(focus); - } - - try { - if (DEBUG_INPUT || DEBUG_FOCUS) { - Log.v(TAG, "Delivering key " + event.getKeyCode() - + " to " + focus); - } - focus.mClient.dispatchKey(event); - return true; - } catch (android.os.RemoteException e) { - Log.i(TAG, "WINDOW DIED during key dispatch: " + focus); - try { - removeWindow(focus.mSession, focus.mClient); - } catch (java.util.NoSuchElementException ex) { - // This will happen if the window has already been - // removed. - } - } - - return false; - } - - public void pauseKeyDispatching(IBinder _token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "pauseKeyDispatching()")) { - return; - } - - synchronized (mWindowMap) { - WindowToken token = mTokenMap.get(_token); - if (token != null) { - mKeyWaiter.pauseDispatchingLocked(token); - } - } - } - - public void resumeKeyDispatching(IBinder _token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "resumeKeyDispatching()")) { - return; - } - - synchronized (mWindowMap) { - WindowToken token = mTokenMap.get(_token); - if (token != null) { - mKeyWaiter.resumeDispatchingLocked(token); - } - } - } - - public void setEventDispatching(boolean enabled) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "resumeKeyDispatching()")) { - return; - } - - synchronized (mWindowMap) { - mKeyWaiter.setEventDispatchingLocked(enabled); - } - } - - /** - * Injects a keystroke event into the UI. - * - * @param ev A motion event describing the keystroke action. (Be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectKeyEvent(KeyEvent ev, boolean sync) { - long downTime = ev.getDownTime(); - long eventTime = ev.getEventTime(); - - int action = ev.getAction(); - int code = ev.getKeyCode(); - int repeatCount = ev.getRepeatCount(); - int metaState = ev.getMetaState(); - int deviceId = ev.getDeviceId(); - int scancode = ev.getScanCode(); - - if (eventTime == 0) eventTime = SystemClock.uptimeMillis(); - if (downTime == 0) downTime = eventTime; - - KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState, - deviceId, scancode); - - boolean result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid()); - if (sync) { - mKeyWaiter.waitForNextEventTarget(null, null, null, false, true); - } - return result; - } - - /** - * Inject a pointer (touch) event into the UI. - * - * @param ev A motion event describing the pointer (touch) action. (As noted in - * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectPointerEvent(MotionEvent ev, boolean sync) { - boolean result = dispatchPointer(null, ev, Binder.getCallingPid(), Binder.getCallingUid()); - if (sync) { - mKeyWaiter.waitForNextEventTarget(null, null, null, false, true); - } - return result; - } - - /** - * Inject a trackball (navigation device) event into the UI. - * - * @param ev A motion event describing the trackball action. (As noted in - * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectTrackballEvent(MotionEvent ev, boolean sync) { - boolean result = dispatchTrackball(null, ev, Binder.getCallingPid(), Binder.getCallingUid()); - if (sync) { - mKeyWaiter.waitForNextEventTarget(null, null, null, false, true); - } - return result; - } - - private WindowState getFocusedWindow() { - synchronized (mWindowMap) { - return getFocusedWindowLocked(); - } - } - - private WindowState getFocusedWindowLocked() { - return mCurrentFocus; - } - - /** - * This class holds the state for dispatching key events. This state - * is protected by the KeyWaiter instance, NOT by the window lock. You - * can be holding the main window lock while acquire the KeyWaiter lock, - * but not the other way around. - */ - final class KeyWaiter { - public static final int RETURN_NOTHING = 0; - public static final int RETURN_PENDING_POINTER = 1; - public static final int RETURN_PENDING_TRACKBALL = 2; - - final Object SKIP_TARGET_TOKEN = new Object(); - final Object CONSUMED_EVENT_TOKEN = new Object(); - - private WindowState mLastWin = null; - private IBinder mLastBinder = null; - private boolean mFinished = true; - private boolean mGotFirstWindow = false; - private boolean mEventDispatching = true; - private long mTimeToSwitch = 0; - /* package */ boolean mWasFrozen = false; - - // Target of Motion events - WindowState mMotionTarget; - - // Windows above the target who would like to receive an "outside" - // touch event for any down events outside of them. - WindowState mOutsideTouchTargets; - - /** - * Wait for the last event dispatch to complete, then find the next - * target that should receive the given event and wait for that one - * to be ready to receive it. - */ - Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev, - MotionEvent nextMotion, boolean isPointerEvent, - boolean failIfTimeout) { - long startTime = SystemClock.uptimeMillis(); - long keyDispatchingTimeout = 5 * 1000; - long waitedFor = 0; - - while (true) { - // Figure out which window we care about. It is either the - // last window we are waiting to have process the event or, - // if none, then the next window we think the event should go - // to. Note: we retrieve mLastWin outside of the lock, so - // it may change before we lock. Thus we must check it again. - WindowState targetWin = mLastWin; - boolean targetIsNew = targetWin == null; - if (DEBUG_INPUT) Log.v( - TAG, "waitForLastKey: mFinished=" + mFinished + - ", mLastWin=" + mLastWin); - if (targetIsNew) { - Object target = findTargetWindow(nextKey, qev, nextMotion, - isPointerEvent); - if (target == SKIP_TARGET_TOKEN) { - // The user has pressed a special key, and we are - // dropping all pending events before it. - if (DEBUG_INPUT) Log.v(TAG, "Skipping: " + nextKey - + " " + nextMotion); - return null; - } - if (target == CONSUMED_EVENT_TOKEN) { - if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey - + " " + nextMotion); - return target; - } - targetWin = (WindowState)target; - } - - AppWindowToken targetApp = null; - - // Now: is it okay to send the next event to this window? - synchronized (this) { - // First: did we come here based on the last window not - // being null, but it changed by the time we got here? - // If so, try again. - if (!targetIsNew && mLastWin == null) { - continue; - } - - // We never dispatch events if not finished with the - // last one, or the display is frozen. - if (mFinished && !mDisplayFrozen) { - // If event dispatching is disabled, then we - // just consume the events. - if (!mEventDispatching) { - if (DEBUG_INPUT) Log.v(TAG, - "Skipping event; dispatching disabled: " - + nextKey + " " + nextMotion); - return null; - } - if (targetWin != null) { - // If this is a new target, and that target is not - // paused or unresponsive, then all looks good to - // handle the event. - if (targetIsNew && !targetWin.mToken.paused) { - return targetWin; - } - - // If we didn't find a target window, and there is no - // focused app window, then just eat the events. - } else if (mFocusedApp == null) { - if (DEBUG_INPUT) Log.v(TAG, - "Skipping event; no focused app: " - + nextKey + " " + nextMotion); - return null; - } - } - - if (DEBUG_INPUT) Log.v( - TAG, "Waiting for last key in " + mLastBinder - + " target=" + targetWin - + " mFinished=" + mFinished - + " mDisplayFrozen=" + mDisplayFrozen - + " targetIsNew=" + targetIsNew - + " paused=" - + (targetWin != null ? targetWin.mToken.paused : false) - + " mFocusedApp=" + mFocusedApp); - - targetApp = targetWin != null - ? targetWin.mAppToken : mFocusedApp; - - long curTimeout = keyDispatchingTimeout; - if (mTimeToSwitch != 0) { - long now = SystemClock.uptimeMillis(); - if (mTimeToSwitch <= now) { - // If an app switch key has been pressed, and we have - // waited too long for the current app to finish - // processing keys, then wait no more! - doFinishedKeyLocked(true); - continue; - } - long switchTimeout = mTimeToSwitch - now; - if (curTimeout > switchTimeout) { - curTimeout = switchTimeout; - } - } - - try { - // after that continue - // processing keys, so we don't get stuck. - if (DEBUG_INPUT) Log.v( - TAG, "Waiting for key dispatch: " + curTimeout); - wait(curTimeout); - if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @" - + SystemClock.uptimeMillis() + " startTime=" - + startTime + " switchTime=" + mTimeToSwitch); - } catch (InterruptedException e) { - } - } - - // If we were frozen during configuration change, restart the - // timeout checks from now; otherwise look at whether we timed - // out before awakening. - if (mWasFrozen) { - waitedFor = 0; - mWasFrozen = false; - } else { - waitedFor = SystemClock.uptimeMillis() - startTime; - } - - if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) { - IApplicationToken at = null; - synchronized (this) { - Log.w(TAG, "Key dispatching timed out sending to " + - (targetWin != null ? targetWin.mAttrs.getTitle() - : "<null>")); - //dump(); - if (targetWin != null) { - at = targetWin.getAppToken(); - } else if (targetApp != null) { - at = targetApp.appToken; - } - } - - boolean abort = true; - if (at != null) { - try { - long timeout = at.getKeyDispatchingTimeout(); - if (timeout > waitedFor) { - // we did not wait the proper amount of time for this application. - // set the timeout to be the real timeout and wait again. - keyDispatchingTimeout = timeout - waitedFor; - continue; - } else { - abort = at.keyDispatchingTimedOut(); - } - } catch (RemoteException ex) { - } - } - - synchronized (this) { - if (abort && (mLastWin == targetWin || targetWin == null)) { - mFinished = true; - if (mLastWin != null) { - if (DEBUG_INPUT) Log.v(TAG, - "Window " + mLastWin + - " timed out on key input"); - if (mLastWin.mToken.paused) { - Log.w(TAG, "Un-pausing dispatching to this window"); - mLastWin.mToken.paused = false; - } - } - if (mMotionTarget == targetWin) { - mMotionTarget = null; - } - mLastWin = null; - mLastBinder = null; - if (failIfTimeout || targetWin == null) { - return null; - } - } else { - Log.w(TAG, "Continuing to wait for key to be dispatched"); - startTime = SystemClock.uptimeMillis(); - } - } - } - } - } - - Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev, - MotionEvent nextMotion, boolean isPointerEvent) { - mOutsideTouchTargets = null; - - if (nextKey != null) { - // Find the target window for a normal key event. - final int keycode = nextKey.getKeyCode(); - final int repeatCount = nextKey.getRepeatCount(); - final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP; - boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode); - if (!dispatch) { - mPolicy.interceptKeyTi(null, keycode, - nextKey.getMetaState(), down, repeatCount); - Log.w(TAG, "Event timeout during app switch: dropping " - + nextKey); - return SKIP_TARGET_TOKEN; - } - - // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")"); - - WindowState focus = null; - synchronized(mWindowMap) { - focus = getFocusedWindowLocked(); - } - - wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT); - - if (mPolicy.interceptKeyTi(focus, - keycode, nextKey.getMetaState(), down, repeatCount)) { - return CONSUMED_EVENT_TOKEN; - } - - return focus; - - } else if (!isPointerEvent) { - boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1); - if (!dispatch) { - Log.w(TAG, "Event timeout during app switch: dropping trackball " - + nextMotion); - return SKIP_TARGET_TOKEN; - } - - WindowState focus = null; - synchronized(mWindowMap) { - focus = getFocusedWindowLocked(); - } - - wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT); - return focus; - } - - if (nextMotion == null) { - return SKIP_TARGET_TOKEN; - } - - boolean dispatch = mKeyWaiter.checkShouldDispatchKey( - KeyEvent.KEYCODE_UNKNOWN); - if (!dispatch) { - Log.w(TAG, "Event timeout during app switch: dropping pointer " - + nextMotion); - return SKIP_TARGET_TOKEN; - } - - // Find the target window for a pointer event. - int action = nextMotion.getAction(); - final float xf = nextMotion.getX(); - final float yf = nextMotion.getY(); - final long eventTime = nextMotion.getEventTime(); - - final boolean screenWasOff = qev != null - && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0; - - WindowState target = null; - - synchronized(mWindowMap) { - synchronized (this) { - if (action == MotionEvent.ACTION_DOWN) { - if (mMotionTarget != null) { - // this is weird, we got a pen down, but we thought it was - // already down! - // XXX: We should probably send an ACTION_UP to the current - // target. - Log.w(TAG, "Pointer down received while already down in: " - + mMotionTarget); - mMotionTarget = null; - } - - // ACTION_DOWN is special, because we need to lock next events to - // the window we'll land onto. - final int x = (int)xf; - final int y = (int)yf; - - final ArrayList windows = mWindows; - final int N = windows.size(); - WindowState topErrWindow = null; - final Rect tmpRect = mTempRect; - for (int i=N-1; i>=0; i--) { - WindowState child = (WindowState)windows.get(i); - //Log.i(TAG, "Checking dispatch to: " + child); - final int flags = child.mAttrs.flags; - if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) { - if (topErrWindow == null) { - topErrWindow = child; - } - } - if (!child.isVisibleLw()) { - //Log.i(TAG, "Not visible!"); - continue; - } - if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { - //Log.i(TAG, "Not touchable!"); - if ((flags & WindowManager.LayoutParams - .FLAG_WATCH_OUTSIDE_TOUCH) != 0) { - child.mNextOutsideTouch = mOutsideTouchTargets; - mOutsideTouchTargets = child; - } - continue; - } - tmpRect.set(child.mFrame); - if (child.mTouchableInsets == ViewTreeObserver - .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) { - // The touch is inside of the window if it is - // inside the frame, AND the content part of that - // frame that was given by the application. - tmpRect.left += child.mGivenContentInsets.left; - tmpRect.top += child.mGivenContentInsets.top; - tmpRect.right -= child.mGivenContentInsets.right; - tmpRect.bottom -= child.mGivenContentInsets.bottom; - } else if (child.mTouchableInsets == ViewTreeObserver - .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) { - // The touch is inside of the window if it is - // inside the frame, AND the visible part of that - // frame that was given by the application. - tmpRect.left += child.mGivenVisibleInsets.left; - tmpRect.top += child.mGivenVisibleInsets.top; - tmpRect.right -= child.mGivenVisibleInsets.right; - tmpRect.bottom -= child.mGivenVisibleInsets.bottom; - } - final int touchFlags = flags & - (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); - if (tmpRect.contains(x, y) || touchFlags == 0) { - //Log.i(TAG, "Using this target!"); - if (!screenWasOff || (flags & - WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) { - mMotionTarget = child; - } else { - //Log.i(TAG, "Waking, skip!"); - mMotionTarget = null; - } - break; - } - - if ((flags & WindowManager.LayoutParams - .FLAG_WATCH_OUTSIDE_TOUCH) != 0) { - child.mNextOutsideTouch = mOutsideTouchTargets; - mOutsideTouchTargets = child; - //Log.i(TAG, "Adding to outside target list: " + child); - } - } - - // if there's an error window but it's not accepting - // focus (typically because it is not yet visible) just - // wait for it -- any other focused window may in fact - // be in ANR state. - if (topErrWindow != null && mMotionTarget != topErrWindow) { - mMotionTarget = null; - } - } - - target = mMotionTarget; - } - } - - wakeupIfNeeded(target, eventType(nextMotion)); - - // Pointer events are a little different -- if there isn't a - // target found for any event, then just drop it. - return target != null ? target : SKIP_TARGET_TOKEN; - } - - boolean checkShouldDispatchKey(int keycode) { - synchronized (this) { - if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) { - mTimeToSwitch = 0; - return true; - } - if (mTimeToSwitch != 0 - && mTimeToSwitch < SystemClock.uptimeMillis()) { - return false; - } - return true; - } - } - - void bindTargetWindowLocked(WindowState win, - int pendingWhat, QueuedEvent pendingMotion) { - synchronized (this) { - bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion); - } - } - - void bindTargetWindowLocked(WindowState win) { - synchronized (this) { - bindTargetWindowLockedLocked(win, RETURN_NOTHING, null); - } - } - - void bindTargetWindowLockedLocked(WindowState win, - int pendingWhat, QueuedEvent pendingMotion) { - mLastWin = win; - mLastBinder = win.mClient.asBinder(); - mFinished = false; - if (pendingMotion != null) { - final Session s = win.mSession; - if (pendingWhat == RETURN_PENDING_POINTER) { - releasePendingPointerLocked(s); - s.mPendingPointerMove = pendingMotion; - s.mPendingPointerWindow = win; - if (DEBUG_INPUT) Log.v(TAG, - "bindTargetToWindow " + s.mPendingPointerMove); - } else if (pendingWhat == RETURN_PENDING_TRACKBALL) { - releasePendingTrackballLocked(s); - s.mPendingTrackballMove = pendingMotion; - s.mPendingTrackballWindow = win; - } - } - } - - void releasePendingPointerLocked(Session s) { - if (DEBUG_INPUT) Log.v(TAG, - "releasePendingPointer " + s.mPendingPointerMove); - if (s.mPendingPointerMove != null) { - mQueue.recycleEvent(s.mPendingPointerMove); - s.mPendingPointerMove = null; - } - } - - void releasePendingTrackballLocked(Session s) { - if (s.mPendingTrackballMove != null) { - mQueue.recycleEvent(s.mPendingTrackballMove); - s.mPendingTrackballMove = null; - } - } - - MotionEvent finishedKey(Session session, IWindow client, boolean force, - int returnWhat) { - if (DEBUG_INPUT) Log.v( - TAG, "finishedKey: client=" + client + ", force=" + force); - - if (client == null) { - return null; - } - - synchronized (this) { - if (DEBUG_INPUT) Log.v( - TAG, "finishedKey: client=" + client.asBinder() - + ", force=" + force + ", last=" + mLastBinder - + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")"); - - QueuedEvent qev = null; - WindowState win = null; - if (returnWhat == RETURN_PENDING_POINTER) { - qev = session.mPendingPointerMove; - win = session.mPendingPointerWindow; - session.mPendingPointerMove = null; - session.mPendingPointerWindow = null; - } else if (returnWhat == RETURN_PENDING_TRACKBALL) { - qev = session.mPendingTrackballMove; - win = session.mPendingTrackballWindow; - session.mPendingTrackballMove = null; - session.mPendingTrackballWindow = null; - } - - if (mLastBinder == client.asBinder()) { - if (DEBUG_INPUT) Log.v( - TAG, "finishedKey: last paused=" - + ((mLastWin != null) ? mLastWin.mToken.paused : "null")); - if (mLastWin != null && (!mLastWin.mToken.paused || force - || !mEventDispatching)) { - doFinishedKeyLocked(false); - } else { - // Make sure to wake up anyone currently waiting to - // dispatch a key, so they can re-evaluate their - // current situation. - mFinished = true; - notifyAll(); - } - } - - if (qev != null) { - MotionEvent res = (MotionEvent)qev.event; - if (DEBUG_INPUT) Log.v(TAG, - "Returning pending motion: " + res); - mQueue.recycleEvent(qev); - if (win != null && returnWhat == RETURN_PENDING_POINTER) { - res.offsetLocation(-win.mFrame.left, -win.mFrame.top); - } - return res; - } - return null; - } - } - - void tickle() { - synchronized (this) { - notifyAll(); - } - } - - void handleNewWindowLocked(WindowState newWindow) { - if (!newWindow.canReceiveKeys()) { - return; - } - synchronized (this) { - if (DEBUG_INPUT) Log.v( - TAG, "New key dispatch window: win=" - + newWindow.mClient.asBinder() - + ", last=" + mLastBinder - + " (token=" + (mLastWin != null ? mLastWin.mToken : null) - + "), finished=" + mFinished + ", paused=" - + newWindow.mToken.paused); - - // Displaying a window implicitly causes dispatching to - // be unpaused. (This is to protect against bugs if someone - // pauses dispatching but forgets to resume.) - newWindow.mToken.paused = false; - - mGotFirstWindow = true; - boolean doNotify = true; - - if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) { - if (DEBUG_INPUT) Log.v(TAG, - "New SYSTEM_ERROR window; resetting state"); - mLastWin = null; - mLastBinder = null; - mMotionTarget = null; - mFinished = true; - } else if (mLastWin != null) { - // If the new window is above the window we are - // waiting on, then stop waiting and let key dispatching - // start on the new guy. - if (DEBUG_INPUT) Log.v( - TAG, "Last win layer=" + mLastWin.mLayer - + ", new win layer=" + newWindow.mLayer); - if (newWindow.mLayer >= mLastWin.mLayer) { - if (!mLastWin.canReceiveKeys()) { - mLastWin.mToken.paused = false; - doFinishedKeyLocked(true); // does a notifyAll() - doNotify = false; - } - } else { - // the new window is lower; no need to wake key waiters - doNotify = false; - } - } - - if (doNotify) { - notifyAll(); - } - } - } - - void pauseDispatchingLocked(WindowToken token) { - synchronized (this) - { - if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token); - token.paused = true; - - /* - if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) { - mPaused = true; - } else { - if (mLastWin == null) { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: no last window."); - } else if (mFinished) { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: finished last key."); - } else { - if (Config.LOGI) Log.i( - TAG, "Key dispatching not paused: window in higher layer."); - } - } - */ - } - } - - void resumeDispatchingLocked(WindowToken token) { - synchronized (this) { - if (token.paused) { - if (DEBUG_INPUT) Log.v( - TAG, "Resuming WindowToken " + token - + ", last=" + mLastBinder - + " (token=" + (mLastWin != null ? mLastWin.mToken : null) - + "), finished=" + mFinished + ", paused=" - + token.paused); - token.paused = false; - if (mLastWin != null && mLastWin.mToken == token && mFinished) { - doFinishedKeyLocked(true); - } else { - notifyAll(); - } - } - } - } - - void setEventDispatchingLocked(boolean enabled) { - synchronized (this) { - mEventDispatching = enabled; - notifyAll(); - } - } - - void appSwitchComing() { - synchronized (this) { - // Don't wait for more than .5 seconds for app to finish - // processing the pending events. - long now = SystemClock.uptimeMillis() + 500; - if (DEBUG_INPUT) Log.v(TAG, "appSwitchComing: " + now); - if (mTimeToSwitch == 0 || now < mTimeToSwitch) { - mTimeToSwitch = now; - } - notifyAll(); - } - } - - private final void doFinishedKeyLocked(boolean doRecycle) { - if (mLastWin != null) { - releasePendingPointerLocked(mLastWin.mSession); - releasePendingTrackballLocked(mLastWin.mSession); - } - - if (mLastWin == null || !mLastWin.mToken.paused - || !mLastWin.isVisibleLw()) { - // If the current window has been paused, we aren't -really- - // finished... so let the waiters still wait. - mLastWin = null; - mLastBinder = null; - } - mFinished = true; - notifyAll(); - } - } - - private class KeyQ extends KeyInputQueue - implements KeyInputQueue.FilterCallback { - PowerManager.WakeLock mHoldingScreen; - - KeyQ() { - super(mContext); - PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); - mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, - "KEEP_SCREEN_ON_FLAG"); - mHoldingScreen.setReferenceCounted(false); - } - - @Override - boolean preprocessEvent(InputDevice device, RawInputEvent event) { - if (mPolicy.preprocessInputEventTq(event)) { - return true; - } - - switch (event.type) { - case RawInputEvent.EV_KEY: { - // XXX begin hack - if (DEBUG) { - if (event.keycode == KeyEvent.KEYCODE_G) { - if (event.value != 0) { - // G down - mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER); - } - return false; - } - if (event.keycode == KeyEvent.KEYCODE_D) { - if (event.value != 0) { - //dump(); - } - return false; - } - } - // XXX end hack - - boolean screenIsOff = !mPowerManager.screenIsOn(); - boolean screenIsDim = !mPowerManager.screenIsBright(); - int actions = mPolicy.interceptKeyTq(event, !screenIsOff); - - if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) { - mPowerManager.goToSleep(event.when); - } - - if (screenIsOff) { - event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE; - } - if (screenIsDim) { - event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE; - } - if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) { - mPowerManager.userActivity(event.when, false, - LocalPowerManager.BUTTON_EVENT); - } - - if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) { - if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) { - filterQueue(this); - mKeyWaiter.appSwitchComing(); - } - return true; - } else { - return false; - } - } - - case RawInputEvent.EV_REL: { - boolean screenIsOff = !mPowerManager.screenIsOn(); - boolean screenIsDim = !mPowerManager.screenIsBright(); - if (screenIsOff) { - if (!mPolicy.isWakeRelMovementTq(event.deviceId, - device.classes, event)) { - //Log.i(TAG, "dropping because screenIsOff and !isWakeKey"); - return false; - } - event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE; - } - if (screenIsDim) { - event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE; - } - return true; - } - - case RawInputEvent.EV_ABS: { - boolean screenIsOff = !mPowerManager.screenIsOn(); - boolean screenIsDim = !mPowerManager.screenIsBright(); - if (screenIsOff) { - if (!mPolicy.isWakeAbsMovementTq(event.deviceId, - device.classes, event)) { - //Log.i(TAG, "dropping because screenIsOff and !isWakeKey"); - return false; - } - event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE; - } - if (screenIsDim) { - event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE; - } - return true; - } - - default: - return true; - } - } - - public int filterEvent(QueuedEvent ev) { - switch (ev.classType) { - case RawInputEvent.CLASS_KEYBOARD: - KeyEvent ke = (KeyEvent)ev.event; - if (mPolicy.isMovementKeyTi(ke.getKeyCode())) { - Log.w(TAG, "Dropping movement key during app switch: " - + ke.getKeyCode() + ", action=" + ke.getAction()); - return FILTER_REMOVE; - } - return FILTER_ABORT; - default: - return FILTER_KEEP; - } - } - - /** - * Must be called with the main window manager lock held. - */ - void setHoldScreenLocked(boolean holding) { - boolean state = mHoldingScreen.isHeld(); - if (holding != state) { - if (holding) { - mHoldingScreen.acquire(); - } else { - mPolicy.screenOnStopped(); - mHoldingScreen.release(); - } - } - } - }; - - public boolean detectSafeMode() { - mSafeMode = mPolicy.detectSafeMode(); - return mSafeMode; - } - - public void systemReady() { - mPolicy.systemReady(); - } - - private final class InputDispatcherThread extends Thread { - // Time to wait when there is nothing to do: 9999 seconds. - static final int LONG_WAIT=9999*1000; - - public InputDispatcherThread() { - super("InputDispatcher"); - } - - @Override - public void run() { - while (true) { - try { - process(); - } catch (Exception e) { - Log.e(TAG, "Exception in input dispatcher", e); - } - } - } - - private void process() { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); - - // The last key event we saw - KeyEvent lastKey = null; - - // Last keydown time for auto-repeating keys - long lastKeyTime = SystemClock.uptimeMillis(); - long nextKeyTime = lastKeyTime+LONG_WAIT; - - // How many successive repeats we generated - int keyRepeatCount = 0; - - // Need to report that configuration has changed? - boolean configChanged = false; - - while (true) { - long curTime = SystemClock.uptimeMillis(); - - if (DEBUG_INPUT) Log.v( - TAG, "Waiting for next key: now=" + curTime - + ", repeat @ " + nextKeyTime); - - // Retrieve next event, waiting only as long as the next - // repeat timeout. If the configuration has changed, then - // don't wait at all -- we'll report the change as soon as - // we have processed all events. - QueuedEvent ev = mQueue.getEvent( - (int)((!configChanged && curTime < nextKeyTime) - ? (nextKeyTime-curTime) : 0)); - - if (DEBUG_INPUT && ev != null) Log.v( - TAG, "Event: type=" + ev.classType + " data=" + ev.event); - - try { - if (ev != null) { - curTime = ev.when; - int eventType; - if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) { - eventType = eventType((MotionEvent)ev.event); - } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD || - ev.classType == RawInputEvent.CLASS_TRACKBALL) { - eventType = LocalPowerManager.BUTTON_EVENT; - } else { - eventType = LocalPowerManager.OTHER_EVENT; - } - mPowerManager.userActivity(curTime, false, eventType); - switch (ev.classType) { - case RawInputEvent.CLASS_KEYBOARD: - KeyEvent ke = (KeyEvent)ev.event; - if (ke.isDown()) { - lastKey = ke; - keyRepeatCount = 0; - lastKeyTime = curTime; - nextKeyTime = lastKeyTime - + KEY_REPEAT_FIRST_DELAY; - if (DEBUG_INPUT) Log.v( - TAG, "Received key down: first repeat @ " - + nextKeyTime); - } else { - lastKey = null; - // Arbitrary long timeout. - lastKeyTime = curTime; - nextKeyTime = curTime + LONG_WAIT; - if (DEBUG_INPUT) Log.v( - TAG, "Received key up: ignore repeat @ " - + nextKeyTime); - } - dispatchKey((KeyEvent)ev.event, 0, 0); - mQueue.recycleEvent(ev); - break; - case RawInputEvent.CLASS_TOUCHSCREEN: - //Log.i(TAG, "Read next event " + ev); - dispatchPointer(ev, (MotionEvent)ev.event, 0, 0); - break; - case RawInputEvent.CLASS_TRACKBALL: - dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0); - break; - case RawInputEvent.CLASS_CONFIGURATION_CHANGED: - configChanged = true; - break; - default: - mQueue.recycleEvent(ev); - break; - } - - } else if (configChanged) { - configChanged = false; - sendNewConfiguration(); - - } else if (lastKey != null) { - curTime = SystemClock.uptimeMillis(); - - // Timeout occurred while key was down. If it is at or - // past the key repeat time, dispatch the repeat. - if (DEBUG_INPUT) Log.v( - TAG, "Key timeout: repeat=" + nextKeyTime - + ", now=" + curTime); - if (curTime < nextKeyTime) { - continue; - } - - lastKeyTime = nextKeyTime; - nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY; - keyRepeatCount++; - if (DEBUG_INPUT) Log.v( - TAG, "Key repeat: count=" + keyRepeatCount - + ", next @ " + nextKeyTime); - dispatchKey(new KeyEvent(lastKey, curTime, keyRepeatCount), 0, 0); - - } else { - curTime = SystemClock.uptimeMillis(); - - lastKeyTime = curTime; - nextKeyTime = curTime + LONG_WAIT; - } - - } catch (Exception e) { - Log.e(TAG, - "Input thread received uncaught exception: " + e, e); - } - } - } - } - - // ------------------------------------------------------------- - // Client Session State - // ------------------------------------------------------------- - - private final class Session extends IWindowSession.Stub - implements IBinder.DeathRecipient { - final IInputMethodClient mClient; - final IInputContext mInputContext; - final int mUid; - final int mPid; - SurfaceSession mSurfaceSession; - int mNumWindow = 0; - boolean mClientDead = false; - - /** - * Current pointer move event being dispatched to client window... must - * hold key lock to access. - */ - QueuedEvent mPendingPointerMove; - WindowState mPendingPointerWindow; - - /** - * Current trackball move event being dispatched to client window... must - * hold key lock to access. - */ - QueuedEvent mPendingTrackballMove; - WindowState mPendingTrackballWindow; - - public Session(IInputMethodClient client, IInputContext inputContext) { - mClient = client; - mInputContext = inputContext; - mUid = Binder.getCallingUid(); - mPid = Binder.getCallingPid(); - synchronized (mWindowMap) { - if (mInputMethodManager == null && mHaveInputMethods) { - IBinder b = ServiceManager.getService( - Context.INPUT_METHOD_SERVICE); - mInputMethodManager = IInputMethodManager.Stub.asInterface(b); - } - } - long ident = Binder.clearCallingIdentity(); - try { - // Note: it is safe to call in to the input method manager - // here because we are not holding our lock. - if (mInputMethodManager != null) { - mInputMethodManager.addClient(client, inputContext, - mUid, mPid); - } else { - client.setUsingInputMethod(false); - } - client.asBinder().linkToDeath(this, 0); - } catch (RemoteException e) { - // The caller has died, so we can just forget about this. - try { - if (mInputMethodManager != null) { - mInputMethodManager.removeClient(client); - } - } catch (RemoteException ee) { - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - // Log all 'real' exceptions thrown to the caller - if (!(e instanceof SecurityException)) { - Log.e(TAG, "Window Session Crash", e); - } - throw e; - } - } - - public void binderDied() { - // Note: it is safe to call in to the input method manager - // here because we are not holding our lock. - try { - if (mInputMethodManager != null) { - mInputMethodManager.removeClient(mClient); - } - } catch (RemoteException e) { - } - synchronized(mWindowMap) { - mClientDead = true; - killSessionLocked(); - } - } - - public int add(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, Rect outContentInsets) { - return addWindow(this, window, attrs, viewVisibility, outContentInsets); - } - - public void remove(IWindow window) { - removeWindow(this, window); - } - - public int relayout(IWindow window, WindowManager.LayoutParams attrs, - int requestedWidth, int requestedHeight, int viewFlags, - boolean insetsPending, Rect outFrame, Rect outContentInsets, - Rect outVisibleInsets, Surface outSurface) { - return relayoutWindow(this, window, attrs, - requestedWidth, requestedHeight, viewFlags, insetsPending, - outFrame, outContentInsets, outVisibleInsets, outSurface); - } - - public void setTransparentRegion(IWindow window, Region region) { - setTransparentRegionWindow(this, window, region); - } - - public void setInsets(IWindow window, int touchableInsets, - Rect contentInsets, Rect visibleInsets) { - setInsetsWindow(this, window, touchableInsets, contentInsets, - visibleInsets); - } - - public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { - getWindowDisplayFrame(this, window, outDisplayFrame); - } - - public void finishDrawing(IWindow window) { - if (localLOGV) Log.v( - TAG, "IWindow finishDrawing called for " + window); - finishDrawingWindow(this, window); - } - - public void finishKey(IWindow window) { - if (localLOGV) Log.v( - TAG, "IWindow finishKey called for " + window); - mKeyWaiter.finishedKey(this, window, false, - KeyWaiter.RETURN_NOTHING); - } - - public MotionEvent getPendingPointerMove(IWindow window) { - if (localLOGV) Log.v( - TAG, "IWindow getPendingMotionEvent called for " + window); - return mKeyWaiter.finishedKey(this, window, false, - KeyWaiter.RETURN_PENDING_POINTER); - } - - public MotionEvent getPendingTrackballMove(IWindow window) { - if (localLOGV) Log.v( - TAG, "IWindow getPendingMotionEvent called for " + window); - return mKeyWaiter.finishedKey(this, window, false, - KeyWaiter.RETURN_PENDING_TRACKBALL); - } - - public void setInTouchMode(boolean mode) { - synchronized(mWindowMap) { - mInTouchMode = mode; - } - } - - public boolean getInTouchMode() { - synchronized(mWindowMap) { - return mInTouchMode; - } - } - - public boolean performHapticFeedback(IWindow window, int effectId, - boolean always) { - synchronized(mWindowMap) { - long ident = Binder.clearCallingIdentity(); - try { - return mPolicy.performHapticFeedback( - windowForClientLocked(this, window), effectId, always); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - void windowAddedLocked() { - if (mSurfaceSession == null) { - if (localLOGV) Log.v( - TAG, "First window added to " + this + ", creating SurfaceSession"); - mSurfaceSession = new SurfaceSession(); - mSessions.add(this); - } - mNumWindow++; - } - - void windowRemovedLocked() { - mNumWindow--; - killSessionLocked(); - } - - void killSessionLocked() { - if (mNumWindow <= 0 && mClientDead) { - mSessions.remove(this); - if (mSurfaceSession != null) { - if (localLOGV) Log.v( - TAG, "Last window removed from " + this - + ", destroying " + mSurfaceSession); - try { - mSurfaceSession.kill(); - } catch (Exception e) { - Log.w(TAG, "Exception thrown when killing surface session " - + mSurfaceSession + " in session " + this - + ": " + e.toString()); - } - mSurfaceSession = null; - } - } - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mNumWindow=" + mNumWindow - + " mClientDead=" + mClientDead - + " mSurfaceSession=" + mSurfaceSession); - pw.println(prefix + "mPendingPointerWindow=" + mPendingPointerWindow - + " mPendingPointerMove=" + mPendingPointerMove); - pw.println(prefix + "mPendingTrackballWindow=" + mPendingTrackballWindow - + " mPendingTrackballMove=" + mPendingTrackballMove); - } - - @Override - public String toString() { - return "Session{" - + Integer.toHexString(System.identityHashCode(this)) + "}"; - } - } - - // ------------------------------------------------------------- - // Client Window State - // ------------------------------------------------------------- - - private final class WindowState implements WindowManagerPolicy.WindowState { - final Session mSession; - final IWindow mClient; - WindowToken mToken; - AppWindowToken mAppToken; - AppWindowToken mTargetAppToken; - final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); - final DeathRecipient mDeathRecipient; - final WindowState mAttachedWindow; - final ArrayList mChildWindows = new ArrayList(); - final int mBaseLayer; - final int mSubLayer; - final boolean mLayoutAttached; - final boolean mIsImWindow; - int mViewVisibility; - boolean mPolicyVisibility = true; - boolean mPolicyVisibilityAfterAnim = true; - boolean mAppFreezing; - Surface mSurface; - boolean mAttachedHidden; // is our parent window hidden? - boolean mLastHidden; // was this window last hidden? - int mRequestedWidth; - int mRequestedHeight; - int mLastRequestedWidth; - int mLastRequestedHeight; - int mReqXPos; - int mReqYPos; - int mLayer; - int mAnimLayer; - int mLastLayer; - boolean mHaveFrame; - - WindowState mNextOutsideTouch; - - // Actual frame shown on-screen (may be modified by animation) - final Rect mShownFrame = new Rect(); - final Rect mLastShownFrame = new Rect(); - - /** - * Insets that determine the actually visible area - */ - final Rect mVisibleInsets = new Rect(); - final Rect mLastVisibleInsets = new Rect(); - boolean mVisibleInsetsChanged; - - /** - * Insets that are covered by system windows - */ - final Rect mContentInsets = new Rect(); - final Rect mLastContentInsets = new Rect(); - boolean mContentInsetsChanged; - - /** - * Set to true if we are waiting for this window to receive its - * given internal insets before laying out other windows based on it. - */ - boolean mGivenInsetsPending; - - /** - * These are the content insets that were given during layout for - * this window, to be applied to windows behind it. - */ - final Rect mGivenContentInsets = new Rect(); - - /** - * These are the visible insets that were given during layout for - * this window, to be applied to windows behind it. - */ - final Rect mGivenVisibleInsets = new Rect(); - - /** - * Flag indicating whether the touchable region should be adjusted by - * the visible insets; if false the area outside the visible insets is - * NOT touchable, so we must use those to adjust the frame during hit - * tests. - */ - int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; - - // Current transformation being applied. - float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1; - float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1; - float mHScale=1, mVScale=1; - float mLastHScale=1, mLastVScale=1; - final Matrix mTmpMatrix = new Matrix(); - - // "Real" frame that the application sees. - final Rect mFrame = new Rect(); - final Rect mLastFrame = new Rect(); - - final Rect mContainingFrame = new Rect(); - final Rect mDisplayFrame = new Rect(); - final Rect mContentFrame = new Rect(); - final Rect mVisibleFrame = new Rect(); - - float mShownAlpha = 1; - float mAlpha = 1; - float mLastAlpha = 1; - - // Set to true if, when the window gets displayed, it should perform - // an enter animation. - boolean mEnterAnimationPending; - - // Currently running animation. - boolean mAnimating; - boolean mLocalAnimating; - Animation mAnimation; - boolean mAnimationIsEntrance; - boolean mHasTransformation; - boolean mHasLocalTransformation; - final Transformation mTransformation = new Transformation(); - - // This is set after IWindowSession.relayout() has been called at - // least once for the window. It allows us to detect the situation - // where we don't yet have a surface, but should have one soon, so - // we can give the window focus before waiting for the relayout. - boolean mRelayoutCalled; - - // This is set after the Surface has been created but before the - // window has been drawn. During this time the surface is hidden. - boolean mDrawPending; - - // This is set after the window has finished drawing for the first - // time but before its surface is shown. The surface will be - // displayed when the next layout is run. - boolean mCommitDrawPending; - - // This is set during the time after the window's drawing has been - // committed, and before its surface is actually shown. It is used - // to delay showing the surface until all windows in a token are ready - // to be shown. - boolean mReadyToShow; - - // Set when the window has been shown in the screen the first time. - boolean mHasDrawn; - - // Currently running an exit animation? - boolean mExiting; - - // Currently on the mDestroySurface list? - boolean mDestroying; - - // Completely remove from window manager after exit animation? - boolean mRemoveOnExit; - - // Set when the orientation is changing and this window has not yet - // been updated for the new orientation. - boolean mOrientationChanging; - - // Is this window now (or just being) removed? - boolean mRemoved; - - WindowState(Session s, IWindow c, WindowToken token, - WindowState attachedWindow, WindowManager.LayoutParams a, - int viewVisibility) { - mSession = s; - mClient = c; - mToken = token; - mAttrs.copyFrom(a); - mViewVisibility = viewVisibility; - DeathRecipient deathRecipient = new DeathRecipient(); - mAlpha = a.alpha; - if (localLOGV) Log.v( - TAG, "Window " + this + " client=" + c.asBinder() - + " token=" + token + " (" + mAttrs.token + ")"); - try { - c.asBinder().linkToDeath(deathRecipient, 0); - } catch (RemoteException e) { - mDeathRecipient = null; - mAttachedWindow = null; - mLayoutAttached = false; - mIsImWindow = false; - mBaseLayer = 0; - mSubLayer = 0; - return; - } - mDeathRecipient = deathRecipient; - - if ((mAttrs.type >= FIRST_SUB_WINDOW && - mAttrs.type <= LAST_SUB_WINDOW)) { - // The multiplier here is to reserve space for multiple - // windows in the same type layer. - mBaseLayer = mPolicy.windowTypeToLayerLw( - attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; - mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type); - mAttachedWindow = attachedWindow; - mAttachedWindow.mChildWindows.add(this); - mLayoutAttached = mAttrs.type != - WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; - mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD - || attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG; - } else { - // The multiplier here is to reserve space for multiple - // windows in the same type layer. - mBaseLayer = mPolicy.windowTypeToLayerLw(a.type) - * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; - mSubLayer = 0; - mAttachedWindow = null; - mLayoutAttached = false; - mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD - || mAttrs.type == TYPE_INPUT_METHOD_DIALOG; - } - - WindowState appWin = this; - while (appWin.mAttachedWindow != null) { - appWin = mAttachedWindow; - } - WindowToken appToken = appWin.mToken; - while (appToken.appWindowToken == null) { - WindowToken parent = mTokenMap.get(appToken.token); - if (parent == null || appToken == parent) { - break; - } - appToken = parent; - } - mAppToken = appToken.appWindowToken; - - mSurface = null; - mRequestedWidth = 0; - mRequestedHeight = 0; - mLastRequestedWidth = 0; - mLastRequestedHeight = 0; - mReqXPos = 0; - mReqYPos = 0; - mLayer = 0; - mAnimLayer = 0; - mLastLayer = 0; - } - - void attach() { - if (localLOGV) Log.v( - TAG, "Attaching " + this + " token=" + mToken - + ", list=" + mToken.windows); - mSession.windowAddedLocked(); - } - - public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) { - mHaveFrame = true; - - final int pw = pf.right-pf.left; - final int ph = pf.bottom-pf.top; - - int w,h; - if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) { - w = mAttrs.width < 0 ? pw : mAttrs.width; - h = mAttrs.height< 0 ? ph : mAttrs.height; - } else { - w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth; - h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight; - } - - final Rect container = mContainingFrame; - container.set(pf); - - final Rect display = mDisplayFrame; - display.set(df); - - final Rect content = mContentFrame; - content.set(cf); - - final Rect visible = mVisibleFrame; - visible.set(vf); - - final Rect frame = mFrame; - - //System.out.println("In: w=" + w + " h=" + h + " container=" + - // container + " x=" + mAttrs.x + " y=" + mAttrs.y); - - Gravity.apply(mAttrs.gravity, w, h, container, - (int) (mAttrs.x + mAttrs.horizontalMargin * pw), - (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame); - - //System.out.println("Out: " + mFrame); - - // Now make sure the window fits in the overall display. - Gravity.applyDisplay(mAttrs.gravity, df, frame); - - // Make sure the content and visible frames are inside of the - // final window frame. - if (content.left < frame.left) content.left = frame.left; - if (content.top < frame.top) content.top = frame.top; - if (content.right > frame.right) content.right = frame.right; - if (content.bottom > frame.bottom) content.bottom = frame.bottom; - if (visible.left < frame.left) visible.left = frame.left; - if (visible.top < frame.top) visible.top = frame.top; - if (visible.right > frame.right) visible.right = frame.right; - if (visible.bottom > frame.bottom) visible.bottom = frame.bottom; - - final Rect contentInsets = mContentInsets; - contentInsets.left = content.left-frame.left; - contentInsets.top = content.top-frame.top; - contentInsets.right = frame.right-content.right; - contentInsets.bottom = frame.bottom-content.bottom; - - final Rect visibleInsets = mVisibleInsets; - visibleInsets.left = visible.left-frame.left; - visibleInsets.top = visible.top-frame.top; - visibleInsets.right = frame.right-visible.right; - visibleInsets.bottom = frame.bottom-visible.bottom; - - if (localLOGV) { - //if ("com.google.android.youtube".equals(mAttrs.packageName) - // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - Log.v(TAG, "Resolving (mRequestedWidth=" - + mRequestedWidth + ", mRequestedheight=" - + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph - + "): frame=" + mFrame.toShortString() - + " ci=" + contentInsets.toShortString() - + " vi=" + visibleInsets.toShortString()); - //} - } - } - - public Rect getFrameLw() { - return mFrame; - } - - public Rect getShownFrameLw() { - return mShownFrame; - } - - public Rect getDisplayFrameLw() { - return mDisplayFrame; - } - - public Rect getContentFrameLw() { - return mContentFrame; - } - - public Rect getVisibleFrameLw() { - return mVisibleFrame; - } - - public boolean getGivenInsetsPendingLw() { - return mGivenInsetsPending; - } - - public Rect getGivenContentInsetsLw() { - return mGivenContentInsets; - } - - public Rect getGivenVisibleInsetsLw() { - return mGivenVisibleInsets; - } - - public WindowManager.LayoutParams getAttrs() { - return mAttrs; - } - - public int getSurfaceLayer() { - return mLayer; - } - - public IApplicationToken getAppToken() { - return mAppToken != null ? mAppToken.appToken : null; - } - - public boolean hasAppShownWindows() { - return mAppToken != null ? mAppToken.firstWindowDrawn : false; - } - - public boolean hasAppStartingIcon() { - return mAppToken != null ? (mAppToken.startingData != null) : false; - } - - public WindowManagerPolicy.WindowState getAppStartingWindow() { - return mAppToken != null ? mAppToken.startingWindow : null; - } - - public void setAnimation(Animation anim) { - if (localLOGV) Log.v( - TAG, "Setting animation in " + this + ": " + anim); - mAnimating = false; - mLocalAnimating = false; - mAnimation = anim; - mAnimation.restrictDuration(MAX_ANIMATION_DURATION); - mAnimation.scaleCurrentDuration(mWindowAnimationScale); - } - - public void clearAnimation() { - if (mAnimation != null) { - mAnimating = true; - mLocalAnimating = false; - mAnimation = null; - } - } - - Surface createSurfaceLocked() { - if (mSurface == null) { - mDrawPending = true; - mCommitDrawPending = false; - mReadyToShow = false; - if (mAppToken != null) { - mAppToken.allDrawn = false; - } - - int flags = 0; - if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) { - flags |= Surface.HARDWARE; - } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) { - flags |= Surface.GPU; - } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) { - flags |= Surface.PUSH_BUFFERS; - } - - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { - flags |= Surface.SECURE; - } - if (DEBUG_VISIBILITY) Log.v( - TAG, "Creating surface in session " - + mSession.mSurfaceSession + " window " + this - + " w=" + mFrame.width() - + " h=" + mFrame.height() + " format=" - + mAttrs.format + " flags=" + flags); - - int w = mFrame.width(); - int h = mFrame.height(); - if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // for a scaled surface, we always want the requested - // size. - w = mRequestedWidth; - h = mRequestedHeight; - } - - try { - mSurface = new Surface( - mSession.mSurfaceSession, mSession.mPid, - 0, w, h, mAttrs.format, flags); - } catch (Surface.OutOfResourcesException e) { - Log.w(TAG, "OutOfResourcesException creating surface"); - reclaimSomeSurfaceMemoryLocked(this, "create"); - return null; - } catch (Exception e) { - Log.e(TAG, "Exception creating surface", e); - return null; - } - - if (localLOGV) Log.v( - TAG, "Got surface: " + mSurface - + ", set left=" + mFrame.left + " top=" + mFrame.top - + ", animLayer=" + mAnimLayer); - if (SHOW_TRANSACTIONS) { - Log.i(TAG, ">>> OPEN TRANSACTION"); - Log.i(TAG, " SURFACE " + mSurface + ": CREATE (" - + mAttrs.getTitle() + ") pos=(" + - mFrame.left + "," + mFrame.top + ") (" + - mFrame.width() + "x" + mFrame.height() + "), layer=" + - mAnimLayer + " HIDE"); - } - Surface.openTransaction(); - try { - try { - mSurface.setPosition(mFrame.left, mFrame.top); - mSurface.setLayer(mAnimLayer); - mSurface.hide(); - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { - mSurface.setFlags(Surface.SURFACE_DITHER, - Surface.SURFACE_DITHER); - } - } catch (RuntimeException e) { - Log.w(TAG, "Error creating surface in " + w, e); - reclaimSomeSurfaceMemoryLocked(this, "create-init"); - } - mLastHidden = true; - } finally { - if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION"); - Surface.closeTransaction(); - } - if (localLOGV) Log.v( - TAG, "Created surface " + this); - } - return mSurface; - } - - void destroySurfaceLocked() { - // Window is no longer on-screen, so can no longer receive - // key events... if we were waiting for it to finish - // handling a key event, the wait is over! - mKeyWaiter.finishedKey(mSession, mClient, true, - KeyWaiter.RETURN_NOTHING); - mKeyWaiter.releasePendingPointerLocked(mSession); - mKeyWaiter.releasePendingTrackballLocked(mSession); - - if (mAppToken != null && this == mAppToken.startingWindow) { - mAppToken.startingDisplayed = false; - } - - if (localLOGV) Log.v( - TAG, "Window " + this - + " destroying surface " + mSurface + ", session " + mSession); - if (mSurface != null) { - try { - if (SHOW_TRANSACTIONS) { - RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); - Log.i(TAG, " SURFACE " + mSurface + ": DESTROY (" - + mAttrs.getTitle() + ")", ex); - } - mSurface.clear(); - } catch (RuntimeException e) { - Log.w(TAG, "Exception thrown when destroying Window " + this - + " surface " + mSurface + " session " + mSession - + ": " + e.toString()); - } - mSurface = null; - mDrawPending = false; - mCommitDrawPending = false; - mReadyToShow = false; - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = (WindowState)mChildWindows.get(i); - c.mAttachedHidden = true; - } - } - } - - boolean finishDrawingLocked() { - if (mDrawPending) { - if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v( - TAG, "finishDrawingLocked: " + mSurface); - mCommitDrawPending = true; - mDrawPending = false; - return true; - } - return false; - } - - // This must be called while inside a transaction. - void commitFinishDrawingLocked(long currentTime) { - //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface); - if (!mCommitDrawPending) { - return; - } - mCommitDrawPending = false; - mReadyToShow = true; - final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING; - final AppWindowToken atoken = mAppToken; - if (atoken == null || atoken.allDrawn || starting) { - performShowLocked(); - } - } - - // This must be called while inside a transaction. - boolean performShowLocked() { - if (DEBUG_VISIBILITY) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.v(TAG, "performShow on " + this - + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay() - + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e); - } - if (mReadyToShow && isReadyForDisplay()) { - if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.i( - TAG, " SURFACE " + mSurface + ": SHOW (performShowLocked)"); - if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + this - + " during animation: policyVis=" + mPolicyVisibility - + " attHidden=" + mAttachedHidden - + " tok.hiddenRequested=" - + (mAppToken != null ? mAppToken.hiddenRequested : false) - + " tok.idden=" - + (mAppToken != null ? mAppToken.hidden : false) - + " animating=" + mAnimating - + " tok animating=" - + (mAppToken != null ? mAppToken.animating : false)); - if (!showSurfaceRobustlyLocked(this)) { - return false; - } - mLastAlpha = -1; - mHasDrawn = true; - mLastHidden = false; - mReadyToShow = false; - enableScreenIfNeededLocked(); - - applyEnterAnimationLocked(this); - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = (WindowState)mChildWindows.get(i); - if (c.mSurface != null && c.mAttachedHidden) { - c.mAttachedHidden = false; - c.performShowLocked(); - } - } - - if (mAttrs.type != TYPE_APPLICATION_STARTING - && mAppToken != null) { - mAppToken.firstWindowDrawn = true; - if (mAnimation == null && mAppToken.startingData != null) { - if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting " - + mToken - + ": first real window is shown, no animation"); - mFinishedStarting.add(mAppToken); - mH.sendEmptyMessage(H.FINISHED_STARTING); - } - mAppToken.updateReportedVisibilityLocked(); - } - } - return true; - } - - // This must be called while inside a transaction. Returns true if - // there is more animation to run. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!mDisplayFrozen) { - // We will run animations as long as the display isn't frozen. - - if (!mDrawPending && !mCommitDrawPending && mAnimation != null) { - mHasTransformation = true; - mHasLocalTransformation = true; - if (!mLocalAnimating) { - if (DEBUG_ANIM) Log.v( - TAG, "Starting animation in " + this + - " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() + - " dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale); - mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh); - mAnimation.setStartTime(currentTime); - mLocalAnimating = true; - mAnimating = true; - } - mTransformation.clear(); - final boolean more = mAnimation.getTransformation( - currentTime, mTransformation); - if (DEBUG_ANIM) Log.v( - TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + mTransformation); - if (more) { - // we're not done! - return true; - } - if (DEBUG_ANIM) Log.v( - TAG, "Finished animation in " + this + - " @ " + currentTime); - mAnimation = null; - //WindowManagerService.this.dump(); - } - mHasLocalTransformation = false; - if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null - && mAppToken.hasTransformation) { - // When our app token is animating, we kind-of pretend like - // we are as well. Note the mLocalAnimating mAnimationIsEntrance - // part of this check means that we will only do this if - // our window is not currently exiting, or it is not - // locally animating itself. The idea being that one that - // is exiting and doing a local animation should be removed - // once that animation is done. - mAnimating = true; - mHasTransformation = true; - mTransformation.clear(); - return false; - } else if (mHasTransformation) { - // Little trick to get through the path below to act like - // we have finished an animation. - mAnimating = true; - } else if (isAnimating()) { - mAnimating = true; - } - } else if (mAnimation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - mAnimating = true; - mLocalAnimating = true; - mAnimation = null; - } - - if (!mAnimating && !mLocalAnimating) { - return false; - } - - if (DEBUG_ANIM) Log.v( - TAG, "Animation done in " + this + ": exiting=" + mExiting - + ", reportedVisible=" - + (mAppToken != null ? mAppToken.reportedVisible : false)); - - mAnimating = false; - mLocalAnimating = false; - mAnimation = null; - mAnimLayer = mLayer; - if (mIsImWindow) { - mAnimLayer += mInputMethodAnimLayerAdjustment; - } - if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this - + " anim layer: " + mAnimLayer); - mHasTransformation = false; - mHasLocalTransformation = false; - mPolicyVisibility = mPolicyVisibilityAfterAnim; - mTransformation.clear(); - if (mHasDrawn - && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING - && mAppToken != null - && mAppToken.firstWindowDrawn - && mAppToken.startingData != null) { - if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting " - + mToken + ": first real window done animating"); - mFinishedStarting.add(mAppToken); - mH.sendEmptyMessage(H.FINISHED_STARTING); - } - - finishExit(); - - if (mAppToken != null) { - mAppToken.updateReportedVisibilityLocked(); - } - - return false; - } - - void finishExit() { - if (DEBUG_ANIM) Log.v( - TAG, "finishExit in " + this - + ": exiting=" + mExiting - + " remove=" + mRemoveOnExit - + " windowAnimating=" + isWindowAnimating()); - - final int N = mChildWindows.size(); - for (int i=0; i<N; i++) { - ((WindowState)mChildWindows.get(i)).finishExit(); - } - - if (!mExiting) { - return; - } - - if (isWindowAnimating()) { - return; - } - - if (localLOGV) Log.v( - TAG, "Exit animation finished in " + this - + ": remove=" + mRemoveOnExit); - if (mSurface != null) { - mDestroySurface.add(this); - mDestroying = true; - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + mSurface + ": HIDE (finishExit)"); - try { - mSurface.hide(); - } catch (RuntimeException e) { - Log.w(TAG, "Error hiding surface in " + this, e); - } - mLastHidden = true; - mKeyWaiter.releasePendingPointerLocked(mSession); - } - mExiting = false; - if (mRemoveOnExit) { - mPendingRemove.add(this); - mRemoveOnExit = false; - } - } - - boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - if (dsdx < .99999f || dsdx > 1.00001f) return false; - if (dtdy < .99999f || dtdy > 1.00001f) return false; - if (dtdx < -.000001f || dtdx > .000001f) return false; - if (dsdy < -.000001f || dsdy > .000001f) return false; - return true; - } - - void computeShownFrameLocked() { - final boolean selfTransformation = mHasLocalTransformation; - Transformation attachedTransformation = - (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation) - ? mAttachedWindow.mTransformation : null; - Transformation appTransformation = - (mAppToken != null && mAppToken.hasTransformation) - ? mAppToken.transformation : null; - if (selfTransformation || attachedTransformation != null - || appTransformation != null) { - // cache often used attributes locally - final Rect frame = mFrame; - final float tmpFloats[] = mTmpFloats; - final Matrix tmpMatrix = mTmpMatrix; - - // Compute the desired transformation. - tmpMatrix.setTranslate(frame.left, frame.top); - if (selfTransformation) { - tmpMatrix.preConcat(mTransformation.getMatrix()); - } - if (attachedTransformation != null) { - tmpMatrix.preConcat(attachedTransformation.getMatrix()); - } - if (appTransformation != null) { - tmpMatrix.preConcat(appTransformation.getMatrix()); - } - - // "convert" it into SurfaceFlinger's format - // (a 2x2 matrix + an offset) - // Here we must not transform the position of the surface - // since it is already included in the transformation. - //Log.i(TAG, "Transform: " + matrix); - - tmpMatrix.getValues(tmpFloats); - mDsDx = tmpFloats[Matrix.MSCALE_X]; - mDtDx = tmpFloats[Matrix.MSKEW_X]; - mDsDy = tmpFloats[Matrix.MSKEW_Y]; - mDtDy = tmpFloats[Matrix.MSCALE_Y]; - int x = (int)tmpFloats[Matrix.MTRANS_X]; - int y = (int)tmpFloats[Matrix.MTRANS_Y]; - int w = frame.width(); - int h = frame.height(); - mShownFrame.set(x, y, x+w, y+h); - - // Now set the alpha... but because our current hardware - // can't do alpha transformation on a non-opaque surface, - // turn it off if we are running an animation that is also - // transforming since it is more important to have that - // animation be smooth. - mShownAlpha = mAlpha; - if (!mLimitedAlphaCompositing - || (!PixelFormat.formatHasAlpha(mAttrs.format) - || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) - && x == frame.left && y == frame.top))) { - //Log.i(TAG, "Applying alpha transform"); - if (selfTransformation) { - mShownAlpha *= mTransformation.getAlpha(); - } - if (attachedTransformation != null) { - mShownAlpha *= attachedTransformation.getAlpha(); - } - if (appTransformation != null) { - mShownAlpha *= appTransformation.getAlpha(); - } - } else { - //Log.i(TAG, "Not applying alpha transform"); - } - - if (localLOGV) Log.v( - TAG, "Continuing animation in " + this + - ": " + mShownFrame + - ", alpha=" + mTransformation.getAlpha()); - return; - } - - mShownFrame.set(mFrame); - mShownAlpha = mAlpha; - mDsDx = 1; - mDtDx = 0; - mDsDy = 0; - mDtDy = 1; - } - - /** - * Is this window visible? It is not visible if there is no - * surface, or we are in the process of running an exit animation - * that will remove the surface, or its app token has been hidden. - */ - public boolean isVisibleLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested) - && !mExiting && !mDestroying; - } - - /** - * Is this window visible, ignoring its app token? It is not visible - * if there is no surface, or we are in the process of running an exit animation - * that will remove the surface. - */ - public boolean isWinVisibleLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested || atoken.animating) - && !mExiting && !mDestroying; - } - - /** - * The same as isVisible(), but follows the current hidden state of - * the associated app token, not the pending requested hidden state. - */ - boolean isVisibleNow() { - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && !mToken.hidden && !mExiting && !mDestroying; - } - - /** - * Same as isVisible(), but we also count it as visible between the - * call to IWindowSession.add() and the first relayout(). - */ - boolean isVisibleOrAdding() { - final AppWindowToken atoken = mAppToken; - return (mSurface != null - || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) - && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested) - && !mExiting && !mDestroying; - } - - /** - * Is this window currently on-screen? It is on-screen either if it - * is visible or it is currently running an animation before no longer - * being visible. - */ - boolean isOnScreen() { - final AppWindowToken atoken = mAppToken; - if (atoken != null) { - return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && !atoken.hiddenRequested) - || mAnimating || atoken.animating); - } else { - return mSurface != null && mPolicyVisibility && !mDestroying - && (!mAttachedHidden || mAnimating); - } - } - - /** - * Like isOnScreen(), but we don't return true if the window is part - * of a transition that has not yet been started. - */ - boolean isReadyForDisplay() { - final AppWindowToken atoken = mAppToken; - final boolean animating = atoken != null ? atoken.animating : false; - return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && !mToken.hidden) - || mAnimating || animating); - } - - /** Is the window or its container currently animating? */ - boolean isAnimating() { - final WindowState attached = mAttachedWindow; - final AppWindowToken atoken = mAppToken; - return mAnimation != null - || (attached != null && attached.mAnimation != null) - || (atoken != null && - (atoken.animation != null - || atoken.inPendingTransaction)); - } - - /** Is this window currently animating? */ - boolean isWindowAnimating() { - return mAnimation != null; - } - - /** - * Like isOnScreen, but returns false if the surface hasn't yet - * been drawn. - */ - public boolean isDisplayedLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mDestroying - && !mDrawPending && !mCommitDrawPending - && ((!mAttachedHidden && - (atoken == null || !atoken.hiddenRequested)) - || mAnimating); - } - - public boolean fillsScreenLw(int screenWidth, int screenHeight, - boolean shownFrame, boolean onlyOpaque) { - if (mSurface == null) { - return false; - } - if (mAppToken != null && !mAppToken.appFullscreen) { - return false; - } - if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) { - return false; - } - final Rect frame = shownFrame ? mShownFrame : mFrame; - if (frame.left <= 0 && frame.top <= 0 - && frame.right >= screenWidth - && frame.bottom >= screenHeight) { - return true; - } - return false; - } - - boolean isFullscreenOpaque(int screenWidth, int screenHeight) { - if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null - || mAnimation != null || mDrawPending || mCommitDrawPending) { - return false; - } - if (mFrame.left <= 0 && mFrame.top <= 0 && - mFrame.right >= screenWidth && mFrame.bottom >= screenHeight) { - return true; - } - return false; - } - - void removeLocked() { - if (mAttachedWindow != null) { - mAttachedWindow.mChildWindows.remove(this); - } - destroySurfaceLocked(); - mSession.windowRemovedLocked(); - try { - mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); - } catch (RuntimeException e) { - // Ignore if it has already been removed (usually because - // we are doing this as part of processing a death note.) - } - } - - private class DeathRecipient implements IBinder.DeathRecipient { - public void binderDied() { - try { - synchronized(mWindowMap) { - WindowState win = windowForClientLocked(mSession, mClient); - Log.i(TAG, "WIN DEATH: " + win); - if (win != null) { - removeWindowLocked(mSession, win); - } - } - } catch (IllegalArgumentException ex) { - // This will happen if the window has already been - // removed. - } - } - } - - /** Returns true if this window desires key events. */ - public final boolean canReceiveKeys() { - return isVisibleOrAdding() - && (mViewVisibility == View.VISIBLE) - && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0); - } - - public boolean hasDrawnLw() { - return mHasDrawn; - } - - public boolean showLw(boolean doAnimation) { - if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) { - mPolicyVisibility = true; - mPolicyVisibilityAfterAnim = true; - if (doAnimation) { - applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); - } - requestAnimationLocked(0); - return true; - } - return false; - } - - public boolean hideLw(boolean doAnimation) { - boolean current = doAnimation ? mPolicyVisibilityAfterAnim - : mPolicyVisibility; - if (current) { - if (doAnimation) { - applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); - if (mAnimation == null) { - doAnimation = false; - } - } - if (doAnimation) { - mPolicyVisibilityAfterAnim = false; - } else { - mPolicyVisibilityAfterAnim = false; - mPolicyVisibility = false; - } - requestAnimationLocked(0); - return true; - } - return false; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "mSession=" + mSession - + " mClient=" + mClient.asBinder()); - pw.println(prefix + "mAttrs=" + mAttrs); - pw.println(prefix + "mAttachedWindow=" + mAttachedWindow - + " mLayoutAttached=" + mLayoutAttached - + " mIsImWindow=" + mIsImWindow); - pw.println(prefix + "mBaseLayer=" + mBaseLayer - + " mSubLayer=" + mSubLayer - + " mAnimLayer=" + mLayer + "+" - + (mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment - : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)) - + "=" + mAnimLayer - + " mLastLayer=" + mLastLayer); - pw.println(prefix + "mSurface=" + mSurface); - pw.println(prefix + "mToken=" + mToken); - pw.println(prefix + "mAppToken=" + mAppToken); - pw.println(prefix + "mTargetAppToken=" + mTargetAppToken); - pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility) - + " mPolicyVisibility=" + mPolicyVisibility - + " (after=" + mPolicyVisibilityAfterAnim - + ") mAttachedHidden=" + mAttachedHidden - + " mLastHidden=" + mLastHidden - + " mHaveFrame=" + mHaveFrame); - pw.println(prefix + "Requested w=" + mRequestedWidth + " h=" + mRequestedHeight - + " x=" + mReqXPos + " y=" + mReqYPos); - pw.println(prefix + "mGivenContentInsets=" + mGivenContentInsets.toShortString() - + " mGivenVisibleInsets=" + mGivenVisibleInsets.toShortString() - + " mTouchableInsets=" + mTouchableInsets - + " pending=" + mGivenInsetsPending); - pw.println(prefix + "mShownFrame=" + mShownFrame.toShortString() - + " last=" + mLastShownFrame.toShortString()); - pw.println(prefix + "mFrame=" + mFrame.toShortString() - + " last=" + mLastFrame.toShortString()); - pw.println(prefix + "mContainingFrame=" + mContainingFrame.toShortString() - + " mDisplayFrame=" + mDisplayFrame.toShortString()); - pw.println(prefix + "mContentFrame=" + mContentFrame.toShortString() - + " mVisibleFrame=" + mVisibleFrame.toShortString()); - pw.println(prefix + "mContentInsets=" + mContentInsets.toShortString() - + " last=" + mLastContentInsets.toShortString() - + " mVisibleInsets=" + mVisibleInsets.toShortString() - + " last=" + mLastVisibleInsets.toShortString()); - pw.println(prefix + "mShownAlpha=" + mShownAlpha - + " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha); - pw.println(prefix + "mAnimating=" + mAnimating - + " mLocalAnimating=" + mLocalAnimating - + " mAnimationIsEntrance=" + mAnimationIsEntrance - + " mAnimation=" + mAnimation); - pw.println(prefix + "XForm: has=" + mHasTransformation - + " " + mTransformation.toShortString()); - pw.println(prefix + "mDrawPending=" + mDrawPending - + " mCommitDrawPending=" + mCommitDrawPending - + " mReadyToShow=" + mReadyToShow - + " mHasDrawn=" + mHasDrawn); - pw.println(prefix + "mExiting=" + mExiting - + " mRemoveOnExit=" + mRemoveOnExit - + " mDestroying=" + mDestroying - + " mRemoved=" + mRemoved); - pw.println(prefix + "mOrientationChanging=" + mOrientationChanging - + " mAppFreezing=" + mAppFreezing); - } - - @Override - public String toString() { - return "Window{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + mAttrs.getTitle() + "}"; - } - } - - // ------------------------------------------------------------- - // Window Token State - // ------------------------------------------------------------- - - class WindowToken { - // The actual token. - final IBinder token; - - // 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; - - // All of the windows associated with this token. - final ArrayList<WindowState> windows = new ArrayList<WindowState>(); - - // Is key dispatching paused for this token? - boolean paused = false; - - // Should this token's windows be hidden? - boolean hidden; - - // Temporary for finding which tokens no longer have visible windows. - boolean hasVisible; - - WindowToken(IBinder _token, int type, boolean _explicit) { - token = _token; - windowType = type; - explicit = _explicit; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "token=" + token); - pw.println(prefix + "windows=" + windows); - pw.println(prefix + "windowType=" + windowType + " hidden=" + hidden - + " hasVisible=" + hasVisible); - } - - @Override - public String toString() { - return "WindowToken{" - + Integer.toHexString(System.identityHashCode(this)) - + " token=" + token + "}"; - } - }; - - class AppWindowToken extends WindowToken { - // Non-null only for application tokens. - final IApplicationToken appToken; - - // All of the windows and child windows that are included in this - // application token. Note this list is NOT sorted! - final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>(); - - int groupId = -1; - boolean appFullscreen; - int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - - // These are used for determining when all windows associated with - // an activity have been drawn, so they can be made visible together - // at the same time. - int lastTransactionSequence = mTransactionSequence-1; - int numInterestingWindows; - int numDrawnWindows; - boolean inPendingTransaction; - boolean allDrawn; - - // Is this token going to be hidden in a little while? If so, it - // won't be taken into account for setting the screen orientation. - boolean willBeHidden; - - // Is this window's surface needed? This is almost like hidden, except - // it will sometimes be true a little earlier: when the token has - // been shown, but is still waiting for its app transition to execute - // before making its windows shown. - boolean hiddenRequested; - - // Have we told the window clients to hide themselves? - boolean clientHidden; - - // Last visibility state we reported to the app token. - boolean reportedVisible; - - // Set to true when the token has been removed from the window mgr. - boolean removed; - - // Have we been asked to have this token keep the screen frozen? - boolean freezingScreen; - - boolean animating; - Animation animation; - boolean hasTransformation; - final Transformation transformation = new Transformation(); - - // Offset to the window of all layers in the token, for use by - // AppWindowToken animations. - int animLayerAdjustment; - - // Information about an application starting window if displayed. - StartingData startingData; - WindowState startingWindow; - View startingView; - boolean startingDisplayed; - boolean startingMoved; - boolean firstWindowDrawn; - - AppWindowToken(IApplicationToken _token) { - super(_token.asBinder(), - WindowManager.LayoutParams.TYPE_APPLICATION, true); - appWindowToken = this; - appToken = _token; - } - - public void setAnimation(Animation anim) { - if (localLOGV) Log.v( - TAG, "Setting animation in " + this + ": " + anim); - animation = anim; - animating = false; - anim.restrictDuration(MAX_ANIMATION_DURATION); - anim.scaleCurrentDuration(mTransitionAnimationScale); - int zorder = anim.getZAdjustment(); - int adj = 0; - if (zorder == Animation.ZORDER_TOP) { - adj = TYPE_LAYER_OFFSET; - } else if (zorder == Animation.ZORDER_BOTTOM) { - adj = -TYPE_LAYER_OFFSET; - } - - if (animLayerAdjustment != adj) { - animLayerAdjustment = adj; - updateLayers(); - } - } - - public void setDummyAnimation() { - if (animation == null) { - if (localLOGV) Log.v( - TAG, "Setting dummy animation in " + this); - animation = sDummyAnimation; - } - } - - public void clearAnimation() { - if (animation != null) { - animation = null; - animating = true; - } - } - - void updateLayers() { - final int N = allAppWindows.size(); - final int adj = animLayerAdjustment; - for (int i=0; i<N; i++) { - WindowState w = allAppWindows.get(i); - w.mAnimLayer = w.mLayer + adj; - if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": " - + w.mAnimLayer); - if (w == mInputMethodTarget) { - setInputMethodAnimLayerAdjustment(adj); - } - } - } - - void sendAppVisibilityToClients() { - final int N = allAppWindows.size(); - for (int i=0; i<N; i++) { - WindowState win = allAppWindows.get(i); - if (win == startingWindow && clientHidden) { - // Don't hide the starting window. - continue; - } - try { - if (DEBUG_VISIBILITY) Log.v(TAG, - "Setting visibility of " + win + ": " + (!clientHidden)); - win.mClient.dispatchAppVisibility(!clientHidden); - } catch (RemoteException e) { - } - } - } - - void showAllWindowsLocked() { - final int NW = allAppWindows.size(); - for (int i=0; i<NW; i++) { - WindowState w = allAppWindows.get(i); - if (DEBUG_VISIBILITY) Log.v(TAG, - "performing show on: " + w); - w.performShowLocked(); - } - } - - // This must be called while inside a transaction. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!mDisplayFrozen) { - // We will run animations as long as the display isn't frozen. - - if (animation == sDummyAnimation) { - // This guy is going to animate, but not yet. For now count - // it is not animating for purposes of scheduling transactions; - // when it is really time to animate, this will be set to - // a real animation and the next call will execute normally. - return false; - } - - if ((allDrawn || animating || startingDisplayed) && animation != null) { - if (!animating) { - if (DEBUG_ANIM) Log.v( - TAG, "Starting animation in " + this + - " @ " + currentTime + ": dw=" + dw + " dh=" + dh - + " scale=" + mTransitionAnimationScale - + " allDrawn=" + allDrawn + " animating=" + animating); - animation.initialize(dw, dh, dw, dh); - animation.setStartTime(currentTime); - animating = true; - } - transformation.clear(); - final boolean more = animation.getTransformation( - currentTime, transformation); - if (DEBUG_ANIM) Log.v( - TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + transformation); - if (more) { - // we're done! - hasTransformation = true; - return true; - } - if (DEBUG_ANIM) Log.v( - TAG, "Finished animation in " + this + - " @ " + currentTime); - animation = null; - } - } else if (animation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - animating = true; - animation = null; - } - - hasTransformation = false; - - if (!animating) { - return false; - } - - clearAnimation(); - animating = false; - if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) { - moveInputMethodWindowsIfNeededLocked(true); - } - - if (DEBUG_ANIM) Log.v( - TAG, "Animation done in " + this - + ": reportedVisible=" + reportedVisible); - - transformation.clear(); - if (animLayerAdjustment != 0) { - animLayerAdjustment = 0; - updateLayers(); - } - - final int N = windows.size(); - for (int i=0; i<N; i++) { - ((WindowState)windows.get(i)).finishExit(); - } - updateReportedVisibilityLocked(); - - return false; - } - - void updateReportedVisibilityLocked() { - if (appToken == null) { - return; - } - - int numInteresting = 0; - int numVisible = 0; - boolean nowGone = true; - - if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this); - final int N = allAppWindows.size(); - for (int i=0; i<N; i++) { - WindowState win = allAppWindows.get(i); - if (win == startingWindow || win.mAppFreezing) { - continue; - } - if (DEBUG_VISIBILITY) { - Log.v(TAG, "Win " + win + ": isDisplayed=" - + win.isDisplayedLw() - + ", isAnimating=" + win.isAnimating()); - if (!win.isDisplayedLw()) { - Log.v(TAG, "Not displayed: s=" + win.mSurface - + " pv=" + win.mPolicyVisibility - + " dp=" + win.mDrawPending - + " cdp=" + win.mCommitDrawPending - + " ah=" + win.mAttachedHidden - + " th=" - + (win.mAppToken != null - ? win.mAppToken.hiddenRequested : false) - + " a=" + win.mAnimating); - } - } - numInteresting++; - if (win.isDisplayedLw()) { - if (!win.isAnimating()) { - numVisible++; - } - nowGone = false; - } else if (win.isAnimating()) { - nowGone = false; - } - } - - boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; - if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting=" - + numInteresting + " visible=" + numVisible); - if (nowVisible != reportedVisible) { - if (DEBUG_VISIBILITY) Log.v( - TAG, "Visibility changed in " + this - + ": vis=" + nowVisible); - reportedVisible = nowVisible; - Message m = mH.obtainMessage( - H.REPORT_APPLICATION_TOKEN_WINDOWS, - nowVisible ? 1 : 0, - nowGone ? 1 : 0, - this); - mH.sendMessage(m); - } - } - - void dump(PrintWriter pw, String prefix) { - super.dump(pw, prefix); - pw.println(prefix + "app=" + (appToken != null)); - pw.println(prefix + "allAppWindows=" + allAppWindows); - pw.println(prefix + "groupId=" + groupId - + " requestedOrientation=" + requestedOrientation); - pw.println(prefix + "hiddenRequested=" + hiddenRequested - + " clientHidden=" + clientHidden - + " willBeHidden=" + willBeHidden - + " reportedVisible=" + reportedVisible); - pw.println(prefix + "paused=" + paused - + " freezingScreen=" + freezingScreen); - pw.println(prefix + "numInterestingWindows=" + numInterestingWindows - + " numDrawnWindows=" + numDrawnWindows - + " inPendingTransaction=" + inPendingTransaction - + " allDrawn=" + allDrawn); - pw.println(prefix + "animating=" + animating - + " animation=" + animation); - pw.println(prefix + "animLayerAdjustment=" + animLayerAdjustment - + " transformation=" + transformation.toShortString()); - pw.println(prefix + "startingData=" + startingData - + " removed=" + removed - + " firstWindowDrawn=" + firstWindowDrawn); - pw.println(prefix + "startingWindow=" + startingWindow - + " startingView=" + startingView - + " startingDisplayed=" + startingDisplayed - + " startingMoved" + startingMoved); - } - - @Override - public String toString() { - return "AppWindowToken{" - + Integer.toHexString(System.identityHashCode(this)) - + " token=" + token + "}"; - } - } - - public static WindowManager.LayoutParams findAnimations( - ArrayList<AppWindowToken> order, - ArrayList<AppWindowToken> tokenList1, - ArrayList<AppWindowToken> tokenList2) { - // We need to figure out which animation to use... - WindowManager.LayoutParams animParams = null; - int animSrc = 0; - - //Log.i(TAG, "Looking for animations..."); - for (int i=order.size()-1; i>=0; i--) { - AppWindowToken wtoken = order.get(i); - //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows"); - if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) { - int j = wtoken.windows.size(); - while (j > 0) { - j--; - WindowState win = wtoken.windows.get(j); - //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type); - if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION - || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { - //Log.i(TAG, "Found base or application window, done!"); - if (wtoken.appFullscreen) { - return win.mAttrs; - } - if (animSrc < 2) { - animParams = win.mAttrs; - animSrc = 2; - } - } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) { - //Log.i(TAG, "Found normal window, we may use this..."); - animParams = win.mAttrs; - animSrc = 1; - } - } - } - } - - return animParams; - } - - // ------------------------------------------------------------- - // DummyAnimation - // ------------------------------------------------------------- - - // This is an animation that does nothing: it just immediately finishes - // itself every time it is called. It is used as a stub animation in cases - // where we want to synchronize multiple things that may be animating. - static final class DummyAnimation extends Animation { - public boolean getTransformation(long currentTime, Transformation outTransformation) { - return false; - } - } - static final Animation sDummyAnimation = new DummyAnimation(); - - // ------------------------------------------------------------- - // Async Handler - // ------------------------------------------------------------- - - static final class StartingData { - final String pkg; - final int theme; - final CharSequence nonLocalizedLabel; - final int labelRes; - final int icon; - - StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel, - int _labelRes, int _icon) { - pkg = _pkg; - theme = _theme; - nonLocalizedLabel = _nonLocalizedLabel; - labelRes = _labelRes; - icon = _icon; - } - } - - private final class H extends Handler { - public static final int REPORT_FOCUS_CHANGE = 2; - public static final int REPORT_LOSING_FOCUS = 3; - public static final int ANIMATE = 4; - public static final int ADD_STARTING = 5; - public static final int REMOVE_STARTING = 6; - public static final int FINISHED_STARTING = 7; - public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8; - public static final int UPDATE_ORIENTATION = 10; - public static final int WINDOW_FREEZE_TIMEOUT = 11; - public static final int HOLD_SCREEN_CHANGED = 12; - public static final int APP_TRANSITION_TIMEOUT = 13; - public static final int PERSIST_ANIMATION_SCALE = 14; - public static final int FORCE_GC = 15; - public static final int ENABLE_SCREEN = 16; - public static final int APP_FREEZE_TIMEOUT = 17; - - private Session mLastReportedHold; - - public H() { - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case REPORT_FOCUS_CHANGE: { - WindowState lastFocus; - WindowState newFocus; - - 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); - if (newFocus != null && lastFocus != null - && !newFocus.isDisplayedLw()) { - //Log.i(TAG, "Delaying loss of focus..."); - mLosingFocus.add(lastFocus); - lastFocus = null; - } - } - - if (lastFocus != newFocus) { - //System.out.println("Changing focus from " + lastFocus - // + " to " + newFocus); - if (newFocus != null) { - try { - //Log.i(TAG, "Gaining focus: " + newFocus); - newFocus.mClient.windowFocusChanged(true, mInTouchMode); - } catch (RemoteException e) { - // Ignore if process has died. - } - } - - if (lastFocus != null) { - try { - //Log.i(TAG, "Losing focus: " + lastFocus); - lastFocus.mClient.windowFocusChanged(false, mInTouchMode); - } catch (RemoteException e) { - // Ignore if process has died. - } - } - } - } break; - - case REPORT_LOSING_FOCUS: { - ArrayList<WindowState> losers; - - synchronized(mWindowMap) { - losers = mLosingFocus; - mLosingFocus = new ArrayList<WindowState>(); - } - - final int N = losers.size(); - for (int i=0; i<N; i++) { - try { - //Log.i(TAG, "Losing delayed focus: " + losers.get(i)); - losers.get(i).mClient.windowFocusChanged(false, mInTouchMode); - } catch (RemoteException e) { - // Ignore if process has died. - } - } - } break; - - case ANIMATE: { - synchronized(mWindowMap) { - mAnimationPending = false; - performLayoutAndPlaceSurfacesLocked(); - } - } break; - - case ADD_STARTING: { - final AppWindowToken wtoken = (AppWindowToken)msg.obj; - final StartingData sd = wtoken.startingData; - - if (sd == null) { - // Animation has been canceled... do nothing. - return; - } - - if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting " - + wtoken + ": pkg=" + sd.pkg); - - View view = null; - try { - view = mPolicy.addStartingWindow( - wtoken.token, sd.pkg, - sd.theme, sd.nonLocalizedLabel, sd.labelRes, - sd.icon); - } catch (Exception e) { - Log.w(TAG, "Exception when adding starting window", e); - } - - if (view != null) { - boolean abort = false; - - synchronized(mWindowMap) { - if (wtoken.removed || wtoken.startingData == null) { - // If the window was successfully added, then - // we need to remove it. - if (wtoken.startingWindow != null) { - if (DEBUG_STARTING_WINDOW) Log.v(TAG, - "Aborted starting " + wtoken - + ": removed=" + wtoken.removed - + " startingData=" + wtoken.startingData); - wtoken.startingWindow = null; - wtoken.startingData = null; - abort = true; - } - } else { - wtoken.startingView = view; - } - if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG, - "Added starting " + wtoken - + ": startingWindow=" - + wtoken.startingWindow + " startingView=" - + wtoken.startingView); - } - - if (abort) { - try { - mPolicy.removeStartingWindow(wtoken.token, view); - } catch (Exception e) { - Log.w(TAG, "Exception when removing starting window", e); - } - } - } - } break; - - case REMOVE_STARTING: { - final AppWindowToken wtoken = (AppWindowToken)msg.obj; - IBinder token = null; - View view = null; - synchronized (mWindowMap) { - if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting " - + wtoken + ": startingWindow=" - + wtoken.startingWindow + " startingView=" - + wtoken.startingView); - if (wtoken.startingWindow != null) { - view = wtoken.startingView; - token = wtoken.token; - wtoken.startingData = null; - wtoken.startingView = null; - wtoken.startingWindow = null; - } - } - if (view != null) { - try { - mPolicy.removeStartingWindow(token, view); - } catch (Exception e) { - Log.w(TAG, "Exception when removing starting window", e); - } - } - } break; - - case FINISHED_STARTING: { - IBinder token = null; - View view = null; - while (true) { - synchronized (mWindowMap) { - final int N = mFinishedStarting.size(); - if (N <= 0) { - break; - } - AppWindowToken wtoken = mFinishedStarting.remove(N-1); - - if (DEBUG_STARTING_WINDOW) Log.v(TAG, - "Finished starting " + wtoken - + ": startingWindow=" + wtoken.startingWindow - + " startingView=" + wtoken.startingView); - - if (wtoken.startingWindow == null) { - continue; - } - - view = wtoken.startingView; - token = wtoken.token; - wtoken.startingData = null; - wtoken.startingView = null; - wtoken.startingWindow = null; - } - - try { - mPolicy.removeStartingWindow(token, view); - } catch (Exception e) { - Log.w(TAG, "Exception when removing starting window", e); - } - } - } break; - - case REPORT_APPLICATION_TOKEN_WINDOWS: { - final AppWindowToken wtoken = (AppWindowToken)msg.obj; - - boolean nowVisible = msg.arg1 != 0; - boolean nowGone = msg.arg2 != 0; - - try { - if (DEBUG_VISIBILITY) Log.v( - TAG, "Reporting visible in " + wtoken - + " visible=" + nowVisible - + " gone=" + nowGone); - if (nowVisible) { - wtoken.appToken.windowsVisible(); - } else { - wtoken.appToken.windowsGone(); - } - } catch (RemoteException ex) { - } - } break; - - case UPDATE_ORIENTATION: { - setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false); - break; - } - - case WINDOW_FREEZE_TIMEOUT: { - synchronized (mWindowMap) { - Log.w(TAG, "Window freeze timeout expired."); - int i = mWindows.size(); - while (i > 0) { - i--; - WindowState w = (WindowState)mWindows.get(i); - if (w.mOrientationChanging) { - w.mOrientationChanging = false; - Log.w(TAG, "Force clearing orientation change: " + w); - } - } - performLayoutAndPlaceSurfacesLocked(); - } - break; - } - - case HOLD_SCREEN_CHANGED: { - Session oldHold; - Session newHold; - synchronized (mWindowMap) { - oldHold = mLastReportedHold; - newHold = (Session)msg.obj; - mLastReportedHold = newHold; - } - - if (oldHold != newHold) { - try { - if (oldHold != null) { - mBatteryStats.noteStopWakelock(oldHold.mUid, - "window", - BatteryStats.WAKE_TYPE_WINDOW); - } - if (newHold != null) { - mBatteryStats.noteStartWakelock(newHold.mUid, - "window", - BatteryStats.WAKE_TYPE_WINDOW); - } - } catch (RemoteException e) { - } - } - break; - } - - case APP_TRANSITION_TIMEOUT: { - synchronized (mWindowMap) { - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, - "*** APP TRANSITION TIMEOUT"); - mAppTransitionReady = true; - mAppTransitionTimeout = true; - performLayoutAndPlaceSurfacesLocked(); - } - } - break; - } - - case PERSIST_ANIMATION_SCALE: { - Settings.System.putFloat(mContext.getContentResolver(), - Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); - Settings.System.putFloat(mContext.getContentResolver(), - Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); - break; - } - - case FORCE_GC: { - synchronized(mWindowMap) { - if (mAnimationPending) { - // If we are animating, don't do the gc now but - // delay a bit so we don't interrupt the animation. - mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), - 2000); - return; - } - // If we are currently rotating the display, it will - // schedule a new message when done. - if (mDisplayFrozen) { - return; - } - mFreezeGcPending = 0; - } - Runtime.getRuntime().gc(); - break; - } - - case ENABLE_SCREEN: { - performEnableScreen(); - break; - } - - case APP_FREEZE_TIMEOUT: { - synchronized (mWindowMap) { - Log.w(TAG, "App freeze timeout expired."); - int i = mAppTokens.size(); - while (i > 0) { - i--; - AppWindowToken tok = mAppTokens.get(i); - if (tok.freezingScreen) { - Log.w(TAG, "Force clearing freeze: " + tok); - unsetAppFreezingScreenLocked(tok, true, true); - } - } - } - break; - } - - } - } - } - - // ------------------------------------------------------------- - // IWindowManager API - // ------------------------------------------------------------- - - public IWindowSession openSession(IInputMethodClient client, - IInputContext inputContext) { - if (client == null) throw new IllegalArgumentException("null client"); - if (inputContext == null) throw new IllegalArgumentException("null inputContext"); - return new Session(client, inputContext); - } - - public boolean inputMethodClientHasFocus(IInputMethodClient client) { - synchronized (mWindowMap) { - // The focus for the client is the window immediately below - // where we would place the input method window. - int idx = findDesiredInputMethodWindowIndexLocked(false); - WindowState imFocus; - if (idx > 0) { - imFocus = (WindowState)mWindows.get(idx-1); - if (imFocus != null) { - if (imFocus.mSession.mClient != null && - imFocus.mSession.mClient.asBinder() == client.asBinder()) { - return true; - } - } - } - } - return false; - } - - // ------------------------------------------------------------- - // Internals - // ------------------------------------------------------------- - - final WindowState windowForClientLocked(Session session, IWindow client) { - return windowForClientLocked(session, client.asBinder()); - } - - final WindowState windowForClientLocked(Session session, IBinder client) { - WindowState win = mWindowMap.get(client); - if (localLOGV) Log.v( - TAG, "Looking up client " + client + ": " + win); - if (win == null) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " does not exist", ex); - return null; - } - if (session != null && win.mSession != session) { - RuntimeException ex = new RuntimeException(); - Log.w(TAG, "Requested window " + client + " is in session " + - win.mSession + ", not " + session, ex); - return null; - } - - return win; - } - - private final void assignLayersLocked() { - int N = mWindows.size(); - int curBaseLayer = 0; - int curLayer = 0; - int i; - - for (i=0; i<N; i++) { - WindowState w = (WindowState)mWindows.get(i); - if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) { - curLayer += WINDOW_LAYER_MULTIPLIER; - w.mLayer = curLayer; - } else { - curBaseLayer = curLayer = w.mBaseLayer; - w.mLayer = curLayer; - } - if (w.mTargetAppToken != null) { - w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment; - } else if (w.mAppToken != null) { - w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment; - } 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()); - } - } - - private boolean mInLayout = false; - private final void performLayoutAndPlaceSurfacesLocked() { - if (mInLayout) { - if (Config.DEBUG) { - throw new RuntimeException("Recursive call!"); - } - Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout"); - return; - } - - boolean recoveringMemory = false; - if (mForceRemoves != null) { - recoveringMemory = true; - // Wait a little it for things to settle down, and off we go. - for (int i=0; i<mForceRemoves.size(); i++) { - WindowState ws = mForceRemoves.get(i); - Log.i(TAG, "Force removing: " + ws); - removeWindowInnerLocked(ws.mSession, ws); - } - mForceRemoves = null; - Log.w(TAG, "Due to memory failure, waiting a bit for next layout"); - Object tmp = new Object(); - synchronized (tmp) { - try { - tmp.wait(250); - } catch (InterruptedException e) { - } - } - } - - mInLayout = true; - try { - performLayoutAndPlaceSurfacesLockedInner(recoveringMemory); - - int i = mPendingRemove.size()-1; - if (i >= 0) { - while (i >= 0) { - WindowState w = mPendingRemove.get(i); - removeWindowInnerLocked(w.mSession, w); - i--; - } - mPendingRemove.clear(); - - mInLayout = false; - assignLayersLocked(); - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - - } else { - mInLayout = false; - if (mLayoutNeeded) { - requestAnimationLocked(0); - } - } - } catch (RuntimeException e) { - mInLayout = false; - Log.e(TAG, "Unhandled exception while layout out windows", e); - } - } - - private final void performLayoutLockedInner() { - final int dw = mDisplay.getWidth(); - final int dh = mDisplay.getHeight(); - - final int N = mWindows.size(); - int i; - - // FIRST LOOP: Perform a layout, if needed. - - if (mLayoutNeeded) { - mPolicy.beginLayoutLw(dw, dh); - - // First perform layout of any root windows (not attached - // to another window). - int topAttached = -1; - for (i = N-1; i >= 0; i--) { - WindowState win = (WindowState) mWindows.get(i); - - boolean gone = win.mViewVisibility == View.GONE - || !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 - // if they want. (We do the normal layout for INVISIBLE - // windows, since that means "perform layout as normal, - // just don't display"). - if (!gone || !win.mHaveFrame) { - if (!win.mLayoutAttached) { - mPolicy.layoutWindowLw(win, win.mAttrs, null); - } else { - if (topAttached < 0) topAttached = i; - } - } - } - - // Now perform layout of attached windows, which usually - // depend on the position of the window they are attached to. - // XXX does not deal with windows that are attached to windows - // that are themselves attached. - for (i = topAttached; i >= 0; i--) { - WindowState win = (WindowState) mWindows.get(i); - - // If this view is GONE, then skip it -- keep the current - // frame, and let the caller know so they can ignore it - // if they want. (We do the normal layout for INVISIBLE - // windows, since that means "perform layout as normal, - // just don't display"). - if (win.mLayoutAttached) { - if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) - || !win.mHaveFrame) { - mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); - } - } - } - - mPolicy.finishLayoutLw(); - mLayoutNeeded = false; - } - } - - private final void performLayoutAndPlaceSurfacesLockedInner( - boolean recoveringMemory) { - final long currentTime = SystemClock.uptimeMillis(); - final int dw = mDisplay.getWidth(); - final int dh = mDisplay.getHeight(); - - final int N = mWindows.size(); - int i; - - // FIRST LOOP: Perform a layout, if needed. - - performLayoutLockedInner(); - - if (mFxSession == null) { - mFxSession = new SurfaceSession(); - } - - if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION"); - - // Initialize state of exiting tokens. - for (i=mExitingTokens.size()-1; i>=0; i--) { - mExitingTokens.get(i).hasVisible = false; - } - - // Initialize state of exiting applications. - for (i=mExitingAppTokens.size()-1; i>=0; i--) { - mExitingAppTokens.get(i).hasVisible = false; - } - - // SECOND LOOP: Execute animations and update visibility of windows. - - boolean orientationChangeComplete = true; - Session holdScreen = null; - float screenBrightness = -1; - boolean focusDisplayed = false; - boolean animating = false; - - Surface.openTransaction(); - try { - boolean restart; - - do { - final int transactionSequence = ++mTransactionSequence; - - // Update animations of all applications, including those - // associated with exiting/removed apps - boolean tokensAnimating = false; - final int NAT = mAppTokens.size(); - for (i=0; i<NAT; i++) { - if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) { - tokensAnimating = true; - } - } - final int NEAT = mExitingAppTokens.size(); - for (i=0; i<NEAT; i++) { - if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) { - tokensAnimating = true; - } - } - - animating = tokensAnimating; - restart = false; - - boolean tokenMayBeDrawn = false; - - mPolicy.beginAnimationLw(dw, dh); - - for (i=N-1; i>=0; i--) { - WindowState w = (WindowState)mWindows.get(i); - - final WindowManager.LayoutParams attrs = w.mAttrs; - - if (w.mSurface != null) { - // Execute animation. - w.commitFinishDrawingLocked(currentTime); - if (w.stepAnimationLocked(currentTime, dw, dh)) { - animating = true; - //w.dump(" "); - } - - mPolicy.animatingWindowLw(w, attrs); - } - - final AppWindowToken atoken = w.mAppToken; - if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) { - if (atoken.lastTransactionSequence != transactionSequence) { - atoken.lastTransactionSequence = transactionSequence; - atoken.numInterestingWindows = atoken.numDrawnWindows = 0; - atoken.startingDisplayed = false; - } - if ((w.isOnScreen() || w.mAttrs.type - == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) - && !w.mExiting && !w.mDestroying) { - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { - Log.v(TAG, "Eval win " + w + ": isDisplayed=" - + w.isDisplayedLw() - + ", isAnimating=" + w.isAnimating()); - if (!w.isDisplayedLw()) { - Log.v(TAG, "Not displayed: s=" + w.mSurface - + " pv=" + w.mPolicyVisibility - + " dp=" + w.mDrawPending - + " cdp=" + w.mCommitDrawPending - + " ah=" + w.mAttachedHidden - + " th=" + atoken.hiddenRequested - + " a=" + w.mAnimating); - } - } - if (w != atoken.startingWindow) { - if (!atoken.freezingScreen || !w.mAppFreezing) { - atoken.numInterestingWindows++; - if (w.isDisplayedLw()) { - atoken.numDrawnWindows++; - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG, - "tokenMayBeDrawn: " + atoken - + " freezingScreen=" + atoken.freezingScreen - + " mAppFreezing=" + w.mAppFreezing); - tokenMayBeDrawn = true; - } - } - } else if (w.isDisplayedLw()) { - atoken.startingDisplayed = true; - } - } - } else if (w.mReadyToShow) { - w.performShowLocked(); - } - } - - if (mPolicy.finishAnimationLw()) { - restart = true; - } - - if (tokenMayBeDrawn) { - // See if any windows have been drawn, so they (and others - // associated with them) can now be shown. - final int NT = mTokenList.size(); - for (i=0; i<NT; i++) { - AppWindowToken wtoken = mTokenList.get(i).appWindowToken; - if (wtoken == null) { - continue; - } - if (wtoken.freezingScreen) { - int numInteresting = wtoken.numInterestingWindows; - if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { - if (DEBUG_VISIBILITY) Log.v(TAG, - "allDrawn: " + wtoken - + " interesting=" + numInteresting - + " drawn=" + wtoken.numDrawnWindows); - wtoken.showAllWindowsLocked(); - unsetAppFreezingScreenLocked(wtoken, false, true); - orientationChangeComplete = true; - } - } else if (!wtoken.allDrawn) { - int numInteresting = wtoken.numInterestingWindows; - if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { - if (DEBUG_VISIBILITY) Log.v(TAG, - "allDrawn: " + wtoken - + " interesting=" + numInteresting - + " drawn=" + wtoken.numDrawnWindows); - wtoken.allDrawn = true; - restart = true; - - // We can now show all of the drawn windows! - if (!mOpeningApps.contains(wtoken)) { - wtoken.showAllWindowsLocked(); - } - } - } - } - } - - // If we are ready to perform an app transition, check through - // all of the app tokens to be shown and see if they are ready - // to go. - if (mAppTransitionReady) { - int NN = mOpeningApps.size(); - boolean goodToGo = true; - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, - "Checking " + NN + " opening apps (frozen=" - + mDisplayFrozen + " timeout=" - + mAppTransitionTimeout + ")..."); - if (!mDisplayFrozen && !mAppTransitionTimeout) { - // If the display isn't frozen, wait to do anything until - // all of the apps are ready. Otherwise just go because - // we'll unfreeze the display when everyone is ready. - for (i=0; i<NN && goodToGo; i++) { - AppWindowToken wtoken = mOpeningApps.get(i); - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, - "Check opening app" + wtoken + ": allDrawn=" - + wtoken.allDrawn + " startingDisplayed=" - + wtoken.startingDisplayed); - if (!wtoken.allDrawn && !wtoken.startingDisplayed - && !wtoken.startingMoved) { - goodToGo = false; - } - } - } - if (goodToGo) { - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO"); - int transit = mNextAppTransition; - if (mSkipAppTransitionAnimation) { - transit = WindowManagerPolicy.TRANSIT_NONE; - } - mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE; - mAppTransitionReady = false; - mAppTransitionTimeout = false; - mStartingIconInTransition = false; - mSkipAppTransitionAnimation = false; - - mH.removeMessages(H.APP_TRANSITION_TIMEOUT); - - // We need to figure out which animation to use... - WindowManager.LayoutParams lp = findAnimations(mAppTokens, - mOpeningApps, mClosingApps); - - NN = mOpeningApps.size(); - for (i=0; i<NN; i++) { - AppWindowToken wtoken = mOpeningApps.get(i); - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, - "Now opening app" + wtoken); - wtoken.reportedVisible = false; - wtoken.inPendingTransaction = false; - setTokenVisibilityLocked(wtoken, lp, true, transit, false); - wtoken.updateReportedVisibilityLocked(); - wtoken.showAllWindowsLocked(); - } - NN = mClosingApps.size(); - for (i=0; i<NN; i++) { - AppWindowToken wtoken = mClosingApps.get(i); - if (DEBUG_APP_TRANSITIONS) Log.v(TAG, - "Now closing app" + wtoken); - wtoken.inPendingTransaction = false; - setTokenVisibilityLocked(wtoken, lp, false, transit, false); - wtoken.updateReportedVisibilityLocked(); - // Force the allDrawn flag, because we want to start - // this guy's animations regardless of whether it's - // gotten drawn. - wtoken.allDrawn = true; - } - - mOpeningApps.clear(); - mClosingApps.clear(); - - // 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); - - restart = true; - } - } - } while (restart); - - // THIRD LOOP: Update the surfaces of all windows. - - final boolean someoneLosingFocus = mLosingFocus.size() != 0; - - boolean obscured = false; - boolean blurring = false; - boolean dimming = false; - boolean covered = false; - - for (i=N-1; i>=0; i--) { - WindowState w = (WindowState)mWindows.get(i); - - boolean displayed = false; - final WindowManager.LayoutParams attrs = w.mAttrs; - final int attrFlags = attrs.flags; - - if (w.mSurface != null) { - w.computeShownFrameLocked(); - if (localLOGV) Log.v( - TAG, "Placing surface #" + i + " " + w.mSurface - + ": new=" + w.mShownFrame + ", old=" - + w.mLastShownFrame); - - boolean resize; - int width, height; - if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) { - resize = w.mLastRequestedWidth != w.mRequestedWidth || - w.mLastRequestedHeight != w.mRequestedHeight; - // for a scaled surface, we just want to use - // the requested size. - width = w.mRequestedWidth; - height = w.mRequestedHeight; - w.mLastRequestedWidth = width; - w.mLastRequestedHeight = height; - w.mLastShownFrame.set(w.mShownFrame); - try { - w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top); - } catch (RuntimeException e) { - Log.w(TAG, "Error positioning surface in " + w, e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "position"); - } - } - } else { - resize = !w.mLastShownFrame.equals(w.mShownFrame); - width = w.mShownFrame.width(); - height = w.mShownFrame.height(); - w.mLastShownFrame.set(w.mShownFrame); - if (resize) { - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + w.mSurface + ": (" - + w.mShownFrame.left + "," - + w.mShownFrame.top + ") (" - + w.mShownFrame.width() + "x" - + w.mShownFrame.height() + ")"); - } - } - - if (resize) { - if (width < 1) width = 1; - if (height < 1) height = 1; - if (w.mSurface != null) { - try { - w.mSurface.setSize(width, height); - w.mSurface.setPosition(w.mShownFrame.left, - w.mShownFrame.top); - } catch (RuntimeException e) { - // If something goes wrong with the surface (such - // as running out of memory), don't take down the - // entire system. - Log.e(TAG, "Failure updating surface of " + w - + "size=(" + width + "x" + height - + "), pos=(" + w.mShownFrame.left - + "," + w.mShownFrame.top + ")", e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "size"); - } - } - } - } - if (!w.mAppFreezing) { - w.mContentInsetsChanged = - !w.mLastContentInsets.equals(w.mContentInsets); - w.mVisibleInsetsChanged = - !w.mLastVisibleInsets.equals(w.mVisibleInsets); - if (!w.mLastFrame.equals(w.mFrame) - || w.mContentInsetsChanged - || w.mVisibleInsetsChanged) { - w.mLastFrame.set(w.mFrame); - w.mLastContentInsets.set(w.mContentInsets); - w.mLastVisibleInsets.set(w.mVisibleInsets); - // If the orientation is changing, then we need to - // hold off on unfreezing the display until this - // window has been redrawn; to do that, we need - // to go through the process of getting informed - // by the application when it has finished drawing. - if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation start waiting for draw in " - + w + ", surface " + w.mSurface); - w.mDrawPending = true; - w.mCommitDrawPending = false; - w.mReadyToShow = false; - if (w.mAppToken != null) { - w.mAppToken.allDrawn = false; - } - } - if (DEBUG_ORIENTATION) Log.v(TAG, - "Resizing window " + w + " to " + w.mFrame); - mResizingWindows.add(w); - } else if (w.mOrientationChanging) { - if (!w.mDrawPending && !w.mCommitDrawPending) { - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation not waiting for draw in " - + w + ", surface " + w.mSurface); - w.mOrientationChanging = false; - } - } - } - - if (w.mAttachedHidden) { - if (!w.mLastHidden) { - //dump(); - w.mLastHidden = true; - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-attached)"); - if (w.mSurface != null) { - try { - w.mSurface.hide(); - } catch (RuntimeException e) { - Log.w(TAG, "Exception hiding surface in " + w); - } - } - mKeyWaiter.releasePendingPointerLocked(w.mSession); - } - // If we are waiting for this window to handle an - // orientation change, well, it is hidden, so - // doesn't really matter. Note that this does - // introduce a potential glitch if the window - // becomes unhidden before it has drawn for the - // new orientation. - if (w.mOrientationChanging) { - w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation change skips hidden " + w); - } - } else if (!w.isReadyForDisplay()) { - if (!w.mLastHidden) { - //dump(); - w.mLastHidden = true; - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout-ready)"); - if (w.mSurface != null) { - try { - w.mSurface.hide(); - } catch (RuntimeException e) { - Log.w(TAG, "Exception exception hiding surface in " + w); - } - } - mKeyWaiter.releasePendingPointerLocked(w.mSession); - } - // If we are waiting for this window to handle an - // orientation change, well, it is hidden, so - // doesn't really matter. Note that this does - // introduce a potential glitch if the window - // becomes unhidden before it has drawn for the - // new orientation. - if (w.mOrientationChanging) { - w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation change skips hidden " + w); - } - } else if (w.mLastLayer != w.mAnimLayer - || w.mLastAlpha != w.mShownAlpha - || w.mLastDsDx != w.mDsDx - || w.mLastDtDx != w.mDtDx - || w.mLastDsDy != w.mDsDy - || w.mLastDtDy != w.mDtDy - || w.mLastHScale != w.mHScale - || w.mLastVScale != w.mVScale - || w.mLastHidden) { - displayed = true; - w.mLastAlpha = w.mShownAlpha; - w.mLastLayer = w.mAnimLayer; - w.mLastDsDx = w.mDsDx; - w.mLastDtDx = w.mDtDx; - w.mLastDsDy = w.mDsDy; - w.mLastDtDy = w.mDtDy; - w.mLastHScale = w.mHScale; - w.mLastVScale = w.mVScale; - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + w.mSurface + ": alpha=" - + w.mShownAlpha + " layer=" + w.mAnimLayer); - if (w.mSurface != null) { - try { - w.mSurface.setAlpha(w.mShownAlpha); - w.mSurface.setLayer(w.mAnimLayer); - w.mSurface.setMatrix( - w.mDsDx*w.mHScale, w.mDtDx*w.mVScale, - w.mDsDy*w.mHScale, w.mDtDy*w.mVScale); - } catch (RuntimeException e) { - Log.w(TAG, "Error updating surface in " + w, e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "update"); - } - } - } - - if (w.mLastHidden && !w.mDrawPending - && !w.mCommitDrawPending - && !w.mReadyToShow) { - if (SHOW_TRANSACTIONS) Log.i( - TAG, " SURFACE " + w.mSurface + ": SHOW (performLayout)"); - if (DEBUG_VISIBILITY) Log.v(TAG, "Showing " + w - + " during relayout"); - if (showSurfaceRobustlyLocked(w)) { - w.mHasDrawn = true; - w.mLastHidden = false; - } else { - w.mOrientationChanging = false; - } - } - if (w.mSurface != null) { - w.mToken.hasVisible = true; - } - } else { - displayed = true; - } - - if (displayed) { - if (!covered) { - if (attrs.width == LayoutParams.FILL_PARENT - && attrs.height == LayoutParams.FILL_PARENT) { - covered = true; - } - } - if (w.mOrientationChanging) { - if (w.mDrawPending || w.mCommitDrawPending) { - orientationChangeComplete = false; - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation continue waiting for draw in " + w); - } else { - w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation change complete in " + w); - } - } - w.mToken.hasVisible = true; - } - } else if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) Log.v(TAG, - "Orientation change skips hidden " + w); - w.mOrientationChanging = false; - } - - final boolean canBeSeen = w.isDisplayedLw(); - - if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) { - focusDisplayed = true; - } - - // Update effect. - if (!obscured) { - if (w.mSurface != null) { - if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) { - holdScreen = w.mSession; - } - if (w.mAttrs.screenBrightness >= 0 && screenBrightness < 0) { - screenBrightness = w.mAttrs.screenBrightness; - } - } - if (w.isFullscreenOpaque(dw, dh)) { - // This window completely covers everything behind it, - // so we want to leave all of them as unblurred (for - // performance reasons). - obscured = true; - } else if (canBeSeen && !obscured && - (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) { - if (localLOGV) Log.v(TAG, "Win " + w - + ": blurring=" + blurring - + " obscured=" + obscured - + " displayed=" + displayed); - if ((attrFlags&FLAG_DIM_BEHIND) != 0) { - if (!dimming) { - //Log.i(TAG, "DIM BEHIND: " + w); - dimming = true; - mDimShown = true; - if (mDimSurface == null) { - if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " - + mDimSurface + ": CREATE"); - try { - mDimSurface = new Surface(mFxSession, 0, - -1, 16, 16, - PixelFormat.OPAQUE, - Surface.FX_SURFACE_DIM); - } catch (Exception e) { - Log.e(TAG, "Exception creating Dim surface", e); - } - } - if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " - + mDimSurface + ": SHOW pos=(0,0) (" + - dw + "x" + dh + "), layer=" + (w.mAnimLayer-1)); - if (mDimSurface != null) { - try { - mDimSurface.setPosition(0, 0); - mDimSurface.setSize(dw, dh); - mDimSurface.show(); - } catch (RuntimeException e) { - Log.w(TAG, "Failure showing dim surface", e); - } - } - } - mDimSurface.setLayer(w.mAnimLayer-1); - final float target = w.mExiting ? 0 : attrs.dimAmount; - if (mDimTargetAlpha != target) { - // If the desired dim level has changed, then - // start an animation to it. - mLastDimAnimTime = currentTime; - long duration = (w.mAnimating && w.mAnimation != null) - ? w.mAnimation.computeDurationHint() - : DEFAULT_DIM_DURATION; - if (target > mDimTargetAlpha) { - // This is happening behind the activity UI, - // so we can make it run a little longer to - // give a stronger impression without disrupting - // the user. - duration *= DIM_DURATION_MULTIPLIER; - } - mDimTargetAlpha = target; - mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) - / duration; - } - } - if ((attrFlags&FLAG_BLUR_BEHIND) != 0) { - if (!blurring) { - //Log.i(TAG, "BLUR BEHIND: " + w); - blurring = true; - mBlurShown = true; - if (mBlurSurface == null) { - if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " - + mBlurSurface + ": CREATE"); - try { - mBlurSurface = new Surface(mFxSession, 0, - -1, 16, 16, - PixelFormat.OPAQUE, - Surface.FX_SURFACE_BLUR); - } catch (Exception e) { - Log.e(TAG, "Exception creating Blur surface", e); - } - } - if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " - + mBlurSurface + ": SHOW pos=(0,0) (" + - dw + "x" + dh + "), layer=" + (w.mAnimLayer-1)); - if (mBlurSurface != null) { - mBlurSurface.setPosition(0, 0); - mBlurSurface.setSize(dw, dh); - try { - mBlurSurface.show(); - } catch (RuntimeException e) { - Log.w(TAG, "Failure showing blur surface", e); - } - } - } - mBlurSurface.setLayer(w.mAnimLayer-2); - } - } - } - } - - if (!dimming && mDimShown) { - // Time to hide the dim surface... start fading. - if (mDimTargetAlpha != 0) { - mLastDimAnimTime = currentTime; - mDimTargetAlpha = 0; - mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION; - } - } - - if (mDimShown && mLastDimAnimTime != 0) { - mDimCurrentAlpha += mDimDeltaPerMs - * (currentTime-mLastDimAnimTime); - boolean more = true; - if (mDisplayFrozen) { - // If the display is frozen, there is no reason to animate. - more = false; - } else if (mDimDeltaPerMs > 0) { - if (mDimCurrentAlpha > mDimTargetAlpha) { - more = false; - } - } else if (mDimDeltaPerMs < 0) { - if (mDimCurrentAlpha < mDimTargetAlpha) { - more = false; - } - } else { - more = false; - } - - // Do we need to continue animating? - if (more) { - if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " - + mDimSurface + ": alpha=" + mDimCurrentAlpha); - mLastDimAnimTime = currentTime; - mDimSurface.setAlpha(mDimCurrentAlpha); - animating = true; - } else { - mDimCurrentAlpha = mDimTargetAlpha; - mLastDimAnimTime = 0; - if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " - + mDimSurface + ": final alpha=" + mDimCurrentAlpha); - mDimSurface.setAlpha(mDimCurrentAlpha); - if (!dimming) { - if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface - + ": HIDE"); - try { - mDimSurface.hide(); - } catch (RuntimeException e) { - Log.w(TAG, "Illegal argument exception hiding dim surface"); - } - mDimShown = false; - } - } - } - - if (!blurring && mBlurShown) { - if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface - + ": HIDE"); - try { - mBlurSurface.hide(); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Illegal argument exception hiding blur surface"); - } - mBlurShown = false; - } - - if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION"); - } catch (RuntimeException e) { - Log.e(TAG, "Unhandled exception in Window Manager", e); - } - - Surface.closeTransaction(); - - if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG, - "With display frozen, orientationChangeComplete=" - + orientationChangeComplete); - if (orientationChangeComplete) { - if (mWindowsFreezingScreen) { - mWindowsFreezingScreen = false; - mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); - } - if (mAppsFreezingScreen == 0) { - stopFreezingDisplayLocked(); - } - } - - i = mResizingWindows.size(); - if (i > 0) { - do { - i--; - WindowState win = mResizingWindows.get(i); - try { - win.mClient.resized(win.mFrame.width(), - win.mFrame.height(), win.mLastContentInsets, - win.mLastVisibleInsets, win.mDrawPending); - win.mContentInsetsChanged = false; - win.mVisibleInsetsChanged = false; - } catch (RemoteException e) { - win.mOrientationChanging = false; - } - } while (i > 0); - mResizingWindows.clear(); - } - - // Destroy the surface of any windows that are no longer visible. - i = mDestroySurface.size(); - if (i > 0) { - do { - i--; - WindowState win = mDestroySurface.get(i); - win.mDestroying = false; - if (mInputMethodWindow == win) { - mInputMethodWindow = null; - } - win.destroySurfaceLocked(); - } while (i > 0); - mDestroySurface.clear(); - } - - // Time to remove any exiting tokens? - for (i=mExitingTokens.size()-1; i>=0; i--) { - WindowToken token = mExitingTokens.get(i); - if (!token.hasVisible) { - mExitingTokens.remove(i); - } - } - - // Time to remove any exiting applications? - for (i=mExitingAppTokens.size()-1; i>=0; i--) { - AppWindowToken token = mExitingAppTokens.get(i); - if (!token.hasVisible && !mClosingApps.contains(token)) { - mAppTokens.remove(token); - mExitingAppTokens.remove(i); - } - } - - if (focusDisplayed) { - mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); - } - if (animating) { - requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis()); - } - mQueue.setHoldScreenLocked(holdScreen != null); - if (screenBrightness < 0 || screenBrightness > 1.0f) { - mPowerManager.setScreenBrightnessOverride(-1); - } else { - mPowerManager.setScreenBrightnessOverride((int) - (screenBrightness * Power.BRIGHTNESS_ON)); - } - if (holdScreen != mHoldingScreenOn) { - mHoldingScreenOn = holdScreen; - Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen); - mH.sendMessage(m); - } - } - - void requestAnimationLocked(long delay) { - if (!mAnimationPending) { - mAnimationPending = true; - mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay); - } - } - - /** - * 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. - * - * @return Returns true if the surface was successfully shown. - */ - boolean showSurfaceRobustlyLocked(WindowState win) { - try { - if (win.mSurface != null) { - win.mSurface.show(); - } - return true; - } catch (RuntimeException e) { - Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win); - } - - reclaimSomeSurfaceMemoryLocked(win, "show"); - - return false; - } - - void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) { - final Surface surface = win.mSurface; - - EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(), - win.mSession.mPid, operation); - - if (mForceRemoves == null) { - mForceRemoves = new ArrayList<WindowState>(); - } - - long callingIdentity = Binder.clearCallingIdentity(); - try { - // There was some problem... first, do a sanity check of the - // window list to make sure we haven't left any dangling surfaces - // around. - int N = mWindows.size(); - boolean leakedSurface = false; - Log.i(TAG, "Out of memory for surface! Looking for leaks..."); - for (int i=0; i<N; i++) { - WindowState ws = (WindowState)mWindows.get(i); - if (ws.mSurface != null) { - if (!mSessions.contains(ws.mSession)) { - Log.w(TAG, "LEAKED SURFACE (session doesn't exist): " - + ws + " surface=" + ws.mSurface - + " token=" + win.mToken - + " pid=" + ws.mSession.mPid - + " uid=" + ws.mSession.mUid); - ws.mSurface.clear(); - ws.mSurface = null; - mForceRemoves.add(ws); - i--; - N--; - leakedSurface = true; - } else if (win.mAppToken != null && win.mAppToken.clientHidden) { - Log.w(TAG, "LEAKED SURFACE (app token hidden): " - + ws + " surface=" + ws.mSurface - + " token=" + win.mAppToken); - ws.mSurface.clear(); - ws.mSurface = null; - leakedSurface = true; - } - } - } - - boolean killedApps = false; - if (!leakedSurface) { - Log.w(TAG, "No leaked surfaces; killing applicatons!"); - SparseIntArray pidCandidates = new SparseIntArray(); - for (int i=0; i<N; i++) { - WindowState ws = (WindowState)mWindows.get(i); - if (ws.mSurface != null) { - pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid); - } - } - if (pidCandidates.size() > 0) { - int[] pids = new int[pidCandidates.size()]; - for (int i=0; i<pids.length; i++) { - pids[i] = pidCandidates.keyAt(i); - } - try { - if (mActivityManager.killPidsForMemory(pids)) { - killedApps = true; - } - } catch (RemoteException e) { - } - } - } - - if (leakedSurface || killedApps) { - // We managed to reclaim some memory, so get rid of the trouble - // surface and ask the app to request another one. - Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry."); - if (surface != null) { - surface.clear(); - win.mSurface = null; - } - - try { - win.mClient.dispatchGetNewSurface(); - } catch (RemoteException e) { - } - } - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - - private boolean updateFocusedWindowLocked(int mode) { - WindowState newFocus = computeFocusedWindowLocked(); - if (mCurrentFocus != newFocus) { - // This check makes sure that we don't already have the focus - // change message pending. - 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; - mCurrentFocus = newFocus; - mLosingFocus.remove(newFocus); - if (newFocus != null) { - mKeyWaiter.handleNewWindowLocked(newFocus); - } - - final WindowState imWindow = mInputMethodWindow; - if (newFocus != imWindow && oldFocus != imWindow) { - moveInputMethodWindowsIfNeededLocked( - mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS && - mode != UPDATE_FOCUS_WILL_PLACE_SURFACES); - mLayoutNeeded = true; - if (mode == UPDATE_FOCUS_PLACING_SURFACES) { - performLayoutLockedInner(); - } else if (mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) { - mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); - } - } - return true; - } - return false; - } - - private WindowState computeFocusedWindowLocked() { - WindowState result = null; - WindowState win; - - int i = mWindows.size() - 1; - int nextAppIndex = mAppTokens.size()-1; - WindowToken nextApp = nextAppIndex >= 0 - ? mAppTokens.get(nextAppIndex) : null; - - while (i >= 0) { - win = (WindowState)mWindows.get(i); - - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Looking for focus: " + i - + " = " + win - + ", flags=" + win.mAttrs.flags - + ", canReceive=" + win.canReceiveKeys()); - - AppWindowToken thisApp = win.mAppToken; - - // If this window's application has been removed, just skip it. - if (thisApp != null && thisApp.removed) { - i--; - continue; - } - - // If there is a focused app, don't allow focus to go to any - // windows below it. If this is an application window, step - // through the app tokens until we find its app. - if (thisApp != null && nextApp != null && thisApp != nextApp - && win.mAttrs.type != TYPE_APPLICATION_STARTING) { - int origAppIndex = nextAppIndex; - while (nextAppIndex > 0) { - if (nextApp == mFocusedApp) { - // Whoops, we are below the focused app... no focus - // for you! - if (localLOGV || DEBUG_FOCUS) Log.v( - TAG, "Reached focused app: " + mFocusedApp); - return null; - } - nextAppIndex--; - nextApp = mAppTokens.get(nextAppIndex); - if (nextApp == thisApp) { - break; - } - } - if (thisApp != nextApp) { - // Uh oh, the app token doesn't exist! This shouldn't - // happen, but if it does we can get totally hosed... - // so restart at the original app. - nextAppIndex = origAppIndex; - nextApp = mAppTokens.get(nextAppIndex); - } - } - - // Dispatch to this window if it is wants key events. - if (win.canReceiveKeys()) { - if (DEBUG_FOCUS) Log.v( - TAG, "Found focus @ " + i + " = " + win); - result = win; - break; - } - - i--; - } - - return result; - } - - private void startFreezingDisplayLocked() { - if (mDisplayFrozen) { - return; - } - - mScreenFrozenLock.acquire(); - - long now = SystemClock.uptimeMillis(); - //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now); - if (mFreezeGcPending != 0) { - if (now > (mFreezeGcPending+1000)) { - //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000)); - mH.removeMessages(H.FORCE_GC); - Runtime.getRuntime().gc(); - mFreezeGcPending = now; - } - } else { - mFreezeGcPending = now; - } - - mDisplayFrozen = true; - if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) { - mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE; - mAppTransitionReady = true; - } - - if (PROFILE_ORIENTATION) { - File file = new File("/data/system/frozen"); - Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); - } - Surface.freezeDisplay(0); - } - - private void stopFreezingDisplayLocked() { - if (!mDisplayFrozen) { - return; - } - - mDisplayFrozen = false; - mH.removeMessages(H.APP_FREEZE_TIMEOUT); - if (PROFILE_ORIENTATION) { - Debug.stopMethodTracing(); - } - Surface.unfreezeDisplay(0); - - // Freezing the display also suspends key event delivery, to - // keep events from going astray while the display is reconfigured. - // Now that we're back, notify the key waiter that we're alive - // again and it should restart its timeouts. - synchronized (mKeyWaiter) { - mKeyWaiter.mWasFrozen = true; - mKeyWaiter.notifyAll(); - } - - // A little kludge: a lot could have happened while the - // display was frozen, so now that we are coming back we - // do a gc so that any remote references the system - // processes holds on others can be released if they are - // no longer needed. - mH.removeMessages(H.FORCE_GC); - mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), - 2000); - - mScreenFrozenLock.release(); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump WindowManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized(mWindowMap) { - pw.println("Current Window Manager state:"); - for (int i=mWindows.size()-1; i>=0; i--) { - WindowState w = (WindowState)mWindows.get(i); - pw.println(" Window #" + i + ":"); - w.dump(pw, " "); - } - if (mInputMethodDialogs.size() > 0) { - pw.println(" "); - pw.println(" Input method dialogs:"); - for (int i=mInputMethodDialogs.size()-1; i>=0; i--) { - WindowState w = mInputMethodDialogs.get(i); - pw.println(" IM Dialog #" + i + ": " + w); - } - } - if (mPendingRemove.size() > 0) { - pw.println(" "); - pw.println(" Remove pending for:"); - for (int i=mPendingRemove.size()-1; i>=0; i--) { - WindowState w = mPendingRemove.get(i); - pw.println(" Remove #" + i + ":"); - w.dump(pw, " "); - } - } - if (mForceRemoves != null && mForceRemoves.size() > 0) { - pw.println(" "); - pw.println(" Windows force removing:"); - for (int i=mForceRemoves.size()-1; i>=0; i--) { - WindowState w = mForceRemoves.get(i); - pw.println(" Removing #" + i + ":"); - w.dump(pw, " "); - } - } - if (mDestroySurface.size() > 0) { - pw.println(" "); - pw.println(" Windows waiting to destroy their surface:"); - for (int i=mDestroySurface.size()-1; i>=0; i--) { - WindowState w = mDestroySurface.get(i); - pw.println(" Destroy #" + i + ":"); - w.dump(pw, " "); - } - } - if (mLosingFocus.size() > 0) { - pw.println(" "); - pw.println(" Windows losing focus:"); - for (int i=mLosingFocus.size()-1; i>=0; i--) { - WindowState w = mLosingFocus.get(i); - pw.println(" Losing #" + i + ":"); - w.dump(pw, " "); - } - } - if (mSessions.size() > 0) { - pw.println(" "); - pw.println(" All active sessions:"); - Iterator<Session> it = mSessions.iterator(); - while (it.hasNext()) { - Session s = it.next(); - pw.println(" Session " + s); - s.dump(pw, " "); - } - } - if (mTokenMap.size() > 0) { - pw.println(" "); - pw.println(" All tokens:"); - Iterator<WindowToken> it = mTokenMap.values().iterator(); - while (it.hasNext()) { - WindowToken token = it.next(); - pw.println(" Token " + token.token); - token.dump(pw, " "); - } - } - if (mTokenList.size() > 0) { - pw.println(" "); - pw.println(" Window token list:"); - for (int i=0; i<mTokenList.size(); i++) { - pw.println(" WindowToken #" + i + ": " + mTokenList.get(i)); - } - } - if (mAppTokens.size() > 0) { - pw.println(" "); - pw.println(" Application tokens in Z order:"); - for (int i=mAppTokens.size()-1; i>=0; i--) { - pw.println(" AppWindowToken #" + i + ": " + mAppTokens.get(i)); - } - } - if (mFinishedStarting.size() > 0) { - pw.println(" "); - pw.println(" Finishing start of application tokens:"); - for (int i=mFinishedStarting.size()-1; i>=0; i--) { - WindowToken token = mFinishedStarting.get(i); - pw.println(" Finish Starting App Token #" + i + ":"); - token.dump(pw, " "); - } - } - if (mExitingTokens.size() > 0) { - pw.println(" "); - pw.println(" Exiting tokens:"); - for (int i=mExitingTokens.size()-1; i>=0; i--) { - WindowToken token = mExitingTokens.get(i); - pw.println(" Exiting Token #" + i + ":"); - token.dump(pw, " "); - } - } - if (mExitingAppTokens.size() > 0) { - pw.println(" "); - pw.println(" Exiting application tokens:"); - for (int i=mExitingAppTokens.size()-1; i>=0; i--) { - WindowToken token = mExitingAppTokens.get(i); - pw.println(" Exiting App Token #" + i + ":"); - token.dump(pw, " "); - } - } - pw.println(" "); - pw.println(" mCurrentFocus=" + mCurrentFocus); - pw.println(" mLastFocus=" + mLastFocus); - pw.println(" mFocusedApp=" + mFocusedApp); - pw.println(" mInputMethodTarget=" + mInputMethodTarget); - pw.println(" mInputMethodWindow=" + mInputMethodWindow); - pw.println(" mInTouchMode=" + mInTouchMode); - pw.println(" mSystemBooted=" + mSystemBooted - + " mDisplayEnabled=" + mDisplayEnabled); - pw.println(" mLayoutNeeded=" + mLayoutNeeded - + " 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); - pw.println(" mRotation=" + mRotation - + ", mForcedAppOrientation=" + mForcedAppOrientation - + ", mRequestedRotation=" + mRequestedRotation); - pw.println(" mAnimationPending=" + mAnimationPending - + " mWindowAnimationScale=" + mWindowAnimationScale - + " mTransitionWindowAnimationScale=" + mTransitionAnimationScale); - pw.println(" mNextAppTransition=0x" - + Integer.toHexString(mNextAppTransition) - + ", mAppTransitionReady=" + mAppTransitionReady - + ", mAppTransitionTimeout=" + mAppTransitionTimeout); - pw.println(" mStartingIconInTransition=" + mStartingIconInTransition - + ", mSkipAppTransitionAnimation=" + mSkipAppTransitionAnimation); - pw.println(" mOpeningApps=" + mOpeningApps); - pw.println(" mClosingApps=" + mClosingApps); - pw.println(" DisplayWidth=" + mDisplay.getWidth() - + " DisplayHeight=" + mDisplay.getHeight()); - pw.println(" KeyWaiter state:"); - pw.println(" mLastWin=" + mKeyWaiter.mLastWin - + " mLastBinder=" + mKeyWaiter.mLastBinder); - pw.println(" mFinished=" + mKeyWaiter.mFinished - + " mGotFirstWindow=" + mKeyWaiter.mGotFirstWindow - + " mEventDispatching" + mKeyWaiter.mEventDispatching - + " mTimeToSwitch=" + mKeyWaiter.mTimeToSwitch); - } - } - - public void monitor() { - synchronized (mWindowMap) { } - synchronized (mKeyguardDisabled) { } - synchronized (mKeyWaiter) { } - } -} diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java deleted file mode 100644 index 6443d53..0000000 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ /dev/null @@ -1,11765 +0,0 @@ -/* - * Copyright (C) 2006-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.am; - -import com.android.internal.os.BatteryStatsImpl; -import com.android.internal.os.RuntimeInit; -import com.android.server.IntentResolver; -import com.android.server.ProcessMap; -import com.android.server.ProcessStats; -import com.android.server.SystemServer; -import com.android.server.Watchdog; -import com.android.server.WindowManagerService; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.ActivityManagerNative; -import android.app.ActivityThread; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.IActivityWatcher; -import android.app.IApplicationThread; -import android.app.IInstrumentationWatcher; -import android.app.IIntentReceiver; -import android.app.IIntentSender; -import android.app.IServiceConnection; -import android.app.IThumbnailReceiver; -import android.app.Instrumentation; -import android.app.PendingIntent; -import android.app.ResultInfo; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -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; -import android.content.pm.PackageManager; -import android.content.pm.ProviderInfo; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; -import android.os.Environment; -import android.os.FileUtils; -import android.os.Handler; -import android.os.IBinder; -import android.os.IPermissionController; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.provider.Checkin; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.util.PrintWriterPrinter; -import android.util.SparseArray; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.WindowManagerPolicy; - -import dalvik.system.Zygote; - -import java.io.File; -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; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor { - static final String TAG = "ActivityManager"; - static final boolean DEBUG = false; - static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - static final boolean DEBUG_SWITCH = localLOGV || false; - static final boolean DEBUG_TASKS = localLOGV || false; - static final boolean DEBUG_PAUSE = localLOGV || false; - static final boolean DEBUG_OOM_ADJ = localLOGV || false; - static final boolean DEBUG_TRANSITION = localLOGV || false; - static final boolean DEBUG_BROADCAST = localLOGV || false; - static final boolean DEBUG_SERVICE = localLOGV || false; - static final boolean DEBUG_VISBILITY = localLOGV || false; - static final boolean DEBUG_PROCESSES = localLOGV || false; - static final boolean DEBUG_USER_LEAVING = localLOGV || false; - static final boolean VALIDATE_TOKENS = false; - static final boolean SHOW_ACTIVITY_START_TIME = true; - - // Control over CPU and battery monitoring. - static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes. - static final boolean MONITOR_CPU_USAGE = true; - static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds. - static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample. - static final boolean MONITOR_THREAD_CPU_USAGE = false; - - // Event log tags - static final int LOG_CONFIGURATION_CHANGED = 2719; - static final int LOG_CPU = 2721; - static final int LOG_AM_FINISH_ACTIVITY = 30001; - static final int LOG_TASK_TO_FRONT = 30002; - static final int LOG_AM_NEW_INTENT = 30003; - static final int LOG_AM_CREATE_TASK = 30004; - static final int LOG_AM_CREATE_ACTIVITY = 30005; - static final int LOG_AM_RESTART_ACTIVITY = 30006; - static final int LOG_AM_RESUME_ACTIVITY = 30007; - static final int LOG_ANR = 30008; - static final int LOG_ACTIVITY_LAUNCH_TIME = 30009; - static final int LOG_AM_PROCESS_BOUND = 30010; - static final int LOG_AM_PROCESS_DIED = 30011; - static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012; - static final int LOG_AM_PAUSE_ACTIVITY = 30013; - static final int LOG_AM_PROCESS_START = 30014; - static final int LOG_AM_PROCESS_BAD = 30015; - static final int LOG_AM_PROCESS_GOOD = 30016; - static final int LOG_AM_LOW_MEMORY = 30017; - static final int LOG_AM_DESTROY_ACTIVITY = 30018; - static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019; - static final int LOG_AM_RELAUNCH_ACTIVITY = 30020; - static final int LOG_AM_KILL_FOR_MEMORY = 30023; - static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024; - static final int LOG_AM_BROADCAST_DISCARD_APP = 30025; - static final int LOG_AM_CREATE_SERVICE = 30030; - static final int LOG_AM_DESTROY_SERVICE = 30031; - static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032; - static final int LOG_AM_DROP_PROCESS = 30033; - static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034; - static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035; - static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036; - - static final int LOG_BOOT_PROGRESS_AMS_READY = 3040; - static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050; - - private static final String SYSTEM_SECURE = "ro.secure"; - - // This is the maximum number of application processes we would like - // to have running. Due to the asynchronous nature of things, we can - // temporarily go beyond this limit. - static final int MAX_PROCESSES = 2; - - // Set to false to leave processes running indefinitely, relying on - // the kernel killing them as resources are required. - static final boolean ENFORCE_PROCESS_LIMIT = false; - - // This is the maximum number of activities that we would like to have - // running at a given time. - static final int MAX_ACTIVITIES = 20; - - // Maximum number of recent tasks that we can remember. - static final int MAX_RECENT_TASKS = 20; - - // How long until we reset a task when the user returns to it. Currently - // 30 minutes. - static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30; - - // Set to true to disable the icon that is shown while a new activity - // is being started. - static final boolean SHOW_APP_STARTING_ICON = true; - - // How long we wait until giving up on the last activity to pause. This - // is short because it directly impacts the responsiveness of starting the - // next activity. - static final int PAUSE_TIMEOUT = 500; - - /** - * How long we can hold the launch wake lock before giving up. - */ - static final int LAUNCH_TIMEOUT = 10*1000; - - // How long we wait for a launched process to attach to the activity manager - // before we decide it's never going to come up for real. - static final int PROC_START_TIMEOUT = 10*1000; - - // How long we wait until giving up on the last activity telling us it - // is idle. - static final int IDLE_TIMEOUT = 10*1000; - - // How long to wait after going idle before forcing apps to GC. - static final int GC_TIMEOUT = 5*1000; - - // How long we wait until giving up on an activity telling us it has - // finished destroying itself. - static final int DESTROY_TIMEOUT = 10*1000; - - // How long we allow a receiver to run before giving up on it. - static final int BROADCAST_TIMEOUT = 10*1000; - - // How long we wait for a service to finish executing. - static final int SERVICE_TIMEOUT = 20*1000; - - // How long a service needs to be running until restarting its process - // is no longer considered to be a relaunch of the service. - static final int SERVICE_RESTART_DURATION = 5*1000; - - // Maximum amount of time for there to be no activity on a service before - // we consider it non-essential and allow its process to go on the - // LRU background list. - static final int MAX_SERVICE_INACTIVITY = 10*60*1000; - - // How long we wait until we timeout on key dispatching. - static final int KEY_DISPATCHING_TIMEOUT = 5*1000; - - // The minimum time we allow between crashes, for us to consider this - // application to be bad and stop and its services and reject broadcasts. - static final int MIN_CRASH_INTERVAL = 60*1000; - - // How long we wait until we timeout on key dispatching during instrumentation. - static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000; - - // OOM adjustments for processes in various states: - - // This is a process without anything currently running in it. Definitely - // the first to go! Value set in system/rootdir/init.rc on startup. - // This value is initalized in the constructor, careful when refering to - // this static variable externally. - static int EMPTY_APP_ADJ; - - // This is a process with a content provider that does not have any clients - // attached to it. If it did have any clients, its adjustment would be the - // one for the highest-priority of those processes. - static int CONTENT_PROVIDER_ADJ; - - // This is a process only hosting activities that are not visible, - // so it can be killed without any disruption. Value set in - // system/rootdir/init.rc on startup. - final int HIDDEN_APP_MAX_ADJ; - static int HIDDEN_APP_MIN_ADJ; - - // This is a process holding a secondary server -- killing it will not - // have much of an impact as far as the user is concerned. Value set in - // system/rootdir/init.rc on startup. - final int SECONDARY_SERVER_ADJ; - - // This is a process only hosting activities that are visible to the - // user, so we'd prefer they don't disappear. Value set in - // system/rootdir/init.rc on startup. - final int VISIBLE_APP_ADJ; - - // This is the process running the current foreground app. We'd really - // rather not kill it! Value set in system/rootdir/init.rc on startup. - final int FOREGROUND_APP_ADJ; - - // This is a process running a core server, such as telephony. Definitely - // don't want to kill it, but doing so is not completely fatal. - static final int CORE_SERVER_ADJ = -12; - - // The system process runs at the default adjustment. - static final int SYSTEM_ADJ = -16; - - // Memory pages are 4K. - static final int PAGE_SIZE = 4*1024; - - // Corresponding memory levels for above adjustments. - final int EMPTY_APP_MEM; - final int HIDDEN_APP_MEM; - final int SECONDARY_SERVER_MEM; - final int VISIBLE_APP_MEM; - final int FOREGROUND_APP_MEM; - - final int MY_PID; - - static final String[] EMPTY_STRING_ARRAY = new String[0]; - - enum ActivityState { - INITIALIZING, - RESUMED, - PAUSING, - PAUSED, - STOPPING, - STOPPED, - FINISHING, - DESTROYING, - DESTROYED - } - - /** - * The back history of all previous (and possibly still - * running) activities. It contains HistoryRecord objects. - */ - final ArrayList mHistory = new ArrayList(); - - /** - * List of all active broadcasts that are to be executed immediately - * (without waiting for another broadcast to finish). Currently this only - * contains broadcasts to registered receivers, to avoid spinning up - * a bunch of processes to execute IntentReceiver components. - */ - final ArrayList<BroadcastRecord> mParallelBroadcasts - = new ArrayList<BroadcastRecord>(); - - /** - * List of all active broadcasts that are to be executed one at a time. - * The object at the top of the list is the currently activity broadcasts; - * those after it are waiting for the top to finish.. - */ - final ArrayList<BroadcastRecord> mOrderedBroadcasts - = new ArrayList<BroadcastRecord>(); - - /** - * Set when we current have a BROADCAST_INTENT_MSG in flight. - */ - boolean mBroadcastsScheduled = false; - - /** - * Set to indicate whether to issue an onUserLeaving callback when a - * newly launched activity is being brought in front of us. - */ - boolean mUserLeaving = false; - - /** - * When we are in the process of pausing an activity, before starting the - * next one, this variable holds the activity that is currently being paused. - */ - HistoryRecord mPausingActivity = null; - - /** - * Current activity that is resumed, or null if there is none. - */ - HistoryRecord mResumedActivity = null; - - /** - * Activity we have told the window manager to have key focus. - */ - HistoryRecord mFocusedActivity = null; - - /** - * List of activities that are waiting for a new activity - * to become visible before completing whatever operation they are - * supposed to do. - */ - final ArrayList mWaitingVisibleActivities = new ArrayList(); - - /** - * List of activities that are ready to be stopped, but waiting - * for the next activity to settle down before doing so. It contains - * HistoryRecord objects. - */ - final ArrayList<HistoryRecord> mStoppingActivities - = new ArrayList<HistoryRecord>(); - - /** - * List of intents that were used to start the most recent tasks. - */ - final ArrayList<TaskRecord> mRecentTasks - = new ArrayList<TaskRecord>(); - - /** - * List of activities that are ready to be finished, but waiting - * for the previous activity to settle down before doing so. It contains - * HistoryRecord objects. - */ - final ArrayList mFinishingActivities = new ArrayList(); - - /** - * All of the applications we currently have running organized by name. - * The keys are strings of the application package name (as - * returned by the package manager), and the keys are ApplicationRecord - * objects. - */ - final ProcessMap<ProcessRecord> mProcessNames - = new ProcessMap<ProcessRecord>(); - - /** - * The last time that various processes have crashed. - */ - final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>(); - - /** - * Set of applications that we consider to be bad, and will reject - * incoming broadcasts from (which the user has no control over). - * Processes are added to this set when they have crashed twice within - * a minimum amount of time; they are removed from it when they are - * later restarted (hopefully due to some user action). The value is the - * time it was added to the list. - */ - final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>(); - - /** - * All of the processes we currently have running organized by pid. - * The keys are the pid running the application. - * - * <p>NOTE: This object is protected by its own lock, NOT the global - * activity manager lock! - */ - final SparseArray<ProcessRecord> mPidsSelfLocked - = new SparseArray<ProcessRecord>(); - - /** - * All of the processes that have been forced to be foreground. The key - * is the pid of the caller who requested it (we hold a death - * link on it). - */ - abstract class ForegroundToken implements IBinder.DeathRecipient { - int pid; - IBinder token; - } - final SparseArray<ForegroundToken> mForegroundProcesses - = new SparseArray<ForegroundToken>(); - - /** - * List of records for processes that someone had tried to start before the - * system was ready. We don't start them at that point, but ensure they - * are started by the time booting is complete. - */ - final ArrayList<ProcessRecord> mProcessesOnHold - = new ArrayList<ProcessRecord>(); - - /** - * List of records for processes that we have started and are waiting - * for them to call back. This is really only needed when running in - * single processes mode, in which case we do not have a unique pid for - * each process. - */ - final ArrayList<ProcessRecord> mStartingProcesses - = new ArrayList<ProcessRecord>(); - - /** - * List of persistent applications that are in the process - * of being started. - */ - final ArrayList<ProcessRecord> mPersistentStartingProcesses - = new ArrayList<ProcessRecord>(); - - /** - * Processes that are being forcibly torn down. - */ - final ArrayList<ProcessRecord> mRemovedProcesses - = new ArrayList<ProcessRecord>(); - - /** - * List of running applications, sorted by recent usage. - * The first entry in the list is the least recently used. - * It contains ApplicationRecord objects. This list does NOT include - * any persistent application records (since we never want to exit them). - */ - final ArrayList<ProcessRecord> mLRUProcesses - = new ArrayList<ProcessRecord>(); - - /** - * List of processes that should gc as soon as things are idle. - */ - final ArrayList<ProcessRecord> mProcessesToGc - = new ArrayList<ProcessRecord>(); - - /** - * List of running activities, sorted by recent usage. - * The first entry in the list is the least recently used. - * It contains HistoryRecord objects. - */ - private final ArrayList mLRUActivities = new ArrayList(); - - /** - * Set of PendingResultRecord objects that are currently active. - */ - final HashSet mPendingResultRecords = new HashSet(); - - /** - * Set of IntentSenderRecord objects that are currently active. - */ - final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords - = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>(); - - /** - * Intent broadcast that we have tried to start, but are - * waiting for its application's process to be created. We only - * need one (instead of a list) because we always process broadcasts - * one at a time, so no others can be started while waiting for this - * one. - */ - BroadcastRecord mPendingBroadcast = null; - - /** - * Keeps track of all IIntentReceivers that have been registered for - * broadcasts. Hash keys are the receiver IBinder, hash value is - * a ReceiverList. - */ - final HashMap mRegisteredReceivers = new HashMap(); - - /** - * Resolver for broadcast intents to registered receivers. - * Holds BroadcastFilter (subclass of IntentFilter). - */ - final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver - = new IntentResolver<BroadcastFilter, BroadcastFilter>() { - @Override - protected boolean allowFilterResult( - BroadcastFilter filter, List<BroadcastFilter> dest) { - IBinder target = filter.receiverList.receiver.asBinder(); - for (int i=dest.size()-1; i>=0; i--) { - if (dest.get(i).receiverList.receiver.asBinder() == target) { - return false; - } - } - return true; - } - }; - - /** - * State of all active sticky broadcasts. Keys are the action of the - * sticky Intent, values are an ArrayList of all broadcasted intents with - * that action (which should usually be one). - */ - final HashMap<String, ArrayList<Intent>> mStickyBroadcasts = - new HashMap<String, ArrayList<Intent>>(); - - /** - * All currently running services. - */ - final HashMap<ComponentName, ServiceRecord> mServices = - new HashMap<ComponentName, ServiceRecord>(); - - /** - * All currently running services indexed by the Intent used to start them. - */ - final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = - new HashMap<Intent.FilterComparison, ServiceRecord>(); - - /** - * All currently bound service connections. Keys are the IBinder of - * the client's IServiceConnection. - */ - final HashMap<IBinder, ConnectionRecord> mServiceConnections - = new HashMap<IBinder, ConnectionRecord>(); - - /** - * List of services that we have been asked to start, - * but haven't yet been able to. It is used to hold start requests - * while waiting for their corresponding application thread to get - * going. - */ - final ArrayList<ServiceRecord> mPendingServices - = new ArrayList<ServiceRecord>(); - - /** - * List of services that are scheduled to restart following a crash. - */ - final ArrayList<ServiceRecord> mRestartingServices - = new ArrayList<ServiceRecord>(); - - /** - * List of services that are in the process of being stopped. - */ - final ArrayList<ServiceRecord> mStoppingServices - = new ArrayList<ServiceRecord>(); - - /** - * List of PendingThumbnailsRecord objects of clients who are still - * waiting to receive all of the thumbnails for a task. - */ - final ArrayList mPendingThumbnails = new ArrayList(); - - /** - * List of HistoryRecord objects that have been finished and must - * still report back to a pending thumbnail receiver. - */ - final ArrayList mCancelledThumbnails = new ArrayList(); - - /** - * All of the currently running global content providers. Keys are a - * string containing the provider name and values are a - * ContentProviderRecord object containing the data about it. Note - * that a single provider may be published under multiple names, so - * there may be multiple entries here for a single one in mProvidersByClass. - */ - final HashMap mProvidersByName = new HashMap(); - - /** - * All of the currently running global content providers. Keys are a - * string containing the provider's implementation class and values are a - * ContentProviderRecord object containing the data about it. - */ - final HashMap mProvidersByClass = new HashMap(); - - /** - * List of content providers who have clients waiting for them. The - * application is currently being launched and the provider will be - * removed from this list once it is published. - */ - final ArrayList mLaunchingProviders = new ArrayList(); - - /** - * Global set of specific Uri permissions that have been granted. - */ - final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions - = new SparseArray<HashMap<Uri, UriPermission>>(); - - /** - * Thread-local storage used to carry caller permissions over through - * indirect content-provider access. - * @see #ActivityManagerService.openContentUri() - */ - private class Identity { - public int pid; - public int uid; - - Identity(int _pid, int _uid) { - pid = _pid; - uid = _uid; - } - } - private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>(); - - /** - * All information we have collected about the runtime performance of - * 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 - * a reference to this object to indicate which configuration they are - * currently running in, so this object must be kept immutable. - */ - Configuration mConfiguration = new Configuration(); - - /** - * List of initialization arguments to pass to all processes when binding applications to them. - * For example, references to the commonly used services. - */ - HashMap<String, IBinder> mAppBindArgs; - - /** - * Used to control how we initialize the service. - */ - boolean mStartRunning = false; - ComponentName mTopComponent; - String mTopAction; - String mTopData; - boolean mSystemReady = false; - boolean mBooting = false; - - Context mContext; - - int mFactoryTest; - - /** - * Set while we are wanting to sleep, to prevent any - * activities from being started/resumed. - */ - boolean mSleeping = false; - - /** - * Set when the system is going to sleep, until we have - * successfully paused the current activity and released our wake lock. - * At that point the system is allowed to actually sleep. - */ - PowerManager.WakeLock mGoingToSleep; - - /** - * We don't want to allow the device to go to sleep while in the process - * of launching an activity. This is primarily to allow alarm intent - * receivers to launch an activity and get that to run before the device - * goes back to sleep. - */ - PowerManager.WakeLock mLaunchingActivity; - - /** - * Task identifier that activities are currently being started - * in. Incremented each time a new task is created. - * todo: Replace this with a TokenSpace class that generates non-repeating - * integers that won't wrap. - */ - int mCurTask = 1; - - /** - * Current sequence id for oom_adj computation traversal. - */ - int mAdjSeq = 0; - - /** - * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar - * is set, indicating the user wants processes started in such a way - * that they can use ANDROID_PROCESS_WRAPPER and know what will be - * running in each process (thus no pre-initialized process, etc). - */ - boolean mSimpleProcessManagement = false; - - /** - * System monitoring: number of processes that died since the last - * N procs were started. - */ - int[] mProcDeaths = new int[20]; - - String mDebugApp = null; - boolean mWaitForDebugger = false; - boolean mDebugTransient = false; - String mOrigDebugApp = null; - boolean mOrigWaitForDebugger = false; - boolean mAlwaysFinishActivities = false; - IActivityWatcher mWatcher = null; - - /** - * Callback of last caller to {@link #requestPss}. - */ - Runnable mRequestPssCallback; - - /** - * Remaining processes for which we are waiting results from the last - * call to {@link #requestPss}. - */ - final ArrayList<ProcessRecord> mRequestPssList - = new ArrayList<ProcessRecord>(); - - /** - * Runtime statistics collection thread. This object's lock is used to - * protect all related state. - */ - final Thread mProcessStatsThread; - - /** - * Used to collect process stats when showing not responding dialog. - * Protected by mProcessStatsThread. - */ - final ProcessStats mProcessStats = new ProcessStats( - MONITOR_THREAD_CPU_USAGE); - long mLastCpuTime = 0; - long mLastWriteTime = 0; - - /** - * Set to true after the system has finished booting. - */ - boolean mBooted = false; - - int mProcessLimit = 0; - - WindowManagerService mWindowManager; - - static ActivityManagerService mSelf; - static ActivityThread mSystemThread; - - private final class AppDeathRecipient implements IBinder.DeathRecipient { - final ProcessRecord mApp; - final int mPid; - final IApplicationThread mAppThread; - - AppDeathRecipient(ProcessRecord app, int pid, - IApplicationThread thread) { - if (localLOGV) Log.v( - TAG, "New death recipient " + this - + " for thread " + thread.asBinder()); - mApp = app; - mPid = pid; - mAppThread = thread; - } - - public void binderDied() { - if (localLOGV) Log.v( - TAG, "Death received in " + this - + " for thread " + mAppThread.asBinder()); - removeRequestedPss(mApp); - synchronized(ActivityManagerService.this) { - appDiedLocked(mApp, mPid, mAppThread); - } - } - } - - static final int SHOW_ERROR_MSG = 1; - static final int SHOW_NOT_RESPONDING_MSG = 2; - static final int SHOW_FACTORY_ERROR_MSG = 3; - static final int UPDATE_CONFIGURATION_MSG = 4; - static final int GC_BACKGROUND_PROCESSES_MSG = 5; - static final int WAIT_FOR_DEBUGGER_MSG = 6; - static final int BROADCAST_INTENT_MSG = 7; - static final int BROADCAST_TIMEOUT_MSG = 8; - static final int PAUSE_TIMEOUT_MSG = 9; - static final int IDLE_TIMEOUT_MSG = 10; - static final int IDLE_NOW_MSG = 11; - static final int SERVICE_TIMEOUT_MSG = 12; - static final int UPDATE_TIME_ZONE = 13; - static final int SHOW_UID_ERROR_MSG = 14; - static final int IM_FEELING_LUCKY_MSG = 15; - static final int LAUNCH_TIMEOUT_MSG = 16; - static final int DESTROY_TIMEOUT_MSG = 17; - static final int SERVICE_ERROR_MSG = 18; - static final int RESUME_TOP_ACTIVITY_MSG = 19; - static final int PROC_START_TIMEOUT_MSG = 20; - - AlertDialog mUidAlert; - - final Handler mHandler = new Handler() { - //public Handler() { - // if (localLOGV) Log.v(TAG, "Handler started!"); - //} - - public void handleMessage(Message msg) { - switch (msg.what) { - case SHOW_ERROR_MSG: { - HashMap data = (HashMap) msg.obj; - byte[] crashData = (byte[])data.get("crashData"); - if (crashData != null) { - // This needs to be *un*synchronized to avoid deadlock. - ContentResolver resolver = mContext.getContentResolver(); - Checkin.reportCrash(resolver, crashData); - } - synchronized (ActivityManagerService.this) { - ProcessRecord proc = (ProcessRecord)data.get("app"); - if (proc != null && proc.crashDialog != null) { - Log.e(TAG, "App already has crash dialog: " + proc); - return; - } - AppErrorResult res = (AppErrorResult) data.get("result"); - if (!mSleeping) { - Dialog d = new AppErrorDialog( - mContext, res, proc, - (Integer)data.get("flags"), - (String)data.get("shortMsg"), - (String)data.get("longMsg")); - d.show(); - proc.crashDialog = d; - } else { - // The device is asleep, so just pretend that the user - // saw a crash dialog and hit "force quit". - res.set(0); - } - } - } break; - case SHOW_NOT_RESPONDING_MSG: { - synchronized (ActivityManagerService.this) { - HashMap data = (HashMap) msg.obj; - ProcessRecord proc = (ProcessRecord)data.get("app"); - if (proc != null && proc.anrDialog != null) { - Log.e(TAG, "App already has anr dialog: " + proc); - return; - } - Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (HistoryRecord)data.get("activity")); - d.show(); - proc.anrDialog = d; - } - } break; - case SHOW_FACTORY_ERROR_MSG: { - Dialog d = new FactoryErrorDialog( - mContext, msg.getData().getCharSequence("msg")); - d.show(); - enableScreenAfterBoot(); - } break; - case UPDATE_CONFIGURATION_MSG: { - final ContentResolver resolver = mContext.getContentResolver(); - Settings.System.putConfiguration(resolver, (Configuration)msg.obj); - } break; - case GC_BACKGROUND_PROCESSES_MSG: { - synchronized (ActivityManagerService.this) { - performAppGcsIfAppropriateLocked(); - } - } break; - case WAIT_FOR_DEBUGGER_MSG: { - synchronized (ActivityManagerService.this) { - ProcessRecord app = (ProcessRecord)msg.obj; - if (msg.arg1 != 0) { - if (!app.waitedForDebugger) { - Dialog d = new AppWaitingForDebuggerDialog( - ActivityManagerService.this, - mContext, app); - app.waitDialog = d; - app.waitedForDebugger = true; - d.show(); - } - } else { - if (app.waitDialog != null) { - app.waitDialog.dismiss(); - app.waitDialog = null; - } - } - } - } break; - case BROADCAST_INTENT_MSG: { - if (DEBUG_BROADCAST) Log.v( - TAG, "Received BROADCAST_INTENT_MSG"); - processNextBroadcast(true); - } break; - case BROADCAST_TIMEOUT_MSG: { - broadcastTimeout(); - } break; - case PAUSE_TIMEOUT_MSG: { - IBinder token = (IBinder)msg.obj; - // We don't at this point know if the activity is fullscreen, - // so we need to be conservative and assume it isn't. - Log.w(TAG, "Activity pause timeout for " + token); - activityPaused(token, null, true); - } break; - case IDLE_TIMEOUT_MSG: { - IBinder token = (IBinder)msg.obj; - // We don't at this point know if the activity is fullscreen, - // so we need to be conservative and assume it isn't. - Log.w(TAG, "Activity idle timeout for " + token); - activityIdleInternal(token, true); - } break; - case DESTROY_TIMEOUT_MSG: { - IBinder token = (IBinder)msg.obj; - // We don't at this point know if the activity is fullscreen, - // so we need to be conservative and assume it isn't. - Log.w(TAG, "Activity destroy timeout for " + token); - activityDestroyed(token); - } break; - case IDLE_NOW_MSG: { - IBinder token = (IBinder)msg.obj; - activityIdle(token); - } break; - case SERVICE_TIMEOUT_MSG: { - serviceTimeout((ProcessRecord)msg.obj); - } break; - case UPDATE_TIME_ZONE: { - synchronized (ActivityManagerService.this) { - for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = mLRUProcesses.get(i); - if (r.thread != null) { - try { - r.thread.updateTimeZone(); - } catch (RemoteException ex) { - Log.w(TAG, "Failed to update time zone for: " + r.info.processName); - } - } - } - } - break; - } - case SHOW_UID_ERROR_MSG: { - // XXX This is a temporary dialog, no need to localize. - AlertDialog d = new BaseErrorDialog(mContext); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); - d.setCancelable(false); - d.setTitle("System UIDs Inconsistent"); - d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable."); - d.setButton("I'm Feeling Lucky", - mHandler.obtainMessage(IM_FEELING_LUCKY_MSG)); - mUidAlert = d; - d.show(); - } break; - case IM_FEELING_LUCKY_MSG: { - if (mUidAlert != null) { - mUidAlert.dismiss(); - mUidAlert = null; - } - } break; - case LAUNCH_TIMEOUT_MSG: { - synchronized (ActivityManagerService.this) { - if (mLaunchingActivity.isHeld()) { - Log.w(TAG, "Launch timeout has expired, giving up wake lock!"); - mLaunchingActivity.release(); - } - } - } break; - case SERVICE_ERROR_MSG: { - ServiceRecord srv = (ServiceRecord)msg.obj; - // This needs to be *un*synchronized to avoid deadlock. - Checkin.logEvent(mContext.getContentResolver(), - Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING, - srv.name.toShortString()); - } break; - case RESUME_TOP_ACTIVITY_MSG: { - synchronized (ActivityManagerService.this) { - resumeTopActivityLocked(null); - } - } - case PROC_START_TIMEOUT_MSG: { - ProcessRecord app = (ProcessRecord)msg.obj; - synchronized (ActivityManagerService.this) { - processStartTimedOutLocked(app); - } - } - } - } - }; - - public static void setSystemProcess() { - try { - ActivityManagerService m = mSelf; - - ServiceManager.addService("activity", m); - ServiceManager.addService("meminfo", new MemBinder(m)); - if (MONITOR_CPU_USAGE) { - ServiceManager.addService("cpuinfo", new CpuBinder(m)); - } - ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m)); - ServiceManager.addService("activity.services", new ServicesBinder(m)); - ServiceManager.addService("activity.senders", new SendersBinder(m)); - ServiceManager.addService("activity.providers", new ProvidersBinder(m)); - ServiceManager.addService("permission", new PermissionController(m)); - - ApplicationInfo info = - mSelf.mContext.getPackageManager().getApplicationInfo( - "android", PackageManager.GET_SHARED_LIBRARY_FILES); - synchronized (mSelf) { - ProcessRecord app = mSelf.newProcessRecordLocked( - mSystemThread.getApplicationThread(), info, - info.processName); - app.persistent = true; - app.pid = Process.myPid(); - app.maxAdj = SYSTEM_ADJ; - mSelf.mProcessNames.put(app.processName, app.info.uid, app); - synchronized (mSelf.mPidsSelfLocked) { - mSelf.mPidsSelfLocked.put(app.pid, app); - } - mSelf.updateLRUListLocked(app, true); - } - } catch (PackageManager.NameNotFoundException e) { - throw new RuntimeException( - "Unable to find android system package", e); - } - } - - public void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; - } - - public static final Context main(int factoryTest) { - AThread thr = new AThread(); - thr.start(); - - synchronized (thr) { - while (thr.mService == null) { - try { - thr.wait(); - } catch (InterruptedException e) { - } - } - } - - ActivityManagerService m = thr.mService; - mSelf = m; - ActivityThread at = ActivityThread.systemMain(); - mSystemThread = at; - Context context = at.getSystemContext(); - m.mContext = context; - m.mFactoryTest = factoryTest; - PowerManager pm = - (PowerManager)context.getSystemService(Context.POWER_SERVICE); - m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch"); - m.mLaunchingActivity.setReferenceCounted(false); - - m.mBatteryStatsService.publish(context); - m.mUsageStatsService.publish(context); - - synchronized (thr) { - thr.mReady = true; - thr.notifyAll(); - } - - m.startRunning(null, null, null, null); - - return context; - } - - public static ActivityManagerService self() { - return mSelf; - } - - static class AThread extends Thread { - ActivityManagerService mService; - boolean mReady = false; - - public AThread() { - super("ActivityManager"); - } - - public void run() { - Looper.prepare(); - - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_FOREGROUND); - - ActivityManagerService m = new ActivityManagerService(); - - synchronized (this) { - mService = m; - notifyAll(); - } - - synchronized (this) { - while (!mReady) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - - Looper.loop(); - } - } - - static class BroadcastsBinder extends Binder { - ActivityManagerService mActivityManagerService; - BroadcastsBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mActivityManagerService.dumpBroadcasts(pw); - } - } - - static class ServicesBinder extends Binder { - ActivityManagerService mActivityManagerService; - ServicesBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mActivityManagerService.dumpServices(pw); - } - } - - static class SendersBinder extends Binder { - ActivityManagerService mActivityManagerService; - SendersBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mActivityManagerService.dumpSenders(pw); - } - } - - static class ProvidersBinder extends Binder { - ActivityManagerService mActivityManagerService; - ProvidersBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mActivityManagerService.dumpProviders(pw); - } - } - - static class MemBinder extends Binder { - ActivityManagerService mActivityManagerService; - MemBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - ActivityManagerService service = mActivityManagerService; - ArrayList<ProcessRecord> procs; - synchronized (mActivityManagerService) { - if (args != null && args.length > 0 - && args[0].charAt(0) != '-') { - procs = new ArrayList<ProcessRecord>(); - int pid = -1; - try { - pid = Integer.parseInt(args[0]); - } catch (NumberFormatException e) { - - } - for (int i=0; i<service.mLRUProcesses.size(); i++) { - ProcessRecord proc = service.mLRUProcesses.get(i); - if (proc.pid == pid) { - procs.add(proc); - } else if (proc.processName.equals(args[0])) { - procs.add(proc); - } - } - if (procs.size() <= 0) { - pw.println("No process found for: " + args[0]); - return; - } - } else { - procs = service.mLRUProcesses; - } - } - dumpApplicationMemoryUsage(fd, pw, procs, " ", args); - } - } - - static class CpuBinder extends Binder { - ActivityManagerService mActivityManagerService; - CpuBinder(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - synchronized (mActivityManagerService.mProcessStatsThread) { - pw.print(mActivityManagerService.mProcessStats.printCurrentState()); - } - } - } - - private ActivityManagerService() { - String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT"); - if (v != null && Integer.getInteger(v) != 0) { - mSimpleProcessManagement = true; - } - v = System.getenv("ANDROID_DEBUG_APP"); - if (v != null) { - mSimpleProcessManagement = true; - } - - MY_PID = Process.myPid(); - - File dataDir = Environment.getDataDirectory(); - File systemDir = new File(dataDir, "system"); - systemDir.mkdirs(); - mBatteryStatsService = new BatteryStatsService(new File( - systemDir, "batterystats.bin").toString()); - mBatteryStatsService.getActiveStatistics().readLocked(); - mBatteryStatsService.getActiveStatistics().writeLocked(); - - mUsageStatsService = new UsageStatsService( new File( - systemDir, "usagestats.bin").toString()); - - mConfiguration.makeDefault(); - mProcessStats.init(); - - // Add ourself to the Watchdog monitors. - Watchdog.getInstance().addMonitor(this); - - // These values are set in system/rootdir/init.rc on startup. - FOREGROUND_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ")); - VISIBLE_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ")); - SECONDARY_SERVER_ADJ = - Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ")); - HIDDEN_APP_MIN_ADJ = - Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ")); - CONTENT_PROVIDER_ADJ = - Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ")); - HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1; - EMPTY_APP_ADJ = - Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ")); - FOREGROUND_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE; - VISIBLE_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE; - SECONDARY_SERVER_MEM = - Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE; - HIDDEN_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE; - EMPTY_APP_MEM = - Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE; - - mProcessStatsThread = new Thread("ProcessStats") { - public void run() { - while (true) { - try { - try { - synchronized(this) { - final long now = SystemClock.uptimeMillis(); - long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now; - long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now; - //Log.i(TAG, "Cpu delay=" + nextCpuDelay - // + ", write delay=" + nextWriteDelay); - if (nextWriteDelay < nextCpuDelay) { - nextCpuDelay = nextWriteDelay; - } - if (nextCpuDelay > 0) { - this.wait(nextCpuDelay); - } - } - } catch (InterruptedException e) { - } - - updateCpuStatsNow(); - } catch (Exception e) { - Log.e(TAG, "Unexpected exception collecting process stats", e); - } - } - } - }; - mProcessStatsThread.start(); - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - return super.onTransact(code, data, reply, flags); - } catch (RuntimeException e) { - // The activity manager only throws security exceptions, so let's - // log all others. - if (!(e instanceof SecurityException)) { - Log.e(TAG, "Activity Manager Crash", e); - } - throw e; - } - } - - void updateCpuStats() { - synchronized (mProcessStatsThread) { - final long now = SystemClock.uptimeMillis(); - if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) { - mProcessStatsThread.notify(); - } - } - } - - void updateCpuStatsNow() { - synchronized (mProcessStatsThread) { - final long now = SystemClock.uptimeMillis(); - boolean haveNewCpuStats = false; - - if (MONITOR_CPU_USAGE && - mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) { - mLastCpuTime = now; - haveNewCpuStats = true; - mProcessStats.update(); - //Log.i(TAG, mProcessStats.printCurrentState()); - //Log.i(TAG, "Total CPU usage: " - // + mProcessStats.getTotalCpuPercent() + "%"); - - // Log the cpu usage if the property is set. - if ("true".equals(SystemProperties.get("events.cpu"))) { - int user = mProcessStats.getLastUserTime(); - int system = mProcessStats.getLastSystemTime(); - int iowait = mProcessStats.getLastIoWaitTime(); - int irq = mProcessStats.getLastIrqTime(); - int softIrq = mProcessStats.getLastSoftIrqTime(); - int idle = mProcessStats.getLastIdleTime(); - - int total = user + system + iowait + irq + softIrq + idle; - if (total == 0) total = 1; - - EventLog.writeEvent(LOG_CPU, - ((user+system+iowait+irq+softIrq) * 100) / total, - (user * 100) / total, - (system * 100) / total, - (iowait * 100) / total, - (irq * 100) / total, - (softIrq * 100) / total); - } - } - - synchronized(mBatteryStatsService.getActiveStatistics()) { - synchronized(mPidsSelfLocked) { - if (haveNewCpuStats) { - if (mBatteryStatsService.isOnBattery()) { - final int N = mProcessStats.countWorkingStats(); - for (int i=0; i<N; i++) { - ProcessStats.Stats st - = mProcessStats.getWorkingStats(i); - ProcessRecord pr = mPidsSelfLocked.get(st.pid); - if (pr != null) { - BatteryStatsImpl.Uid.Proc ps = pr.batteryStats; - ps.addCpuTimeLocked(st.rel_utime, st.rel_stime); - } - } - } - } - } - - if (mLastWriteTime < (now-BATTERY_STATS_TIME)) { - mLastWriteTime = now; - mBatteryStatsService.getActiveStatistics().writeLocked(); - } - } - } - } - - /** - * Initialize the application bind args. These are passed to each - * process when the bindApplication() IPC is sent to the process. They're - * lazily setup to make sure the services are running when they're asked for. - */ - private HashMap<String, IBinder> getCommonServicesLocked() { - if (mAppBindArgs == null) { - mAppBindArgs = new HashMap<String, IBinder>(); - - // Setup the application init args - mAppBindArgs.put("package", ServiceManager.getService("package")); - mAppBindArgs.put("window", ServiceManager.getService("window")); - mAppBindArgs.put(Context.ALARM_SERVICE, - ServiceManager.getService(Context.ALARM_SERVICE)); - } - return mAppBindArgs; - } - - private final void setFocusedActivityLocked(HistoryRecord r) { - if (mFocusedActivity != r) { - mFocusedActivity = r; - mWindowManager.setFocusedApp(r, true); - } - } - - private final void updateLRUListLocked(ProcessRecord app, - boolean oomAdj) { - // put it on the LRU to keep track of when it should be exited. - int lrui = mLRUProcesses.indexOf(app); - if (lrui >= 0) mLRUProcesses.remove(lrui); - mLRUProcesses.add(app); - //Log.i(TAG, "Putting proc to front: " + app.processName); - if (oomAdj) { - updateOomAdjLocked(); - } - } - - private final boolean updateLRUListLocked(HistoryRecord r) { - final boolean hadit = mLRUActivities.remove(r); - mLRUActivities.add(r); - return hadit; - } - - private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) { - int i = mHistory.size()-1; - while (i >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (!r.finishing && r != notTop) { - return r; - } - i--; - } - return null; - } - - /** - * This is a simplified version of topRunningActivityLocked that provides a number of - * optional skip-over modes. It is intended for use with the ActivityWatcher hook only. - * - * @param token If non-null, any history records matching this token will be skipped. - * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. - * - * @return Returns the HistoryRecord of the next activity on the stack. - */ - private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) { - int i = mHistory.size()-1; - while (i >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - // Note: the taskId check depends on real taskId fields being non-zero - if (!r.finishing && (token != r) && (taskId != r.task.taskId)) { - return r; - } - i--; - } - return null; - } - - private final ProcessRecord getProcessRecordLocked( - String processName, int uid) { - if (uid == Process.SYSTEM_UID) { - // The system gets to run in any process. If there are multiple - // processes with the same uid, just pick the first (this - // should never happen). - SparseArray<ProcessRecord> procs = mProcessNames.getMap().get( - processName); - return procs != null ? procs.valueAt(0) : null; - } - ProcessRecord proc = mProcessNames.get(processName, uid); - return proc; - } - - private boolean isNextTransitionForward() { - int transit = mWindowManager.getPendingAppTransition(); - return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN - || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN - || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT; - } - - private final boolean realStartActivityLocked(HistoryRecord r, - ProcessRecord app, boolean andResume, boolean checkConfig) - throws RemoteException { - - r.startFreezingScreenLocked(app, 0); - mWindowManager.setAppVisibility(r, true); - - // Have the window manager re-evaluate the orientation of - // the screen based on the new activity order. Note that - // as a result of this, it can call back into the activity - // manager with a new orientation. We don't care about that, - // because the activity is not currently running so we are - // just restarting it anyway. - if (checkConfig) { - Configuration config = mWindowManager.updateOrientationFromAppTokens( - r.mayFreezeScreenLocked(app) ? r : null); - updateConfigurationLocked(config, r); - } - - r.app = app; - - if (localLOGV) Log.v(TAG, "Launching: " + r); - - int idx = app.activities.indexOf(r); - if (idx < 0) { - app.activities.add(r); - } - updateLRUListLocked(app, true); - - try { - if (app.thread == null) { - throw new RemoteException(); - } - List<ResultInfo> results = null; - List<Intent> newIntents = null; - if (andResume) { - results = r.results; - newIntents = r.newIntents; - } - if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r - + " icicle=" + r.icicle - + " with results=" + results + " newIntents=" + newIntents - + " andResume=" + andResume); - if (andResume) { - EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY, - System.identityHashCode(r), - r.task.taskId, r.shortComponentName); - } - 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 - // and give up. - Log.e(TAG, "Second failure launching " - + r.intent.getComponent().flattenToShortString() - + ", giving up", e); - appDiedLocked(app, app.pid, app.thread); - requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null, - "2nd-crash"); - return false; - } - - // This is the first time we failed -- restart process and - // retry. - app.activities.remove(r); - throw e; - } - - r.launchFailed = false; - if (updateLRUListLocked(r)) { - Log.w(TAG, "Activity " + r - + " being launched, but already in LRU list"); - } - - if (andResume) { - // As part of the process of launching, ActivityThread also performs - // a resume. - r.state = ActivityState.RESUMED; - r.icicle = null; - r.haveState = false; - r.stopped = false; - mResumedActivity = r; - r.task.touchActiveTime(); - completeResumeLocked(r); - pauseIfSleepingLocked(); - } else { - // This activity is not starting in the resumed state... which - // should look like we asked it to pause+stop (but remain visible), - // and it has done so and reported back the current icicle and - // other state. - r.state = ActivityState.STOPPED; - r.stopped = true; - } - - return true; - } - - private final void startSpecificActivityLocked(HistoryRecord r, - boolean andResume, boolean checkConfig) { - // Is this activity's application already running? - ProcessRecord app = getProcessRecordLocked(r.processName, - r.info.applicationInfo.uid); - - if (r.startTime == 0) { - r.startTime = SystemClock.uptimeMillis(); - } - - if (app != null && app.thread != null) { - try { - realStartActivityLocked(r, app, andResume, checkConfig); - return; - } catch (RemoteException e) { - Log.w(TAG, "Exception when starting activity " - + r.intent.getComponent().flattenToShortString(), e); - } - - // If a dead object exception was thrown -- fall through to - // restart the application. - } - - startProcessLocked(r.processName, r.info.applicationInfo, true, 0, - "activity", r.intent.getComponent()); - } - - private final ProcessRecord startProcessLocked(String processName, - ApplicationInfo info, boolean knownToBeDead, int intentFlags, - String hostingType, ComponentName hostingName) { - ProcessRecord app = getProcessRecordLocked(processName, info.uid); - // We don't have to do anything more if: - // (1) There is an existing application record; and - // (2) The caller doesn't think it is dead, OR there is no thread - // object attached to it so we know it couldn't have crashed; and - // (3) There is a pid assigned to it, so it is either starting or - // already running. - if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName - + " app=" + app + " knownToBeDead=" + knownToBeDead - + " thread=" + (app != null ? app.thread : null) - + " pid=" + (app != null ? app.pid : -1)); - if (app != null && - (!knownToBeDead || app.thread == null) && app.pid > 0) { - return app; - } - - String hostingNameStr = hostingName != null - ? hostingName.flattenToShortString() : null; - - if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) { - // If we are in the background, then check to see if this process - // is bad. If so, we will just silently fail. - if (mBadProcesses.get(info.processName, info.uid) != null) { - return null; - } - } else { - // When the user is explicitly starting a process, then clear its - // crash count so that we won't make it bad until they see at - // least one crash dialog again, and make the process good again - // if it had been bad. - mProcessCrashTimes.remove(info.processName, info.uid); - if (mBadProcesses.get(info.processName, info.uid) != null) { - EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid, - info.processName); - mBadProcesses.remove(info.processName, info.uid); - if (app != null) { - app.bad = false; - } - } - } - - if (app == null) { - app = newProcessRecordLocked(null, info, processName); - mProcessNames.put(processName, info.uid, app); - } else { - // If this is a new package in the process, add the package to the list - app.addPackage(info.packageName); - } - - // If the system is not ready yet, then hold off on starting this - // process until it is. - if (!mSystemReady - && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { - if (!mProcessesOnHold.contains(app)) { - mProcessesOnHold.add(app); - } - return app; - } - - startProcessLocked(app, hostingType, hostingNameStr); - return (app.pid != 0) ? app : null; - } - - private final void startProcessLocked(ProcessRecord app, - String hostingType, String hostingNameStr) { - if (app.pid > 0 && app.pid != MY_PID) { - synchronized (mPidsSelfLocked) { - mPidsSelfLocked.remove(app.pid); - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - } - app.pid = 0; - } - - mProcessesOnHold.remove(app); - - updateCpuStats(); - - System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1); - mProcDeaths[0] = 0; - - try { - int uid = app.info.uid; - int[] gids = null; - try { - gids = mContext.getPackageManager().getPackageGids( - app.info.packageName); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to retrieve gids", e); - } - if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) { - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL - && mTopComponent != null - && app.processName.equals(mTopComponent.getPackageName())) { - uid = 0; - } - if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL - && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) { - uid = 0; - } - } - int debugFlags = 0; - if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { - debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; - } - if ("1".equals(SystemProperties.get("debug.checkjni"))) { - debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; - } - if ("1".equals(SystemProperties.get("debug.assert"))) { - debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; - } - int pid = Process.start("android.app.ActivityThread", - mSimpleProcessManagement ? app.processName : null, uid, uid, - gids, debugFlags, null); - BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); - synchronized (bs) { - if (bs.isOnBattery()) { - app.batteryStats.incStartsLocked(); - } - } - - EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid, - app.processName, hostingType, - hostingNameStr != null ? hostingNameStr : ""); - - if (app.persistent) { - Watchdog.getInstance().processStarted(app, app.processName, pid); - } - - StringBuilder buf = new StringBuilder(128); - buf.append("Start proc "); - buf.append(app.processName); - buf.append(" for "); - buf.append(hostingType); - if (hostingNameStr != null) { - buf.append(" "); - buf.append(hostingNameStr); - } - buf.append(": pid="); - buf.append(pid); - buf.append(" uid="); - buf.append(uid); - buf.append(" gids={"); - if (gids != null) { - for (int gi=0; gi<gids.length; gi++) { - if (gi != 0) buf.append(", "); - buf.append(gids[gi]); - - } - } - buf.append("}"); - Log.i(TAG, buf.toString()); - if (pid == 0 || pid == MY_PID) { - // Processes are being emulated with threads. - app.pid = MY_PID; - app.removed = false; - mStartingProcesses.add(app); - } else if (pid > 0) { - app.pid = pid; - app.removed = false; - synchronized (mPidsSelfLocked) { - this.mPidsSelfLocked.put(pid, app); - Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); - msg.obj = app; - mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT); - } - } else { - app.pid = 0; - RuntimeException e = new RuntimeException( - "Failure starting process " + app.processName - + ": returned pid=" + pid); - Log.e(TAG, e.getMessage(), e); - } - } catch (RuntimeException e) { - // XXX do better error recovery. - app.pid = 0; - Log.e(TAG, "Failure starting process " + app.processName, e); - } - } - - private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) { - if (mPausingActivity != null) { - RuntimeException e = new RuntimeException(); - Log.e(TAG, "Trying to pause when pause is already pending for " - + mPausingActivity, e); - } - HistoryRecord prev = mResumedActivity; - if (prev == null) { - RuntimeException e = new RuntimeException(); - Log.e(TAG, "Trying to pause when nothing is resumed", e); - resumeTopActivityLocked(null); - return; - } - if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev); - mResumedActivity = null; - mPausingActivity = prev; - prev.state = ActivityState.PAUSING; - prev.task.touchActiveTime(); - - updateCpuStats(); - - if (prev.app != null && prev.app.thread != null) { - if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev); - try { - EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY, - System.identityHashCode(prev), - 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); - mPausingActivity = null; - } - } else { - mPausingActivity = null; - } - - // If we are not going to sleep, we want to ensure the device is - // awake until the next activity is started. - if (!mSleeping) { - mLaunchingActivity.acquire(); - if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) { - // To be safe, don't allow the wake lock to be held for too long. - Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG); - mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT); - } - } - - - if (mPausingActivity != null) { - // Have the window manager pause its key dispatching until the new - // activity has started. If we're pausing the activity just because - // the screen is being turned off and the UI is sleeping, don't interrupt - // key dispatch; the same activity will pick it up again on wakeup. - if (!uiSleeping) { - prev.pauseKeyDispatchingLocked(); - } else { - if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off"); - } - - // Schedule a pause timeout in case the app doesn't respond. - // We don't give it much time because this directly impacts the - // responsiveness seen by the user. - Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG); - msg.obj = prev; - mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT); - if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete..."); - } else { - // This activity failed to schedule the - // pause, so just treat it as being paused now. - if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next."); - resumeTopActivityLocked(null); - } - } - - 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); - prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE); - } else if (prev.app != null) { - if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev); - if (prev.waitingVisible) { - prev.waitingVisible = false; - mWaitingVisibleActivities.remove(prev); - if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v( - TAG, "Complete pause, no longer waiting: " + prev); - } - if (prev.configDestroy) { - // The previous is being paused because the configuration - // is changing, which means it is actually stopping... - // To juggle the fact that we are also starting a new - // instance right now, we need to first completely stop - // the current instance before starting the new one. - if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev); - destroyActivityLocked(prev, true); - } else { - mStoppingActivities.add(prev); - if (mStoppingActivities.size() > 3) { - // If we already have a few activities waiting to stop, - // then give up on things going idle and start clearing - // them out. - if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle"); - Message msg = Message.obtain(); - msg.what = ActivityManagerService.IDLE_NOW_MSG; - mHandler.sendMessage(msg); - } - } - } else { - if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev); - prev = null; - } - mPausingActivity = null; - } - - if (!mSleeping) { - resumeTopActivityLocked(prev); - } else { - if (mGoingToSleep.isHeld()) { - mGoingToSleep.release(); - } - } - - if (prev != null) { - prev.resumeKeyDispatchingLocked(); - } - } - - /** - * Once we know that we have asked an application to put an activity in - * the resumed state (either by launching it or explicitly telling it), - * this function updates the rest of our state to match that fact. - */ - private final void completeResumeLocked(HistoryRecord next) { - next.idle = false; - next.results = null; - next.newIntents = null; - - // schedule an idle timeout in case the app doesn't do it for us. - Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG); - msg.obj = next; - mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT); - - if (false) { - // The activity was never told to pause, so just keep - // things going as-is. To maintain our own state, - // we need to emulate it coming back and saying it is - // idle. - msg = mHandler.obtainMessage(IDLE_NOW_MSG); - msg.obj = next; - mHandler.sendMessage(msg); - } - - next.thumbnail = null; - setFocusedActivityLocked(next); - next.resumeKeyDispatchingLocked(); - ensureActivitiesVisibleLocked(null, 0); - mWindowManager.executeAppTransition(); - } - - /** - * Make sure that all activities that need to be visible (that is, they - * currently can be seen by the user) actually are. - */ - private final void ensureActivitiesVisibleLocked(HistoryRecord top, - HistoryRecord starting, String onlyThisProcess, int configChanges) { - if (DEBUG_VISBILITY) Log.v( - TAG, "ensureActivitiesVisible behind " + top - + " configChanges=0x" + Integer.toHexString(configChanges)); - - // If the top activity is not fullscreen, then we need to - // make sure any activities under it are now visible. - final int count = mHistory.size(); - int i = count-1; - while (mHistory.get(i) != top) { - i--; - } - HistoryRecord r; - boolean behindFullscreen = false; - for (; i>=0; i--) { - r = (HistoryRecord)mHistory.get(i); - if (DEBUG_VISBILITY) Log.v( - TAG, "Make visible? " + r + " finishing=" + r.finishing - + " state=" + r.state); - if (r.finishing) { - continue; - } - - final boolean doThisProcess = onlyThisProcess == null - || onlyThisProcess.equals(r.processName); - - // First: if this is not the current activity being started, make - // sure it matches the current configuration. - if (r != starting && doThisProcess) { - ensureActivityConfigurationLocked(r); - } - - if (r.app == null || r.app.thread == null) { - if (onlyThisProcess == null - || onlyThisProcess.equals(r.processName)) { - // This activity needs to be visible, but isn't even - // running... get it started, but don't resume it - // at this point. - if (DEBUG_VISBILITY) Log.v( - TAG, "Start and freeze screen for " + r); - if (r != starting) { - r.startFreezingScreenLocked(r.app, configChanges); - } - if (!r.visible) { - if (DEBUG_VISBILITY) Log.v( - TAG, "Starting and making visible: " + r); - mWindowManager.setAppVisibility(r, true); - } - if (r != starting) { - startSpecificActivityLocked(r, false, false); - } - } - - } else if (r.visible) { - // If this activity is already visible, then there is nothing - // else to do here. - if (DEBUG_VISBILITY) Log.v( - TAG, "Skipping: already visible at " + r); - r.stopFreezingScreenLocked(false); - - } else if (onlyThisProcess == null) { - // This activity is not currently visible, but is running. - // Tell it to become visible. - r.visible = true; - if (r.state != ActivityState.RESUMED && r != starting) { - // If this activity is paused, tell it - // to now show its window. - if (DEBUG_VISBILITY) Log.v( - TAG, "Making visible and scheduling visibility: " + r); - try { - mWindowManager.setAppVisibility(r, true); - r.app.thread.scheduleWindowVisibility(r, true); - r.stopFreezingScreenLocked(false); - } catch (Exception e) { - // Just skip on any failure; we'll make it - // visible when it next restarts. - Log.w(TAG, "Exception thrown making visibile: " - + r.intent.getComponent(), e); - } - } - } - - // Aggregate current change flags. - configChanges |= r.configChangeFlags; - - if (r.fullscreen) { - // At this point, nothing else needs to be shown - if (DEBUG_VISBILITY) Log.v( - TAG, "Stopping: fullscreen at " + r); - behindFullscreen = true; - i--; - break; - } - } - - // Now for any activities that aren't visible to the user, make - // sure they no longer are keeping the screen frozen. - while (i >= 0) { - r = (HistoryRecord)mHistory.get(i); - if (DEBUG_VISBILITY) Log.v( - TAG, "Make invisible? " + r + " finishing=" + r.finishing - + " state=" + r.state - + " behindFullscreen=" + behindFullscreen); - if (!r.finishing) { - if (behindFullscreen) { - if (r.visible) { - if (DEBUG_VISBILITY) Log.v( - TAG, "Making invisible: " + r); - r.visible = false; - try { - mWindowManager.setAppVisibility(r, false); - if ((r.state == ActivityState.STOPPING - || r.state == ActivityState.STOPPED) - && r.app != null && r.app.thread != null) { - if (DEBUG_VISBILITY) Log.v( - TAG, "Scheduling invisibility: " + r); - r.app.thread.scheduleWindowVisibility(r, false); - } - } catch (Exception e) { - // Just skip on any failure; we'll make it - // visible when it next restarts. - Log.w(TAG, "Exception thrown making hidden: " - + r.intent.getComponent(), e); - } - } else { - if (DEBUG_VISBILITY) Log.v( - TAG, "Already invisible: " + r); - } - } else if (r.fullscreen) { - if (DEBUG_VISBILITY) Log.v( - TAG, "Now behindFullscreen: " + r); - behindFullscreen = true; - } - } - i--; - } - } - - /** - * Version of ensureActivitiesVisible that can easily be called anywhere. - */ - private final void ensureActivitiesVisibleLocked(HistoryRecord starting, - int configChanges) { - HistoryRecord r = topRunningActivityLocked(null); - if (r != null) { - 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. - * - * @param prev The previously resumed activity, for when in the process - * of pausing; can be null to call from elsewhere. - * - * @return Returns true if something is being resumed, or false if - * nothing happened. - */ - private final boolean resumeTopActivityLocked(HistoryRecord prev) { - // Find the first activity that is not finishing. - HistoryRecord next = topRunningActivityLocked(null); - - // Remember how we'll process this pause/resume situation, and ensure - // that the state is reset however we wind up proceeding. - final boolean userLeaving = mUserLeaving; - mUserLeaving = false; - - if (next == null) { - // There are no more activities! Let's just start up the - // Launcher... - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL - && mTopAction == null) { - // We are running in factory test mode, but unable to find - // the factory test app, so just sit around displaying the - // error message and don't try to start anything. - return false; - } - Intent intent = new Intent( - mTopAction, - mTopData != null ? Uri.parse(mTopData) : null); - intent.setComponent(mTopComponent); - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - intent.addCategory(Intent.CATEGORY_HOME); - } - ActivityInfo aInfo = - intent.resolveActivityInfo(mContext.getPackageManager(), - PackageManager.GET_SHARED_LIBRARY_FILES); - if (aInfo != null) { - intent.setComponent(new ComponentName( - aInfo.applicationInfo.packageName, aInfo.name)); - // Don't do this if the home app is currently being - // instrumented. - ProcessRecord app = getProcessRecordLocked(aInfo.processName, - aInfo.applicationInfo.uid); - if (app == null || app.instrumentationClass == null) { - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivityLocked(null, intent, null, null, 0, aInfo, - null, null, 0, 0, 0, false); - } - } - return true; - } - - // If the top activity is the resumed one, nothing to do. - if (mResumedActivity == next && next.state == ActivityState.RESUMED) { - // Make sure we have executed any pending transitions, since there - // should be nothing left to do at this point. - mWindowManager.executeAppTransition(); - return false; - } - - // The activity may be waiting for stop, but that is no longer - // appropriate for it. - mStoppingActivities.remove(next); - mWaitingVisibleActivities.remove(next); - - if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next); - - // If we are currently pausing an activity, then don't do anything - // until that is done. - if (mPausingActivity != null) { - if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity); - return false; - } - - // We need to start pausing the current activity so the top one - // can be resumed... - if (mResumedActivity != null) { - if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing"); - startPausingLocked(userLeaving, false); - return true; - } - - if (prev != null && prev != next) { - if (!prev.waitingVisible && next != null && !next.nowVisible) { - prev.waitingVisible = true; - mWaitingVisibleActivities.add(prev); - if (DEBUG_SWITCH) Log.v( - TAG, "Resuming top, waiting visible to hide: " + prev); - } else { - // The next activity is already visible, so hide the previous - // activity's windows right now so we can show the new one ASAP. - // We only do this if the previous is finishing, which should mean - // it is on top of the one being resumed so hiding it quickly - // is good. Otherwise, we want to do the normal route of allowing - // the resumed activity to be shown so we can decide if the - // previous should actually be hidden depending on whether the - // new one is found to be full-screen or not. - if (prev.finishing) { - mWindowManager.setAppVisibility(prev, false); - if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: " - + prev + ", waitingVisible=" - + (prev != null ? prev.waitingVisible : null) - + ", nowVisible=" + next.nowVisible); - } else { - if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: " - + prev + ", waitingVisible=" - + (prev != null ? prev.waitingVisible : null) - + ", nowVisible=" + next.nowVisible); - } - } - } - - // We are starting up the next activity, so tell the window manager - // that the previous one will be hidden soon. This way it can know - // to ignore it when computing the desired screen orientation. - if (prev != null) { - if (prev.finishing) { - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare close transition: prev=" + prev); - mWindowManager.prepareAppTransition(prev.task == next.task - ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE - : WindowManagerPolicy.TRANSIT_TASK_CLOSE); - mWindowManager.setAppWillBeHidden(prev); - mWindowManager.setAppVisibility(prev, false); - } else { - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare open transition: prev=" + prev); - mWindowManager.prepareAppTransition(prev.task == next.task - ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN - : WindowManagerPolicy.TRANSIT_TASK_OPEN); - } - if (false) { - mWindowManager.setAppWillBeHidden(prev); - mWindowManager.setAppVisibility(prev, false); - } - } else if (mHistory.size() > 1) { - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare open transition: no previous"); - mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN); - } - - if (next.app != null && next.app.thread != null) { - if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next); - - // This activity is now becoming visible. - mWindowManager.setAppVisibility(next, true); - - HistoryRecord lastResumedActivity = mResumedActivity; - ActivityState lastState = next.state; - - updateCpuStats(); - - next.state = ActivityState.RESUMED; - mResumedActivity = next; - next.task.touchActiveTime(); - updateLRUListLocked(next.app, true); - updateLRUListLocked(next); - - // Have the window manager re-evaluate the orientation of - // the screen based on the new activity order. - Configuration config = mWindowManager.updateOrientationFromAppTokens( - next.mayFreezeScreenLocked(next.app) ? next : null); - if (config != null) { - next.frozenBeforeDestroy = true; - } - if (!updateConfigurationLocked(config, next)) { - // The configuration update wasn't able to keep the existing - // instance of the activity, and instead started a new one. - // We should be all done, but let's just make sure our activity - // is still at the top and schedule another run if something - // weird happened. - HistoryRecord nextNext = topRunningActivityLocked(null); - if (DEBUG_SWITCH) Log.i(TAG, - "Activity config changed during resume: " + next - + ", new next: " + nextNext); - if (nextNext != next) { - // Do over! - mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG); - } - return true; - } - - try { - // Deliver all pending results. - ArrayList a = next.results; - if (a != null) { - final int N = a.size(); - if (!next.finishing && N > 0) { - if (localLOGV) Log.v( - TAG, "Delivering results to " + next - + ": " + a); - next.app.thread.scheduleSendResult(next, a); - } - } - - if (next.newIntents != null) { - next.app.thread.scheduleNewIntent(next.newIntents, next); - } - - EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY, - System.identityHashCode(next), - next.task.taskId, next.shortComponentName); - updateUsageStats(next, true); - - next.app.thread.scheduleResumeActivity(next, - isNextTransitionForward()); - pauseIfSleepingLocked(); - - } catch (Exception e) { - // Whoops, need to restart this activity! - next.state = lastState; - mResumedActivity = lastResumedActivity; - if (Config.LOGD) Log.d(TAG, - "Restarting because process died: " + next); - if (!next.hasBeenLaunched) { - next.hasBeenLaunched = true; - } else { - if (SHOW_APP_STARTING_ICON) { - mWindowManager.setAppStartingWindow( - next, next.packageName, next.theme, - next.nonLocalizedLabel, - next.labelRes, next.icon, null, true); - } - } - startSpecificActivityLocked(next, true, false); - return true; - } - - // From this point on, if something goes wrong there is no way - // to recover the activity. - try { - next.visible = true; - completeResumeLocked(next); - } catch (Exception e) { - // If any exception gets thrown, toss away this - // activity and try the next one. - Log.w(TAG, "Exception thrown during resume of " + next, e); - requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null, - "resume-exception"); - return true; - } - - // Didn't need to use the icicle, and it is now out of date. - next.icicle = null; - next.haveState = false; - next.stopped = false; - - } else { - // Whoops, need to restart this activity! - if (!next.hasBeenLaunched) { - next.hasBeenLaunched = true; - } else { - if (SHOW_APP_STARTING_ICON) { - mWindowManager.setAppStartingWindow( - next, next.packageName, next.theme, - next.nonLocalizedLabel, - next.labelRes, next.icon, null, true); - } - if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next); - } - startSpecificActivityLocked(next, true, true); - } - - return true; - } - - private final void startActivityLocked(HistoryRecord r, boolean newTask) { - final int NH = mHistory.size(); - - int addPos = -1; - - if (!newTask) { - // If starting in an existing task, find where that is... - HistoryRecord next = null; - boolean startIt = true; - for (int i = NH-1; i >= 0; i--) { - HistoryRecord p = (HistoryRecord)mHistory.get(i); - if (p.finishing) { - continue; - } - if (p.task == r.task) { - // Here it is! Now, if this is not yet visible to the - // user, then just add it without starting; it will - // get started when the user navigates back to it. - addPos = i+1; - if (!startIt) { - mHistory.add(addPos, r); - r.inHistory = true; - r.task.numActivities++; - mWindowManager.addAppToken(addPos, r, r.task.taskId, - r.info.screenOrientation, r.fullscreen); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - return; - } - break; - } - if (p.fullscreen) { - startIt = false; - } - next = p; - } - } - - // Place a new activity at top of stack, so it is next to interact - // with the user. - if (addPos < 0) { - addPos = mHistory.size(); - } - - // If we are not placing the new activity frontmost, we do not want - // to deliver the onUserLeaving callback to the actual frontmost - // activity - if (addPos < NH) { - mUserLeaving = false; - if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false"); - } - - // Slot the activity into the history stack and proceed - mHistory.add(addPos, r); - r.inHistory = true; - r.frontOfTask = newTask; - r.task.numActivities++; - if (NH > 0) { - // We want to show the starting preview window if we are - // switching to a new task, or the next activity's process is - // not currently running. - boolean showStartingIcon = newTask; - ProcessRecord proc = r.app; - if (proc == null) { - proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid); - } - if (proc == null || proc.thread == null) { - showStartingIcon = true; - } - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare open transition: starting " + r); - mWindowManager.prepareAppTransition(newTask - ? WindowManagerPolicy.TRANSIT_TASK_OPEN - : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN); - mWindowManager.addAppToken( - addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen); - boolean doShow = true; - if (newTask) { - // Even though this activity is starting fresh, we still need - // to reset it to make sure we apply affinities to move any - // existing activities from other tasks in to it. - // If the caller has requested that the target task be - // reset, then do so. - if ((r.intent.getFlags() - &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { - resetTaskIfNeededLocked(r, r); - doShow = topRunningActivityLocked(null) == r; - } - } - if (SHOW_APP_STARTING_ICON && doShow) { - // Figure out if we are transitioning from another activity that is - // "has the same starting icon" as the next one. This allows the - // window manager to keep the previous window it had previously - // created, if it still had one. - HistoryRecord prev = mResumedActivity; - if (prev != null) { - // 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 already displayed. - else if (prev.nowVisible) prev = null; - } - mWindowManager.setAppStartingWindow( - r, r.packageName, r.theme, r.nonLocalizedLabel, - r.labelRes, r.icon, prev, showStartingIcon); - } - } else { - // If this is the first activity, don't do any fancy animations, - // because there is nothing for it to animate on top of. - mWindowManager.addAppToken(addPos, r, r.task.taskId, - r.info.screenOrientation, r.fullscreen); - } - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - - resumeTopActivityLocked(null); - } - - /** - * Perform clear operation as requested by - * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: assuming the top task on the - * stack is the one that the new activity is being launched in, look for - * an instance of that activity in the stack and, if found, finish all - * activities on top of it and return the instance. - * - * @param newR Description of the new activity being started. - * @return Returns the old activity that should be continue to be used, - * or null if none was found. - */ - private final HistoryRecord performClearTopTaskLocked(int taskId, - HistoryRecord newR, boolean doClear) { - int i = mHistory.size(); - while (i > 0) { - i--; - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.finishing) { - continue; - } - if (r.task.taskId != taskId) { - return null; - } - if (r.realActivity.equals(newR.realActivity)) { - // Here it is! Now finish everything in front... - HistoryRecord ret = r; - if (doClear) { - while (i < (mHistory.size()-1)) { - i++; - r = (HistoryRecord)mHistory.get(i); - if (r.finishing) { - continue; - } - if (finishActivityLocked(r, i, Activity.RESULT_CANCELED, - null, "clear")) { - i--; - } - } - } - - // Finally, if this is a normal launch mode (that is, not - // expecting onNewIntent()), then we will finish the current - // instance of the activity so a new fresh one can be started. - if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) { - if (!ret.finishing) { - int index = indexOfTokenLocked(ret, false); - if (index >= 0) { - finishActivityLocked(ret, 0, Activity.RESULT_CANCELED, - null, "clear"); - } - return null; - } - } - - return ret; - } - } - - return null; - } - - /** - * 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. - */ - private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) { - boolean sent = false; - if (r.state == ActivityState.RESUMED - && r.app != null && r.app.thread != null) { - try { - ArrayList<Intent> ar = new ArrayList<Intent>(); - ar.add(new Intent(intent)); - r.app.thread.scheduleNewIntent(ar, r); - sent = true; - } catch (Exception e) { - Log.w(TAG, "Exception thrown sending new intent to " + r, e); - } - } - if (!sent) { - r.addNewIntentLocked(new Intent(intent)); - } - } - - private final void logStartActivity(int tag, HistoryRecord r, - TaskRecord task) { - EventLog.writeEvent(tag, - System.identityHashCode(r), task.taskId, - r.shortComponentName, r.intent.getAction(), - r.intent.getType(), r.intent.getDataString(), - r.intent.getFlags()); - } - - private final int startActivityLocked(IApplicationThread caller, - Intent intent, String resolvedType, - Uri[] grantedUriPermissions, - int grantedMode, ActivityInfo aInfo, IBinder resultTo, - String resultWho, int requestCode, - int callingPid, int callingUid, boolean onlyIfNeeded) { - Log.i(TAG, "Starting activity: " + intent); - - HistoryRecord sourceRecord = null; - HistoryRecord resultRecord = null; - if (resultTo != null) { - int index = indexOfTokenLocked(resultTo, false); - if (localLOGV) Log.v( - TAG, "Sending result to " + resultTo + " (index " + index + ")"); - if (index >= 0) { - sourceRecord = (HistoryRecord)mHistory.get(index); - if (requestCode >= 0 && !sourceRecord.finishing) { - resultRecord = sourceRecord; - } - } - } - - int launchFlags = intent.getFlags(); - - if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 - && sourceRecord != null) { - // Transfer the result target from the source activity to the new - // one being started, including any failures. - if (requestCode >= 0) { - return START_FORWARD_AND_REQUEST_CONFLICT; - } - resultRecord = sourceRecord.resultTo; - resultWho = sourceRecord.resultWho; - requestCode = sourceRecord.requestCode; - sourceRecord.resultTo = null; - if (resultRecord != null) { - resultRecord.removeResultsLocked( - sourceRecord, resultWho, requestCode); - } - } - - int err = START_SUCCESS; - - if (intent.getComponent() == null) { - // We couldn't find a class that can handle the given Intent. - // That's the end of that! - err = START_INTENT_NOT_RESOLVED; - } - - if (err == START_SUCCESS && aInfo == null) { - // We couldn't find the specific class specified in the Intent. - // Also the end of the line. - err = START_CLASS_NOT_FOUND; - } - - ProcessRecord callerApp = null; - if (err == START_SUCCESS && caller != null) { - callerApp = getRecordForAppLocked(caller); - if (callerApp != null) { - callingPid = callerApp.pid; - callingUid = callerApp.info.uid; - } else { - Log.w(TAG, "Unable to find app for caller " + caller - + " (pid=" + callingPid + ") when starting: " - + intent.toString()); - err = START_PERMISSION_DENIED; - } - } - - if (err != START_SUCCESS) { - if (resultRecord != null) { - sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, - Activity.RESULT_CANCELED, null); - } - return err; - } - - final int perm = checkComponentPermission(aInfo.permission, callingPid, - callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid); - if (perm != PackageManager.PERMISSION_GRANTED) { - if (resultRecord != null) { - sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, - Activity.RESULT_CANCELED, null); - } - String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ")" - + " requires " + aInfo.permission; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - if (mWatcher != null) { - boolean abort = false; - try { - // The Intent we give to the watcher has the extra data - // stripped off, since it can contain private information. - Intent watchIntent = intent.cloneFilter(); - abort = !mWatcher.activityStarting(watchIntent, - aInfo.applicationInfo.packageName); - } catch (RemoteException e) { - mWatcher = null; - } - - if (abort) { - if (resultRecord != null) { - sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, - Activity.RESULT_CANCELED, null); - } - // We pretend to the caller that it was really started, but - // they will just get a cancel result. - return START_SUCCESS; - } - } - - HistoryRecord r = new HistoryRecord(this, callerApp, callingUid, - intent, resolvedType, aInfo, mConfiguration, - resultRecord, resultWho, requestCode); - r.startTime = SystemClock.uptimeMillis(); - - HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) - != 0 ? r : null; - - // We'll invoke onUserLeaving before onPause only if the launching - // activity did not explicitly state that this is an automated launch. - mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; - if (DEBUG_USER_LEAVING) Log.v(TAG, - "startActivity() => mUserLeaving=" + mUserLeaving); - - // If the onlyIfNeeded flag is set, then we can do this if the activity - // being launched is the same as the one making the call... or, as - // a special case, if we do not know the caller then we count the - // current top activity as the caller. - if (onlyIfNeeded) { - HistoryRecord checkedCaller = sourceRecord; - if (checkedCaller == null) { - checkedCaller = topRunningActivityLocked(notTop); - } - if (!checkedCaller.realActivity.equals(r.realActivity)) { - // Caller is not the same as launcher, so always needed. - onlyIfNeeded = false; - } - } - - if (grantedUriPermissions != null && callingUid > 0) { - for (int i=0; i<grantedUriPermissions.length; i++) { - grantUriPermissionLocked(callingUid, r.packageName, - grantedUriPermissions[i], grantedMode, r); - } - } - - grantUriPermissionFromIntentLocked(callingUid, r.packageName, - intent, r); - - if (sourceRecord == null) { - // This activity is not being started from another... in this - // case we -always- start a new task. - if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { - Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: " - + intent); - launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; - } - } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { - // The original activity who is starting us is running as a single - // instance... this new activity it is starting must go on its - // own task. - launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; - } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { - // The activity being started is a single instance... it always - // gets launched into its own task. - launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; - } - - if (resultRecord != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { - // For whatever reason this activity is being launched into a new - // task... yet the caller has requested a result back. Well, that - // is pretty messed up, so instead immediately send back a cancel - // and let the new task continue launched as normal without a - // dependency on its originator. - Log.w(TAG, "Activity is launching as a new task, so cancelling activity result."); - sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, - Activity.RESULT_CANCELED, null); - r.resultTo = null; - resultRecord = null; - } - - boolean addingToTask = false; - if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && - (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { - // If bring to front is requested, and no result is requested, and - // we can find a task that was started with this same - // component, then instead of launching bring that one to the front. - if (resultRecord == null) { - // See if there is a task to bring to the front. If this is - // a SINGLE_INSTANCE activity, there can be one and only one - // instance of it in the history, and it is always in its own - // unique task, so we do a special search. - HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE - ? findTaskLocked(intent, r.info) - : findActivityLocked(intent, r.info); - if (taskTop != null) { - if (taskTop.task.intent == null) { - // This task was started because of movement of - // the activity based on affinity... now that we - // are actually launching it, we can assign the - // base intent. - taskTop.task.setIntent(intent, r.info); - } - // If the target task is not in the front, then we need - // to bring it to the front... except... well, with - // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like - // to have the same behavior as if a new instance was - // being started, which means not bringing it to the front - // if the caller is not itself in the front. - HistoryRecord curTop = topRunningActivityLocked(notTop); - if (curTop.task != taskTop.task) { - r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); - boolean callerAtFront = sourceRecord == null - || curTop.task == sourceRecord.task; - if (callerAtFront) { - // We really do want to push this one into the - // user's face, right now. - moveTaskToFrontLocked(taskTop.task); - } - } - // If the caller has requested that the target task be - // reset, then do so. - if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { - taskTop = resetTaskIfNeededLocked(taskTop, r); - } - if (onlyIfNeeded) { - // We don't need to start a new activity, and - // the client said not to do anything if that - // is the case, so this is it! And for paranoia, make - // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); - return START_RETURN_INTENT_TO_CALLER; - } - if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { - // In this situation we want to remove all activities - // from the task up to the one being started. In most - // cases this means we are resetting the task to its - // initial state. - HistoryRecord top = performClearTopTaskLocked( - taskTop.task.taskId, r, true); - if (top != null) { - if (top.frontOfTask) { - // Activity aliases may mean we use different - // intents for the top activity, so make sure - // the task now has the identity of the new - // intent. - top.task.setIntent(r.intent, r.info); - } - logStartActivity(LOG_AM_NEW_INTENT, r, top.task); - deliverNewIntentLocked(top, r.intent); - } else { - // A special case: we need to - // start the activity because it is not currently - // running, and the caller has asked to clear the - // current task to have this activity at the top. - addingToTask = true; - // Now pretend like this activity is being started - // by the top of its task, so it is put in the - // right place. - sourceRecord = taskTop; - } - } else if (r.realActivity.equals(taskTop.task.realActivity)) { - // In this case the top activity on the task is the - // same as the one being launched, so we take that - // as a request to bring the task to the foreground. - // If the top activity in the task is the root - // activity, deliver this new intent to it if it - // desires. - if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 - && taskTop.realActivity.equals(r.realActivity)) { - logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task); - if (taskTop.frontOfTask) { - taskTop.task.setIntent(r.intent, r.info); - } - deliverNewIntentLocked(taskTop, r.intent); - } else if (!r.intent.filterEquals(taskTop.task.intent)) { - // In this case we are launching the root activity - // of the task, but with a different intent. We - // should start a new instance on top. - addingToTask = true; - sourceRecord = taskTop; - } - } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) { - // In this case an activity is being launched in to an - // existing task, without resetting that task. This - // is typically the situation of launching an activity - // from a notification or shortcut. We want to place - // the new activity on top of the current task. - addingToTask = true; - sourceRecord = taskTop; - } else if (!taskTop.task.rootWasReset) { - // In this case we are launching in to an existing task - // that has not yet been started from its front door. - // The current task has been brought to the front. - // Ideally, we'd probably like to place this new task - // at the bottom of its stack, but that's a little hard - // to do with the current organization of the code so - // for now we'll just drop it. - taskTop.task.setIntent(r.intent, r.info); - } - if (!addingToTask) { - // We didn't do anything... but it was needed (a.k.a., client - // don't use that intent!) And for paranoia, make - // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); - return START_TASK_TO_FRONT; - } - } - } - } - - //String uri = r.intent.toURI(); - //Intent intent2 = new Intent(uri); - //Log.i(TAG, "Given intent: " + r.intent); - //Log.i(TAG, "URI is: " + uri); - //Log.i(TAG, "To intent: " + intent2); - - if (r.packageName != null) { - // If the activity being launched is the same as the one currently - // at the top, then we need to check if it should only be launched - // once. - HistoryRecord top = topRunningActivityLocked(notTop); - if (top != null && resultRecord == null) { - if (top.realActivity.equals(r.realActivity)) { - if (top.app != null && top.app.thread != null) { - if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP - || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { - logStartActivity(LOG_AM_NEW_INTENT, top, top.task); - // For paranoia, make sure we have correctly - // resumed the top activity. - resumeTopActivityLocked(null); - if (onlyIfNeeded) { - // We don't need to start a new activity, and - // the client said not to do anything if that - // is the case, so this is it! - return START_RETURN_INTENT_TO_CALLER; - } - deliverNewIntentLocked(top, r.intent); - return START_DELIVERED_TO_TOP; - } - } - } - } - - } else { - if (resultRecord != null) { - sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, - Activity.RESULT_CANCELED, null); - } - return START_CLASS_NOT_FOUND; - } - - boolean newTask = false; - - // Should this be considered a new task? - if (resultRecord == null && !addingToTask - && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { - // todo: should do better management of integers. - mCurTask++; - if (mCurTask <= 0) { - mCurTask = 1; - } - r.task = new TaskRecord(mCurTask, r.info, intent, - (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0); - if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r - + " in new task " + r.task); - newTask = true; - addRecentTask(r.task); - - } else if (sourceRecord != null) { - if (!addingToTask && - (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - // In this case, we are adding the activity to an existing - // task, but the caller has asked to clear that task if the - // activity is already running. - HistoryRecord top = performClearTopTaskLocked( - sourceRecord.task.taskId, r, true); - if (top != null) { - logStartActivity(LOG_AM_NEW_INTENT, r, top.task); - deliverNewIntentLocked(top, r.intent); - // For paranoia, make sure we have correctly - // resumed the top activity. - 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 - // it. - r.task = sourceRecord.task; - if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r - + " in existing task " + r.task); - - } else { - // This not being started from an existing activity, and not part - // of a new task... just put it in the top task, though these days - // this case should never happen. - final int N = mHistory.size(); - HistoryRecord prev = - N > 0 ? (HistoryRecord)mHistory.get(N-1) : null; - r.task = prev != null - ? prev.task - : new TaskRecord(mCurTask, r.info, intent, - (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0); - if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r - + " in new guessed " + r.task); - } - if (newTask) { - EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId); - } - logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task); - startActivityLocked(r, newTask); - return START_SUCCESS; - } - - public final int startActivity(IApplicationThread caller, - Intent intent, String resolvedType, Uri[] grantedUriPermissions, - int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - // Don't modify the client's object! - intent = new Intent(intent); - - // Collect information about the target of the Intent. - // Must do this before locking, because resolving the intent - // may require launching a process to run its content provider. - ActivityInfo aInfo; - try { - ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveIntent( - intent, resolvedType, - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); - aInfo = rInfo != null ? rInfo.activityInfo : null; - } catch (RemoteException e) { - aInfo = null; - } - - if (aInfo != null) { - // Store the found target back into the intent, because now that - // we have it we never want to do this again. For example, if the - // user navigates back to this point in the history, we should - // always restart the exact same activity. - intent.setComponent(new ComponentName( - aInfo.applicationInfo.packageName, aInfo.name)); - - // Don't debug things in the system process - if (debug) { - if (!aInfo.processName.equals("system")) { - setDebugApp(aInfo.processName, true, false); - } - } - } - - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - int res = startActivityLocked(caller, intent, resolvedType, - grantedUriPermissions, grantedMode, aInfo, - resultTo, resultWho, requestCode, -1, -1, - onlyIfNeeded); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - public boolean startNextMatchingActivity(IBinder callingActivity, - Intent intent) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized (this) { - int index = indexOfTokenLocked(callingActivity, false); - if (index < 0) { - return false; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - if (r.app == null || r.app.thread == null) { - // The caller is not running... d'oh! - return false; - } - intent = new Intent(intent); - // The caller is not allowed to change the data. - intent.setDataAndType(r.intent.getData(), r.intent.getType()); - // And we are resetting to find the next component... - intent.setComponent(null); - - ActivityInfo aInfo = null; - try { - List<ResolveInfo> resolves = - ActivityThread.getPackageManager().queryIntentActivities( - intent, r.resolvedType, - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); - - // Look for the original activity in the list... - final int N = resolves != null ? resolves.size() : 0; - for (int i=0; i<N; i++) { - ResolveInfo rInfo = resolves.get(i); - if (rInfo.activityInfo.packageName.equals(r.packageName) - && rInfo.activityInfo.name.equals(r.info.name)) { - // We found the current one... the next matching is - // after it. - i++; - if (i<N) { - aInfo = resolves.get(i).activityInfo; - } - break; - } - } - } catch (RemoteException e) { - } - - if (aInfo == null) { - // Nobody who is next! - return false; - } - - intent.setComponent(new ComponentName( - aInfo.applicationInfo.packageName, aInfo.name)); - intent.setFlags(intent.getFlags()&~( - Intent.FLAG_ACTIVITY_FORWARD_RESULT| - Intent.FLAG_ACTIVITY_CLEAR_TOP| - Intent.FLAG_ACTIVITY_MULTIPLE_TASK| - Intent.FLAG_ACTIVITY_NEW_TASK)); - - // Okay now we need to start the new activity, replacing the - // currently running activity. This is a little tricky because - // we want to start the new one as if the current one is finished, - // but not finish the current one first so that there is no flicker. - // And thus... - final boolean wasFinishing = r.finishing; - r.finishing = true; - - // Propagate reply information over to the new activity. - final HistoryRecord resultTo = r.resultTo; - final String resultWho = r.resultWho; - final int requestCode = r.requestCode; - r.resultTo = null; - if (resultTo != null) { - resultTo.removeResultsLocked(r, resultWho, requestCode); - } - - final long origId = Binder.clearCallingIdentity(); - // XXX we are not dealing with propagating grantedUriPermissions... - // those are not yet exposed to user code, so there is no need. - int res = startActivityLocked(r.app.thread, intent, - r.resolvedType, null, 0, aInfo, resultTo, resultWho, - requestCode, -1, r.launchedFromUid, false); - Binder.restoreCallingIdentity(origId); - - r.finishing = wasFinishing; - if (res != START_SUCCESS) { - return false; - } - return true; - } - } - - final int startActivityInPackage(int uid, - Intent intent, String resolvedType, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded) { - // Don't modify the client's object! - intent = new Intent(intent); - - // Collect information about the target of the Intent. - // Must do this before locking, because resolving the intent - // may require launching a process to run its content provider. - ActivityInfo aInfo; - try { - ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveIntent( - intent, resolvedType, - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.GET_SHARED_LIBRARY_FILES); - aInfo = rInfo != null ? rInfo.activityInfo : null; - } catch (RemoteException e) { - aInfo = null; - } - - if (aInfo != null) { - // Store the found target back into the intent, because now that - // we have it we never want to do this again. For example, if the - // user navigates back to this point in the history, we should - // always restart the exact same activity. - intent.setComponent(new ComponentName( - aInfo.applicationInfo.packageName, aInfo.name)); - } - - synchronized(this) { - return startActivityLocked(null, intent, resolvedType, - null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid, - onlyIfNeeded); - } - } - - private final void addRecentTask(TaskRecord task) { - // Remove any existing entries that are the same kind of task. - int N = mRecentTasks.size(); - for (int i=0; i<N; i++) { - TaskRecord tr = mRecentTasks.get(i); - if ((task.affinity != null && task.affinity.equals(tr.affinity)) - || (task.intent != null && task.intent.filterEquals(tr.intent))) { - mRecentTasks.remove(i); - i--; - N--; - if (task.intent == null) { - // If the new recent task we are adding is not fully - // specified, then replace it with the existing recent task. - task = tr; - } - } - } - if (N >= MAX_RECENT_TASKS) { - mRecentTasks.remove(N-1); - } - mRecentTasks.add(0, task); - } - - public void setRequestedOrientation(IBinder token, - int requestedOrientation) { - synchronized (this) { - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - final long origId = Binder.clearCallingIdentity(); - mWindowManager.setAppOrientation(r, requestedOrientation); - Configuration config = mWindowManager.updateOrientationFromAppTokens( - r.mayFreezeScreenLocked(r.app) ? r : null); - if (config != null) { - r.frozenBeforeDestroy = true; - if (!updateConfigurationLocked(config, r)) { - resumeTopActivityLocked(null); - } - } - Binder.restoreCallingIdentity(origId); - } - } - - public int getRequestedOrientation(IBinder token) { - synchronized (this) { - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - return mWindowManager.getAppOrientation(r); - } - } - - private final void stopActivityLocked(HistoryRecord r) { - if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r); - if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0 - || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) { - if (!r.finishing) { - requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null, - "no-history"); - } - } else if (r.app != null && r.app.thread != null) { - if (mFocusedActivity == r) { - setFocusedActivityLocked(topRunningActivityLocked(null)); - } - r.resumeKeyDispatchingLocked(); - try { - r.stopped = false; - r.state = ActivityState.STOPPING; - if (DEBUG_VISBILITY) Log.v( - TAG, "Stopping visible=" + r.visible + " for " + r); - if (!r.visible) { - mWindowManager.setAppVisibility(r, false); - } - r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags); - } catch (Exception e) { - // Maybe just ignore exceptions here... if the process - // has crashed, our death notification will clean things - // up. - Log.w(TAG, "Exception thrown during pause", e); - // Just in case, assume it to be stopped. - r.stopped = true; - r.state = ActivityState.STOPPED; - if (r.configDestroy) { - destroyActivityLocked(r, true); - } - } - } - } - - /** - * @return Returns true if the activity is being finished, false if for - * some reason it is being left as-is. - */ - private final boolean requestFinishActivityLocked(IBinder token, int resultCode, - Intent resultData, String reason) { - if (localLOGV) Log.v( - TAG, "Finishing activity: token=" + token - + ", result=" + resultCode + ", data=" + resultData); - - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return false; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - - // Is this the last activity left? - boolean lastActivity = true; - for (int i=mHistory.size()-1; i>=0; i--) { - HistoryRecord p = (HistoryRecord)mHistory.get(i); - if (!p.finishing && p != r) { - lastActivity = false; - break; - } - } - - // If this is the last activity, but it is the home activity, then - // just don't finish it. - if (lastActivity) { - if (r.intent.hasCategory(Intent.CATEGORY_HOME)) { - return false; - } - } - - finishActivityLocked(r, index, resultCode, resultData, reason); - return true; - } - - /** - * @return Returns true if this activity has been removed from the history - * list, or false if it is still in the list and will be removed later. - */ - private final boolean finishActivityLocked(HistoryRecord r, int index, - int resultCode, Intent resultData, String reason) { - if (r.finishing) { - Log.w(TAG, "Duplicate finish request for " + r); - return false; - } - - r.finishing = true; - EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY, - System.identityHashCode(r), - r.task.taskId, r.shortComponentName, reason); - r.task.numActivities--; - if (r.frontOfTask && index < (mHistory.size()-1)) { - HistoryRecord next = (HistoryRecord)mHistory.get(index+1); - if (next.task == r.task) { - next.frontOfTask = true; - } - } - - r.pauseKeyDispatchingLocked(); - if (mFocusedActivity == r) { - setFocusedActivityLocked(topRunningActivityLocked(null)); - } - - // send the result - HistoryRecord resultTo = r.resultTo; - if (resultTo != null) { - if (localLOGV) Log.v(TAG, "Adding result to " + resultTo); - if (r.info.applicationInfo.uid > 0) { - grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid, - r.packageName, resultData, r); - } - resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode, - resultData); - r.resultTo = null; - } - - // Make sure this HistoryRecord is not holding on to other resources, - // because clients have remote IPC references to this object so we - // can't assume that will go away and want to avoid circular IPC refs. - r.results = null; - r.pendingResults = null; - r.newIntents = null; - r.icicle = null; - - if (mPendingThumbnails.size() > 0) { - // There are clients waiting to receive thumbnails so, in case - // this is an activity that someone is waiting for, add it - // to the pending list so we can correctly update the clients. - mCancelledThumbnails.add(r); - } - - if (mResumedActivity == r) { - boolean endTask = index <= 0 - || ((HistoryRecord)mHistory.get(index-1)).task != r.task; - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare close transition: finishing " + r); - mWindowManager.prepareAppTransition(endTask - ? WindowManagerPolicy.TRANSIT_TASK_CLOSE - : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE); - - // Tell window manager to prepare for this one to be removed. - mWindowManager.setAppVisibility(r, false); - - if (mPausingActivity == null) { - if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r); - if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false"); - startPausingLocked(false, false); - } - - } else if (r.state != ActivityState.PAUSING) { - // If the activity is PAUSING, we will complete the finish once - // it is done pausing; else we can just directly finish it here. - if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r); - return finishCurrentActivityLocked(r, index, - FINISH_AFTER_PAUSE) == null; - } else { - if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r); - } - - return false; - } - - private static final int FINISH_IMMEDIATELY = 0; - private static final int FINISH_AFTER_PAUSE = 1; - private static final int FINISH_AFTER_VISIBLE = 2; - - private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r, - int mode) { - final int index = indexOfTokenLocked(r, false); - if (index < 0) { - return null; - } - - return finishCurrentActivityLocked(r, index, mode); - } - - private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r, - int index, int mode) { - // First things first: if this activity is currently visible, - // and the resumed activity is not yet visible, then hold off on - // finishing until the resumed one becomes visible. - if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) { - if (!mStoppingActivities.contains(r)) { - mStoppingActivities.add(r); - if (mStoppingActivities.size() > 3) { - // If we already have a few activities waiting to stop, - // then give up on things going idle and start clearing - // them out. - Message msg = Message.obtain(); - msg.what = ActivityManagerService.IDLE_NOW_MSG; - mHandler.sendMessage(msg); - } - } - r.state = ActivityState.STOPPING; - updateOomAdjLocked(); - return r; - } - - // make sure the record is cleaned out of other places. - mStoppingActivities.remove(r); - mWaitingVisibleActivities.remove(r); - if (mResumedActivity == r) { - mResumedActivity = null; - } - final ActivityState prevState = r.state; - r.state = ActivityState.FINISHING; - - if (mode == FINISH_IMMEDIATELY - || prevState == ActivityState.STOPPED - || prevState == ActivityState.INITIALIZING) { - // If this activity is already stopped, we can just finish - // it right now. - return destroyActivityLocked(r, true) ? null : r; - } else { - // Need to go through the full pause cycle to get this - // activity into the stopped state and then finish it. - if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r); - mFinishingActivities.add(r); - resumeTopActivityLocked(null); - } - return r; - } - - /** - * This is the internal entry point for handling Activity.finish(). - * - * @param token The Binder token referencing the Activity we want to finish. - * @param resultCode Result code, if any, from this Activity. - * @param resultData Result data (Intent), if any, from this Activity. - * - * @result Returns true if the activity successfully finished, or false if it is still running. - */ - public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) { - // Refuse possible leaked file descriptors - if (resultData != null && resultData.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (mWatcher != null) { - // Find the first activity that is not finishing. - HistoryRecord next = topRunningActivityLocked(token, 0); - if (next != null) { - // ask watcher if this is allowed - boolean resumeOK = true; - try { - resumeOK = mWatcher.activityResuming(next.packageName); - } catch (RemoteException e) { - mWatcher = null; - } - - if (!resumeOK) { - return false; - } - } - } - final long origId = Binder.clearCallingIdentity(); - boolean res = requestFinishActivityLocked(token, resultCode, - resultData, "app-request"); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - void sendActivityResultLocked(int callingUid, HistoryRecord r, - String resultWho, int requestCode, int resultCode, Intent data) { - - if (callingUid > 0) { - grantUriPermissionFromIntentLocked(callingUid, r.packageName, - data, r); - } - - if (mResumedActivity == r && r.app != null && r.app.thread != null) { - try { - ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); - list.add(new ResultInfo(resultWho, requestCode, - resultCode, data)); - r.app.thread.scheduleSendResult(r, list); - return; - } catch (Exception e) { - Log.w(TAG, "Exception thrown sending result to " + r, e); - } - } - - r.addResultLocked(null, resultWho, requestCode, resultCode, data); - } - - public final void finishSubActivity(IBinder token, String resultWho, - int requestCode) { - synchronized(this) { - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return; - } - HistoryRecord self = (HistoryRecord)mHistory.get(index); - - final long origId = Binder.clearCallingIdentity(); - - int i; - for (i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.resultTo == self && r.requestCode == requestCode) { - if ((r.resultWho == null && resultWho == null) || - (r.resultWho != null && r.resultWho.equals(resultWho))) { - finishActivityLocked(r, i, - Activity.RESULT_CANCELED, null, "request-sub"); - } - } - } - - Binder.restoreCallingIdentity(origId); - } - } - - /** - * Perform clean-up of service connections in an activity record. - */ - private final void cleanUpActivityServicesLocked(HistoryRecord r) { - // Throw away any services that have been bound by this activity. - if (r.connections != null) { - Iterator<ConnectionRecord> it = r.connections.iterator(); - while (it.hasNext()) { - ConnectionRecord c = it.next(); - removeConnectionLocked(c, null, r); - } - r.connections = null; - } - } - - /** - * Perform the common clean-up of an activity record. This is called both - * as part of destroyActivityLocked() (when destroying the client-side - * representation) and cleaning things up as a result of its hosting - * processing going away, in which case there is no remaining client-side - * state to destroy so only the cleanup here is needed. - */ - private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) { - if (mResumedActivity == r) { - mResumedActivity = null; - } - if (mFocusedActivity == r) { - mFocusedActivity = null; - } - - r.configDestroy = false; - r.frozenBeforeDestroy = false; - - // Make sure this record is no longer in the pending finishes list. - // This could happen, for example, if we are trimming activities - // down to the max limit while they are still waiting to finish. - mFinishingActivities.remove(r); - mWaitingVisibleActivities.remove(r); - - // Remove any pending results. - if (r.finishing && r.pendingResults != null) { - for (WeakReference<PendingIntentRecord> apr : r.pendingResults) { - PendingIntentRecord rec = apr.get(); - if (rec != null) { - cancelIntentSenderLocked(rec, false); - } - } - r.pendingResults = null; - } - - if (cleanServices) { - cleanUpActivityServicesLocked(r); - } - - if (mPendingThumbnails.size() > 0) { - // There are clients waiting to receive thumbnails so, in case - // this is an activity that someone is waiting for, add it - // to the pending list so we can correctly update the clients. - mCancelledThumbnails.add(r); - } - - // Get rid of any pending idle timeouts. - mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); - } - - private final void removeActivityFromHistoryLocked(HistoryRecord r) { - if (r.state != ActivityState.DESTROYED) { - mHistory.remove(r); - r.inHistory = false; - r.state = ActivityState.DESTROYED; - mWindowManager.removeAppToken(r); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - cleanUpActivityServicesLocked(r); - removeActivityUriPermissionsLocked(r); - } - } - - /** - * Destroy the current CLIENT SIDE instance of an activity. This may be - * called both when actually finishing an activity, or when performing - * a configuration switch where we destroy the current client-side object - * but then create a new client-side object for this same HistoryRecord. - */ - private final boolean destroyActivityLocked(HistoryRecord r, - boolean removeFromApp) { - if (DEBUG_SWITCH) Log.v( - TAG, "Removing activity: token=" + r - + ", app=" + (r.app != null ? r.app.processName : "(null)")); - EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY, - System.identityHashCode(r), - r.task.taskId, r.shortComponentName); - - boolean removedFromHistory = false; - - cleanUpActivityLocked(r, false); - - if (r.app != null) { - if (removeFromApp) { - int idx = r.app.activities.indexOf(r); - if (idx >= 0) { - r.app.activities.remove(idx); - } - if (r.persistent) { - decPersistentCountLocked(r.app); - } - } - - boolean skipDestroy = false; - - try { - if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r); - r.app.thread.scheduleDestroyActivity(r, r.finishing, - r.configChangeFlags); - } catch (Exception e) { - // We can just ignore exceptions here... if the process - // has crashed, our death notification will clean things - // up. - //Log.w(TAG, "Exception thrown during finish", e); - if (r.finishing) { - removeActivityFromHistoryLocked(r); - removedFromHistory = true; - skipDestroy = true; - } - } - - r.app = null; - r.nowVisible = false; - - if (r.finishing && !skipDestroy) { - r.state = ActivityState.DESTROYING; - Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG); - msg.obj = r; - mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT); - } else { - r.state = ActivityState.DESTROYED; - } - } else { - // remove this record from the history. - if (r.finishing) { - removeActivityFromHistoryLocked(r); - removedFromHistory = true; - } else { - r.state = ActivityState.DESTROYED; - } - } - - r.configChangeFlags = 0; - - if (!mLRUActivities.remove(r)) { - Log.w(TAG, "Activity " + r + " being finished, but not in LRU list"); - } - - return removedFromHistory; - } - - private static void removeHistoryRecordsForAppLocked(ArrayList list, - ProcessRecord app) - { - int i = list.size(); - if (localLOGV) Log.v( - TAG, "Removing app " + app + " from list " + list - + " with " + i + " entries"); - while (i > 0) { - i--; - HistoryRecord r = (HistoryRecord)list.get(i); - if (localLOGV) Log.v( - TAG, "Record #" + i + " " + r + ": app=" + r.app); - if (r.app == app) { - if (localLOGV) Log.v(TAG, "Removing this entry!"); - list.remove(i); - } - } - } - - /** - * Main function for removing an existing process from the activity manager - * as a result of that process going away. Clears out all connections - * to the process. - */ - private final void handleAppDiedLocked(ProcessRecord app, - boolean restarting) { - cleanUpApplicationRecordLocked(app, restarting, -1); - if (!restarting) { - mLRUProcesses.remove(app); - } - - // Just in case... - if (mPausingActivity != null && mPausingActivity.app == app) { - if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity); - mPausingActivity = null; - } - - // Remove this application's activities from active lists. - removeHistoryRecordsForAppLocked(mLRUActivities, app); - removeHistoryRecordsForAppLocked(mStoppingActivities, app); - removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app); - removeHistoryRecordsForAppLocked(mFinishingActivities, app); - - boolean atTop = true; - boolean hasVisibleActivities = false; - - // Clean out the history list. - int i = mHistory.size(); - if (localLOGV) Log.v( - TAG, "Removing app " + app + " from history with " + i + " entries"); - while (i > 0) { - i--; - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (localLOGV) Log.v( - TAG, "Record #" + i + " " + r + ": app=" + r.app); - if (r.app == app) { - if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { - if (localLOGV) Log.v( - TAG, "Removing this entry! frozen=" + r.haveState - + " finishing=" + r.finishing); - mHistory.remove(i); - - r.inHistory = false; - mWindowManager.removeAppToken(r); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - removeActivityUriPermissionsLocked(r); - - } else { - // We have the current state for this activity, so - // it can be restarted later when needed. - if (localLOGV) Log.v( - TAG, "Keeping entry, setting app to null"); - if (r.visible) { - hasVisibleActivities = true; - } - r.app = null; - r.nowVisible = false; - if (!r.haveState) { - r.icicle = null; - } - } - - cleanUpActivityLocked(r, true); - r.state = ActivityState.STOPPED; - } - atTop = false; - } - - app.activities.clear(); - - if (app.instrumentationClass != null) { - Log.w(TAG, "Crash of app " + app.processName - + " running instrumentation " + app.instrumentationClass); - Bundle info = new Bundle(); - info.putString("shortMsg", "Process crashed."); - finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info); - } - - if (!restarting) { - if (!resumeTopActivityLocked(null)) { - // If there was nothing to resume, and we are not already - // restarting this process, but there is a visible activity that - // is hosted by the process... then make sure all visible - // activities are running, taking care of restarting this - // process. - if (hasVisibleActivities) { - ensureActivitiesVisibleLocked(null, 0); - } - } - } - } - - private final int getLRURecordIndexForAppLocked(IApplicationThread thread) { - IBinder threadBinder = thread.asBinder(); - - // Find the application record. - int count = mLRUProcesses.size(); - int i; - for (i=0; i<count; i++) { - ProcessRecord rec = mLRUProcesses.get(i); - if (rec.thread != null && rec.thread.asBinder() == threadBinder) { - return i; - } - } - return -1; - } - - private final ProcessRecord getRecordForAppLocked( - IApplicationThread thread) { - if (thread == null) { - return null; - } - - int appIndex = getLRURecordIndexForAppLocked(thread); - return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null; - } - - private final void appDiedLocked(ProcessRecord app, int pid, - IApplicationThread thread) { - - mProcDeaths[0]++; - - if (app.thread != null && app.thread.asBinder() == thread.asBinder()) { - Log.i(TAG, "Process " + app.processName + " (pid " + pid - + ") has died."); - EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName); - if (localLOGV) Log.v( - TAG, "Dying app: " + app + ", pid: " + pid - + ", thread: " + thread.asBinder()); - boolean doLowMem = app.instrumentationClass == null; - handleAppDiedLocked(app, false); - - if (doLowMem) { - // If there are no longer any background processes running, - // and the app that died was not running instrumentation, - // then tell everyone we are now low on memory. - boolean haveBg = false; - int count = mLRUProcesses.size(); - int i; - for (i=0; i<count; i++) { - ProcessRecord rec = mLRUProcesses.get(i); - if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) { - haveBg = true; - break; - } - } - - if (!haveBg) { - Log.i(TAG, "Low Memory: No more background processes."); - EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size()); - for (i=0; i<count; i++) { - ProcessRecord rec = mLRUProcesses.get(i); - if (rec.thread != null) { - rec.lastRequestedGc = SystemClock.uptimeMillis(); - try { - rec.thread.scheduleLowMemory(); - } catch (RemoteException e) { - // Don't care if the process is gone. - } - } - } - } - } - } else if (Config.LOGD) { - Log.d(TAG, "Received spurious death notification for thread " - + thread.asBinder()); - } - } - - final String readFile(String filename) { - try { - FileInputStream fs = new FileInputStream(filename); - byte[] inp = new byte[8192]; - int size = fs.read(inp); - fs.close(); - return new String(inp, 0, 0, size); - } catch (java.io.IOException e) { - } - return ""; - } - - final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity, - final String annotation) { - if (app.notResponding || app.crashing) { - return; - } - - // Log the ANR to the event log. - EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation); - - // If we are on a secure build and the application is not interesting to the user (it is - // not visible or in the background), just kill it instead of displaying a dialog. - boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0")); - if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) { - Process.killProcess(app.pid); - return; - } - - // DeviceMonitor.start(); - - String processInfo = null; - if (MONITOR_CPU_USAGE) { - updateCpuStatsNow(); - synchronized (mProcessStatsThread) { - processInfo = mProcessStats.printCurrentState(); - } - } - - StringBuilder info = new StringBuilder(); - info.append("ANR (application not responding) in process: "); - info.append(app.processName); - if (annotation != null) { - info.append("\nAnnotation: "); - info.append(annotation); - } - if (MONITOR_CPU_USAGE) { - info.append("\nCPU usage:\n"); - info.append(processInfo); - } - Log.i(TAG, info.toString()); - - // The application is not responding. Dump as many thread traces as we can. - boolean fileDump = prepareTraceFile(true); - if (!fileDump) { - // Dumping traces to the log, just dump the process that isn't responding so - // we don't overflow the log - Process.sendSignal(app.pid, Process.SIGNAL_QUIT); - } else { - // Dumping traces to a file so dump all active processes we know about - synchronized (this) { - for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = mLRUProcesses.get(i); - if (r.thread != null) { - Process.sendSignal(r.pid, Process.SIGNAL_QUIT); - } - } - } - } - - if (mWatcher != null) { - try { - int res = mWatcher.appNotResponding(app.processName, - app.pid, info.toString()); - if (res != 0) { - if (res < 0) { - // wait until the SIGQUIT has had a chance to process before killing the - // process. - try { - wait(2000); - } catch (InterruptedException e) { - } - - Process.killProcess(app.pid); - return; - } - } - } catch (RemoteException e) { - mWatcher = null; - } - } - - makeAppNotRespondingLocked(app, - activity != null ? activity.shortComponentName : null, - annotation != null ? "ANR " + annotation : "ANR", - info.toString(), null); - Message msg = Message.obtain(); - HashMap map = new HashMap(); - msg.what = SHOW_NOT_RESPONDING_MSG; - msg.obj = map; - map.put("app", app); - if (activity != null) { - map.put("activity", activity); - } - - mHandler.sendMessage(msg); - return; - } - - /** - * If a stack trace file has been configured, prepare the filesystem - * by creating the directory if it doesn't exist and optionally - * removing the old trace file. - * - * @param removeExisting If set, the existing trace file will be removed. - * @return Returns true if the trace file preparations succeeded - */ - public static boolean prepareTraceFile(boolean removeExisting) { - String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); - boolean fileReady = false; - if (!TextUtils.isEmpty(tracesPath)) { - File f = new File(tracesPath); - if (!f.exists()) { - // Ensure the enclosing directory exists - File dir = f.getParentFile(); - if (!dir.exists()) { - fileReady = dir.mkdirs(); - FileUtils.setPermissions(dir.getAbsolutePath(), - FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1); - } else if (dir.isDirectory()) { - fileReady = true; - } - } else if (removeExisting) { - // Remove the previous traces file, so we don't fill the disk. - // The VM will recreate it - Log.i(TAG, "Removing old ANR trace file from " + tracesPath); - fileReady = f.delete(); - } - } - - return fileReady; - } - - - private final void decPersistentCountLocked(ProcessRecord app) - { - app.persistentActivities--; - if (app.persistentActivities > 0) { - // Still more of 'em... - return; - } - if (app.persistent) { - // Ah, but the application itself is persistent. Whatever! - return; - } - - // App is no longer persistent... make sure it and the ones - // following it in the LRU list have the correc oom_adj. - updateOomAdjLocked(); - } - - public void setPersistent(IBinder token, boolean isPersistent) { - if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY) - != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: setPersistent() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - synchronized(this) { - int index = indexOfTokenLocked(token, true); - if (index < 0) { - return; - } - HistoryRecord r = (HistoryRecord)mHistory.get(index); - ProcessRecord app = r.app; - - if (localLOGV) Log.v( - TAG, "Setting persistence " + isPersistent + ": " + r); - - if (isPersistent) { - if (r.persistent) { - // Okay okay, I heard you already! - if (localLOGV) Log.v(TAG, "Already persistent!"); - return; - } - r.persistent = true; - app.persistentActivities++; - if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities); - if (app.persistentActivities > 1) { - // We aren't the first... - if (localLOGV) Log.v(TAG, "Not the first!"); - return; - } - if (app.persistent) { - // This would be redundant. - if (localLOGV) Log.v(TAG, "App is persistent!"); - return; - } - - // App is now persistent... make sure it and the ones - // following it now have the correct oom_adj. - final long origId = Binder.clearCallingIdentity(); - updateOomAdjLocked(); - Binder.restoreCallingIdentity(origId); - - } else { - if (!r.persistent) { - // Okay okay, I heard you already! - return; - } - r.persistent = false; - final long origId = Binder.clearCallingIdentity(); - decPersistentCountLocked(app); - Binder.restoreCallingIdentity(origId); - - } - } - } - - public boolean clearApplicationUserData(final String packageName, - final IPackageDataObserver observer) { - int uid = Binder.getCallingUid(); - int pid = Binder.getCallingPid(); - long callingId = Binder.clearCallingIdentity(); - try { - IPackageManager pm = ActivityThread.getPackageManager(); - int pkgUid = -1; - synchronized(this) { - try { - pkgUid = pm.getPackageUid(packageName); - } catch (RemoteException e) { - } - if (pkgUid == -1) { - Log.w(TAG, "Invalid packageName:" + packageName); - return false; - } - if (uid == pkgUid || checkComponentPermission( - android.Manifest.permission.CLEAR_APP_USER_DATA, - pid, uid, -1) - == PackageManager.PERMISSION_GRANTED) { - restartPackageLocked(packageName, pkgUid); - } else { - throw new SecurityException(pid+" does not have permission:"+ - android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" + - "for process:"+packageName); - } - } - - 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 { - Binder.restoreCallingIdentity(callingId); - } - return true; - } - - public void restartPackage(final String packageName) { - if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES) - != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: restartPackage() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + android.Manifest.permission.RESTART_PACKAGES; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - long callingId = Binder.clearCallingIdentity(); - try { - IPackageManager pm = ActivityThread.getPackageManager(); - int pkgUid = -1; - synchronized(this) { - 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<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator(); - while (badApps.hasNext()) { - SparseArray<Long> ba = badApps.next(); - if (ba.get(uid) != null) { - badApps.remove(); - } - } - - ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); - - // 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. - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { - final int NA = apps.size(); - for (int ia=0; ia<NA; ia++) { - ProcessRecord app = apps.valueAt(ia); - if (app.removed) { - procs.add(app); - } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) - || app.processName.equals(name) - || app.processName.startsWith(procNamePrefix)) { - app.removed = true; - procs.add(app); - } - } - } - - N = procs.size(); - for (i=0; i<N; i++) { - removeProcessLocked(procs.get(i), callerWillRestart); - } - - for (i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.packageName.equals(name)) { - if (Config.LOGD) Log.d( - TAG, " Force finishing activity " - + r.intent.getComponent().flattenToShortString()); - if (r.app != null) { - r.app.removed = true; - } - r.app = null; - finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall"); - } - } - - ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); - for (ServiceRecord service : mServices.values()) { - if (service.packageName.equals(name)) { - if (service.app != null) { - service.app.removed = true; - } - service.app = null; - services.add(service); - } - } - - N = services.size(); - for (i=0; i<N; i++) { - bringDownServiceLocked(services.get(i), true); - } - - resumeTopActivityLocked(null); - } - - private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) { - final String name = app.processName; - final int uid = app.info.uid; - if (Config.LOGD) Log.d( - TAG, "Force removing process " + app + " (" + name - + "/" + uid + ")"); - - mProcessNames.remove(name, uid); - boolean needRestart = false; - if (app.pid > 0 && app.pid != MY_PID) { - int pid = app.pid; - synchronized (mPidsSelfLocked) { - mPidsSelfLocked.remove(pid); - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - } - handleAppDiedLocked(app, true); - mLRUProcesses.remove(app); - Process.killProcess(pid); - - if (app.persistent) { - if (!callerWillRestart) { - addAppLocked(app.info); - } else { - needRestart = true; - } - } - } else { - mRemovedProcesses.add(app); - } - - return needRestart; - } - - private final void processStartTimedOutLocked(ProcessRecord app) { - final int pid = app.pid; - boolean gone = false; - synchronized (mPidsSelfLocked) { - ProcessRecord knownApp = mPidsSelfLocked.get(pid); - if (knownApp != null && knownApp.thread == null) { - mPidsSelfLocked.remove(pid); - gone = true; - } - } - - if (gone) { - Log.w(TAG, "Process " + app + " failed to attach"); - mProcessNames.remove(app.processName, app.info.uid); - Process.killProcess(pid); - if (mPendingBroadcast.curApp.pid == pid) { - Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping"); - mPendingBroadcast = null; - scheduleBroadcastsLocked(); - } - } else { - Log.w(TAG, "Spurious process start timeout - pid not known for " + app); - } - } - - private final boolean attachApplicationLocked(IApplicationThread thread, - int pid) { - - // Find the application record that is being attached... either via - // the pid if we are running in multiple processes, or just pull the - // next app record if we are emulating process with anonymous threads. - ProcessRecord app; - if (pid != MY_PID && pid >= 0) { - synchronized (mPidsSelfLocked) { - app = mPidsSelfLocked.get(pid); - } - } else if (mStartingProcesses.size() > 0) { - app = mStartingProcesses.remove(0); - app.pid = pid; - } else { - app = null; - } - - if (app == null) { - Log.w(TAG, "No pending application record for pid " + pid - + " (IApplicationThread " + thread + "); dropping process"); - EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid); - if (pid > 0 && pid != MY_PID) { - Process.killProcess(pid); - } else { - try { - thread.scheduleExit(); - } catch (Exception e) { - // Ignore exceptions. - } - } - return false; - } - - // If this application record is still attached to a previous - // process, clean it up now. - if (app.thread != null) { - handleAppDiedLocked(app, true); - } - - // Tell the process all about itself. - - if (localLOGV) Log.v( - TAG, "Binding process pid " + pid + " to record " + app); - - String processName = app.processName; - try { - thread.asBinder().linkToDeath(new AppDeathRecipient( - app, pid, thread), 0); - } catch (RemoteException e) { - app.resetPackageList(); - startProcessLocked(app, "link fail", processName); - return false; - } - - EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName); - - app.thread = thread; - app.curAdj = app.setAdj = -100; - app.forcingToForeground = null; - app.foregroundServices = false; - app.debugging = false; - - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - - List providers = generateApplicationProvidersLocked(app); - - if (localLOGV) Log.v( - TAG, "New app record " + app - + " thread=" + thread.asBinder() + " pid=" + pid); - try { - int testMode = IApplicationThread.DEBUG_OFF; - if (mDebugApp != null && mDebugApp.equals(processName)) { - testMode = mWaitForDebugger - ? IApplicationThread.DEBUG_WAIT - : IApplicationThread.DEBUG_ON; - app.debugging = true; - if (mDebugTransient) { - mDebugApp = mOrigDebugApp; - mWaitForDebugger = mOrigWaitForDebugger; - } - } - thread.bindApplication(processName, app.info, providers, - app.instrumentationClass, app.instrumentationProfileFile, - app.instrumentationArguments, app.instrumentationWatcher, testMode, - mConfiguration, getCommonServicesLocked()); - updateLRUListLocked(app, false); - app.lastRequestedGc = SystemClock.uptimeMillis(); - } catch (Exception e) { - // todo: Yikes! What should we do? For now we will try to - // start another process, but that could easily get us in - // an infinite loop of restarting processes... - Log.w(TAG, "Exception thrown during bind!", e); - - app.resetPackageList(); - startProcessLocked(app, "bind fail", processName); - return false; - } - - // Remove this record from the list of starting applications. - mPersistentStartingProcesses.remove(app); - mProcessesOnHold.remove(app); - - boolean badApp = false; - boolean didSomething = false; - - // See if the top visible activity is waiting to run in this process... - HistoryRecord hr = topRunningActivityLocked(null); - if (hr != null) { - if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid - && processName.equals(hr.processName)) { - try { - if (realStartActivityLocked(hr, app, true, true)) { - didSomething = true; - } - } catch (Exception e) { - Log.w(TAG, "Exception in new application when starting activity " - + hr.intent.getComponent().flattenToShortString(), e); - badApp = true; - } - } else { - ensureActivitiesVisibleLocked(hr, null, processName, 0); - } - } - - // Find any services that should be running in this process... - if (!badApp && mPendingServices.size() > 0) { - ServiceRecord sr = null; - try { - for (int i=0; i<mPendingServices.size(); i++) { - sr = mPendingServices.get(i); - if (app.info.uid != sr.appInfo.uid - || !processName.equals(sr.processName)) { - continue; - } - - mPendingServices.remove(i); - i--; - realStartServiceLocked(sr, app); - didSomething = true; - } - } catch (Exception e) { - Log.w(TAG, "Exception in new application when starting service " - + sr.shortName, e); - badApp = true; - } - } - - // Check if the next broadcast receiver is in this process... - BroadcastRecord br = mPendingBroadcast; - if (!badApp && br != null && br.curApp == app) { - try { - mPendingBroadcast = null; - processCurBroadcastLocked(br, app); - didSomething = true; - } catch (Exception e) { - Log.w(TAG, "Exception in new application when starting receiver " - + br.curComponent.flattenToShortString(), e); - badApp = true; - logBroadcastReceiverDiscard(br); - finishReceiverLocked(br.receiver, br.resultCode, br.resultData, - br.resultExtras, br.resultAbort, true); - scheduleBroadcastsLocked(); - } - } - - if (badApp) { - // todo: Also need to kill application to deal with all - // kinds of exceptions. - handleAppDiedLocked(app, false); - return false; - } - - if (!didSomething) { - updateOomAdjLocked(); - } - - return true; - } - - public final void attachApplication(IApplicationThread thread) { - synchronized (this) { - int callingPid = Binder.getCallingPid(); - final long origId = Binder.clearCallingIdentity(); - attachApplicationLocked(thread, callingPid); - Binder.restoreCallingIdentity(origId); - } - } - - public final void activityIdle(IBinder token) { - final long origId = Binder.clearCallingIdentity(); - activityIdleInternal(token, false); - Binder.restoreCallingIdentity(origId); - } - - final ArrayList<HistoryRecord> processStoppingActivitiesLocked( - boolean remove) { - int N = mStoppingActivities.size(); - if (N <= 0) return null; - - ArrayList<HistoryRecord> stops = null; - - final boolean nowVisible = mResumedActivity != null - && mResumedActivity.nowVisible - && !mResumedActivity.waitingVisible; - for (int i=0; i<N; i++) { - HistoryRecord s = mStoppingActivities.get(i); - if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible=" - + nowVisible + " waitingVisible=" + s.waitingVisible - + " finishing=" + s.finishing); - if (s.waitingVisible && nowVisible) { - mWaitingVisibleActivities.remove(s); - s.waitingVisible = false; - if (s.finishing) { - // If this activity is finishing, it is sitting on top of - // everyone else but we now know it is no longer needed... - // so get rid of it. Otherwise, we need to go through the - // normal flow and hide it once we determine that it is - // hidden by the activities in front of it. - if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s); - mWindowManager.setAppVisibility(s, false); - } - } - if (!s.waitingVisible && remove) { - if (localLOGV) Log.v(TAG, "Ready to stop: " + s); - if (stops == null) { - stops = new ArrayList<HistoryRecord>(); - } - stops.add(s); - mStoppingActivities.remove(i); - N--; - i--; - } - } - - return stops; - } - - void enableScreenAfterBoot() { - mWindowManager.enableScreenAfterBoot(); - } - - final void activityIdleInternal(IBinder token, boolean fromTimeout) { - if (localLOGV) Log.v(TAG, "Activity idle: " + token); - - ArrayList<HistoryRecord> stops = null; - ArrayList<HistoryRecord> finishes = null; - ArrayList<HistoryRecord> thumbnails = null; - int NS = 0; - int NF = 0; - int NT = 0; - IApplicationThread sendThumbnail = null; - boolean booting = false; - boolean enableScreen = false; - - synchronized (this) { - if (token != null) { - mHandler.removeMessages(IDLE_TIMEOUT_MSG, token); - } - - // Get the activity record. - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); - - // No longer need to keep the device awake. - if (mResumedActivity == r && mLaunchingActivity.isHeld()) { - mHandler.removeMessages(LAUNCH_TIMEOUT_MSG); - mLaunchingActivity.release(); - } - - // We are now idle. If someone is waiting for a thumbnail from - // us, we can now deliver. - r.idle = true; - scheduleAppGcsLocked(); - if (r.thumbnailNeeded && r.app != null && r.app.thread != null) { - sendThumbnail = r.app.thread; - r.thumbnailNeeded = false; - } - - // If this activity is fullscreen, set up to hide those under it. - - if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r); - ensureActivitiesVisibleLocked(null, 0); - - //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); - if (!mBooted && !fromTimeout) { - mBooted = true; - enableScreen = true; - } - } - - // Atomically retrieve all of the other things to do. - stops = processStoppingActivitiesLocked(true); - NS = stops != null ? stops.size() : 0; - if ((NF=mFinishingActivities.size()) > 0) { - finishes = new ArrayList<HistoryRecord>(mFinishingActivities); - mFinishingActivities.clear(); - } - if ((NT=mCancelledThumbnails.size()) > 0) { - thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails); - mCancelledThumbnails.clear(); - } - - booting = mBooting; - mBooting = false; - } - - int i; - - // Send thumbnail if requested. - if (sendThumbnail != null) { - try { - sendThumbnail.requestThumbnail(token); - } catch (Exception e) { - Log.w(TAG, "Exception thrown when requesting thumbnail", e); - sendPendingThumbnail(null, token, null, null, true); - } - } - - // Stop any activities that are scheduled to do so but have been - // waiting for the next one to start. - for (i=0; i<NS; i++) { - HistoryRecord r = (HistoryRecord)stops.get(i); - synchronized (this) { - if (r.finishing) { - finishCurrentActivityLocked(r, FINISH_IMMEDIATELY); - } else { - stopActivityLocked(r); - } - } - } - - // Finish any activities that are scheduled to do so but have been - // waiting for the next one to start. - for (i=0; i<NF; i++) { - HistoryRecord r = (HistoryRecord)finishes.get(i); - synchronized (this) { - destroyActivityLocked(r, true); - } - } - - // Report back to any thumbnail receivers. - for (i=0; i<NT; i++) { - HistoryRecord r = (HistoryRecord)thumbnails.get(i); - sendPendingThumbnail(r, null, null, null, true); - } - - if (booting) { - // Ensure that any processes we had put on hold are now started - // up. - final int NP = mProcessesOnHold.size(); - if (NP > 0) { - ArrayList<ProcessRecord> procs = - new ArrayList<ProcessRecord>(mProcessesOnHold); - for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); - } - } - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - // Tell anyone interested that we are done booting! - synchronized (this) { - broadcastIntentLocked(null, null, - new Intent(Intent.ACTION_BOOT_COMPLETED, null), - null, null, 0, null, null, - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, - false, false, MY_PID, Process.SYSTEM_UID); - } - } - } - - trimApplications(); - //dump(); - //mWindowManager.dump(); - - if (enableScreen) { - EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, - SystemClock.uptimeMillis()); - enableScreenAfterBoot(); - } - } - - public final void activityPaused(IBinder token, Bundle icicle) { - // Refuse possible leaked file descriptors - if (icicle != null && icicle.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Bundle"); - } - - final long origId = Binder.clearCallingIdentity(); - activityPaused(token, icicle, false); - Binder.restoreCallingIdentity(origId); - } - - final void activityPaused(IBinder token, Bundle icicle, boolean timeout) { - if (DEBUG_PAUSE) Log.v( - TAG, "Activity paused: token=" + token + ", icicle=" + icicle - + ", timeout=" + timeout); - - HistoryRecord r = null; - - synchronized (this) { - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - r = (HistoryRecord)mHistory.get(index); - if (!timeout) { - r.icicle = icicle; - r.haveState = true; - } - mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - if (mPausingActivity == r) { - r.state = ActivityState.PAUSED; - completePauseLocked(); - } else { - EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY, - System.identityHashCode(r), r.shortComponentName, - mPausingActivity != null - ? mPausingActivity.shortComponentName : "(none)"); - } - } - } - } - - public final void activityStopped(IBinder token, Bitmap thumbnail, - CharSequence description) { - if (localLOGV) Log.v( - TAG, "Activity stopped: token=" + token); - - HistoryRecord r = null; - - final long origId = Binder.clearCallingIdentity(); - - synchronized (this) { - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - r = (HistoryRecord)mHistory.get(index); - r.thumbnail = thumbnail; - r.description = description; - r.stopped = true; - r.state = ActivityState.STOPPED; - if (!r.finishing) { - if (r.configDestroy) { - destroyActivityLocked(r, true); - resumeTopActivityLocked(null); - } - } - } - } - - if (r != null) { - sendPendingThumbnail(r, null, null, null, false); - } - - trimApplications(); - - Binder.restoreCallingIdentity(origId); - } - - public final void activityDestroyed(IBinder token) { - if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token); - synchronized (this) { - mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token); - - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); - if (r.state == ActivityState.DESTROYING) { - final long origId = Binder.clearCallingIdentity(); - removeActivityFromHistoryLocked(r); - Binder.restoreCallingIdentity(origId); - } - } - } - } - - public String getCallingPackage(IBinder token) { - synchronized (this) { - HistoryRecord r = getCallingRecordLocked(token); - return r != null && r.app != null ? r.app.processName : null; - } - } - - public ComponentName getCallingActivity(IBinder token) { - synchronized (this) { - HistoryRecord r = getCallingRecordLocked(token); - return r != null ? r.intent.getComponent() : null; - } - } - - private HistoryRecord getCallingRecordLocked(IBinder token) { - int index = indexOfTokenLocked(token, true); - if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); - if (r != null) { - return r.resultTo; - } - } - return null; - } - - public ComponentName getActivityClassForToken(IBinder token) { - synchronized(this) { - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); - return r.intent.getComponent(); - } - return null; - } - } - - public String getPackageForToken(IBinder token) { - synchronized(this) { - int index = indexOfTokenLocked(token, false); - if (index >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(index); - return r.packageName; - } - return null; - } - } - - public IIntentSender getIntentSender(int type, - String packageName, IBinder token, String resultWho, - int requestCode, Intent intent, String resolvedType, int flags) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - int callingUid = Binder.getCallingUid(); - try { - if (callingUid != 0 && callingUid != Process.SYSTEM_UID && - Process.supportsProcesses()) { - int uid = ActivityThread.getPackageManager() - .getPackageUid(packageName); - if (uid != Binder.getCallingUid()) { - String msg = "Permission Denial: getIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + ", (need uid=" + uid + ")" - + " is not allowed to send as package " + packageName; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - } - } catch (RemoteException e) { - throw new SecurityException(e); - } - HistoryRecord activity = null; - if (type == INTENT_SENDER_ACTIVITY_RESULT) { - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return null; - } - activity = (HistoryRecord)mHistory.get(index); - if (activity.finishing) { - return null; - } - } - - final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; - final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; - final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; - flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT - |PendingIntent.FLAG_UPDATE_CURRENT); - - PendingIntentRecord.Key key = new PendingIntentRecord.Key( - type, packageName, activity, resultWho, - requestCode, intent, resolvedType, flags); - WeakReference<PendingIntentRecord> ref; - ref = mIntentSenderRecords.get(key); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec != null) { - if (!cancelCurrent) { - if (updateCurrent) { - rec.key.requestIntent.replaceExtras(intent); - } - return rec; - } - rec.canceled = true; - mIntentSenderRecords.remove(key); - } - if (noCreate) { - return rec; - } - rec = new PendingIntentRecord(this, key, callingUid); - mIntentSenderRecords.put(key, rec.ref); - if (type == INTENT_SENDER_ACTIVITY_RESULT) { - if (activity.pendingResults == null) { - activity.pendingResults - = new HashSet<WeakReference<PendingIntentRecord>>(); - } - activity.pendingResults.add(rec.ref); - } - return rec; - } - } - - public void cancelIntentSender(IIntentSender sender) { - if (!(sender instanceof PendingIntentRecord)) { - return; - } - synchronized(this) { - PendingIntentRecord rec = (PendingIntentRecord)sender; - try { - int uid = ActivityThread.getPackageManager() - .getPackageUid(rec.key.packageName); - if (uid != Binder.getCallingUid()) { - String msg = "Permission Denial: cancelIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " is not allowed to cancel packges " - + rec.key.packageName; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - } catch (RemoteException e) { - throw new SecurityException(e); - } - cancelIntentSenderLocked(rec, true); - } - } - - void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) { - rec.canceled = true; - mIntentSenderRecords.remove(rec.key); - if (cleanActivity && rec.key.activity != null) { - rec.key.activity.pendingResults.remove(rec.ref); - } - } - - public String getPackageForIntentSender(IIntentSender pendingResult) { - if (!(pendingResult instanceof PendingIntentRecord)) { - return null; - } - synchronized(this) { - try { - PendingIntentRecord res = (PendingIntentRecord)pendingResult; - return res.key.packageName; - } catch (ClassCastException e) { - } - } - return null; - } - - public void setProcessLimit(int max) { - enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT, - "setProcessLimit()"); - mProcessLimit = max; - } - - public int getProcessLimit() { - return mProcessLimit; - } - - void foregroundTokenDied(ForegroundToken token) { - synchronized (ActivityManagerService.this) { - synchronized (mPidsSelfLocked) { - ForegroundToken cur - = mForegroundProcesses.get(token.pid); - if (cur != token) { - return; - } - mForegroundProcesses.remove(token.pid); - ProcessRecord pr = mPidsSelfLocked.get(token.pid); - if (pr == null) { - return; - } - pr.forcingToForeground = null; - pr.foregroundServices = false; - } - updateOomAdjLocked(); - } - } - - public void setProcessForeground(IBinder token, int pid, boolean isForeground) { - enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT, - "setProcessForeground()"); - synchronized(this) { - boolean changed = false; - - synchronized (mPidsSelfLocked) { - ProcessRecord pr = mPidsSelfLocked.get(pid); - if (pr == null) { - Log.w(TAG, "setProcessForeground called on unknown pid: " + pid); - return; - } - ForegroundToken oldToken = mForegroundProcesses.get(pid); - if (oldToken != null) { - oldToken.token.unlinkToDeath(oldToken, 0); - mForegroundProcesses.remove(pid); - pr.forcingToForeground = null; - changed = true; - } - if (isForeground && token != null) { - ForegroundToken newToken = new ForegroundToken() { - public void binderDied() { - foregroundTokenDied(this); - } - }; - newToken.pid = pid; - newToken.token = token; - try { - token.linkToDeath(newToken, 0); - mForegroundProcesses.put(pid, newToken); - pr.forcingToForeground = token; - changed = true; - } catch (RemoteException e) { - // If the process died while doing this, we will later - // do the cleanup with the process death link. - } - } - } - - if (changed) { - updateOomAdjLocked(); - } - } - } - - // ========================================================= - // PERMISSIONS - // ========================================================= - - static class PermissionController extends IPermissionController.Stub { - ActivityManagerService mActivityManagerService; - PermissionController(ActivityManagerService activityManagerService) { - mActivityManagerService = activityManagerService; - } - - public boolean checkPermission(String permission, int pid, int uid) { - return mActivityManagerService.checkPermission(permission, pid, - uid) == PackageManager.PERMISSION_GRANTED; - } - } - - /** - * This can be called with or without the global lock held. - */ - int checkComponentPermission(String permission, int pid, int uid, - int reqUid) { - // We might be performing an operation on behalf of an indirect binder - // invocation, e.g. via {@link #openContentUri}. Check and adjust the - // client identity accordingly before proceeding. - Identity tlsIdentity = sCallerIdentity.get(); - if (tlsIdentity != null) { - Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {" - + tlsIdentity.pid + "," + tlsIdentity.uid + "}"); - uid = tlsIdentity.uid; - pid = tlsIdentity.pid; - } - - // Root, system server and our own process get to do everything. - if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID || - !Process.supportsProcesses()) { - return PackageManager.PERMISSION_GRANTED; - } - // If the target requires a specific UID, always fail for others. - if (reqUid >= 0 && uid != reqUid) { - return PackageManager.PERMISSION_DENIED; - } - if (permission == null) { - return PackageManager.PERMISSION_GRANTED; - } - try { - return ActivityThread.getPackageManager() - .checkUidPermission(permission, uid); - } catch (RemoteException e) { - // Should never happen, but if it does... deny! - Log.e(TAG, "PackageManager is dead?!?", e); - } - return PackageManager.PERMISSION_DENIED; - } - - /** - * As the only public entry point for permissions checking, this method - * can enforce the semantic that requesting a check on a null global - * permission is automatically denied. (Internally a null permission - * string is used when calling {@link #checkComponentPermission} in cases - * when only uid-based security is needed.) - * - * This can be called with or without the global lock held. - */ - public int checkPermission(String permission, int pid, int uid) { - if (permission == null) { - return PackageManager.PERMISSION_DENIED; - } - return checkComponentPermission(permission, pid, uid, -1); - } - - /** - * Binder IPC calls go through the public entry point. - * This can be called with or without the global lock held. - */ - int checkCallingPermission(String permission) { - return checkPermission(permission, - Binder.getCallingPid(), - Binder.getCallingUid()); - } - - /** - * This can be called with or without the global lock held. - */ - void enforceCallingPermission(String permission, String func) { - if (checkCallingPermission(permission) - == PackageManager.PERMISSION_GRANTED) { - return; - } - - String msg = "Permission Denial: " + func + " from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + permission; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - private final boolean checkHoldingPermissionsLocked(IPackageManager pm, - ProviderInfo pi, int uid, int modeFlags) { - try { - if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { - if ((pi.readPermission != null) && - (pm.checkUidPermission(pi.readPermission, uid) - != PackageManager.PERMISSION_GRANTED)) { - return false; - } - } - if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { - if ((pi.writePermission != null) && - (pm.checkUidPermission(pi.writePermission, uid) - != PackageManager.PERMISSION_GRANTED)) { - return false; - } - } - return true; - } catch (RemoteException e) { - return false; - } - } - - private final boolean checkUriPermissionLocked(Uri uri, int uid, - int modeFlags) { - // Root gets to do everything. - if (uid == 0 || !Process.supportsProcesses()) { - return true; - } - HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid); - if (perms == null) return false; - UriPermission perm = perms.get(uri); - if (perm == null) return false; - return (modeFlags&perm.modeFlags) == modeFlags; - } - - public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { - // Another redirected-binder-call permissions check as in - // {@link checkComponentPermission}. - Identity tlsIdentity = sCallerIdentity.get(); - if (tlsIdentity != null) { - uid = tlsIdentity.uid; - pid = tlsIdentity.pid; - } - - // Our own process gets to do everything. - if (pid == MY_PID) { - return PackageManager.PERMISSION_GRANTED; - } - synchronized(this) { - return checkUriPermissionLocked(uri, uid, modeFlags) - ? PackageManager.PERMISSION_GRANTED - : PackageManager.PERMISSION_DENIED; - } - } - - private void grantUriPermissionLocked(int callingUid, - String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) { - modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (modeFlags == 0) { - return; - } - - final IPackageManager pm = ActivityThread.getPackageManager(); - - // If this is not a content: uri, we can't do anything with it. - if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { - return; - } - - String name = uri.getAuthority(); - ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(name); - if (cpr != null) { - pi = cpr.info; - } else { - try { - pi = pm.resolveContentProvider(name, - PackageManager.GET_URI_PERMISSION_PATTERNS); - } catch (RemoteException ex) { - } - } - if (pi == null) { - Log.w(TAG, "No content provider found for: " + name); - return; - } - - int targetUid; - try { - targetUid = pm.getPackageUid(targetPkg); - if (targetUid < 0) { - return; - } - } catch (RemoteException ex) { - return; - } - - // First... does the target actually need this permission? - if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) { - // No need to grant the target this permission. - return; - } - - // Second... maybe someone else has already granted the - // permission? - if (checkUriPermissionLocked(uri, targetUid, modeFlags)) { - // No need to grant the target this permission. - return; - } - - // Third... is the provider allowing granting of URI permissions? - if (!pi.grantUriPermissions) { - throw new SecurityException("Provider " + pi.packageName - + "/" + pi.name - + " does not allow granting of Uri permissions (uri " - + uri + ")"); - } - if (pi.uriPermissionPatterns != null) { - final int N = pi.uriPermissionPatterns.length; - boolean allowed = false; - for (int i=0; i<N; i++) { - if (pi.uriPermissionPatterns[i] != null - && pi.uriPermissionPatterns[i].match(uri.getPath())) { - allowed = true; - break; - } - } - if (!allowed) { - throw new SecurityException("Provider " + pi.packageName - + "/" + pi.name - + " does not allow granting of permission to path of Uri " - + uri); - } - } - - // Fourth... does the caller itself have permission to access - // this uri? - if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) { - if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { - throw new SecurityException("Uid " + callingUid - + " does not have permission to uri " + uri); - } - } - - // Okay! So here we are: the caller has the assumed permission - // to the uri, and the target doesn't. Let's now give this to - // the target. - - HashMap<Uri, UriPermission> targetUris - = mGrantedUriPermissions.get(targetUid); - if (targetUris == null) { - targetUris = new HashMap<Uri, UriPermission>(); - mGrantedUriPermissions.put(targetUid, targetUris); - } - - UriPermission perm = targetUris.get(uri); - if (perm == null) { - perm = new UriPermission(targetUid, uri); - targetUris.put(uri, perm); - - } - perm.modeFlags |= modeFlags; - if (activity == null) { - perm.globalModeFlags |= modeFlags; - } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { - perm.readActivities.add(activity); - if (activity.readUriPermissions == null) { - activity.readUriPermissions = new HashSet<UriPermission>(); - } - activity.readUriPermissions.add(perm); - } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { - perm.writeActivities.add(activity); - if (activity.writeUriPermissions == null) { - activity.writeUriPermissions = new HashSet<UriPermission>(); - } - activity.writeUriPermissions.add(perm); - } - } - - private void grantUriPermissionFromIntentLocked(int callingUid, - String targetPkg, Intent intent, HistoryRecord activity) { - if (intent == null) { - return; - } - Uri data = intent.getData(); - if (data == null) { - return; - } - grantUriPermissionLocked(callingUid, targetPkg, data, - intent.getFlags(), activity); - } - - public void grantUriPermission(IApplicationThread caller, String targetPkg, - Uri uri, int modeFlags) { - synchronized(this) { - final ProcessRecord r = getRecordForAppLocked(caller); - if (r == null) { - throw new SecurityException("Unable to find app for caller " - + caller - + " when granting permission to uri " + uri); - } - if (targetPkg == null) { - Log.w(TAG, "grantUriPermission: null target"); - return; - } - if (uri == null) { - Log.w(TAG, "grantUriPermission: null uri"); - return; - } - - grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags, - null); - } - } - - private void removeUriPermissionIfNeededLocked(UriPermission perm) { - if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION - |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) { - HashMap<Uri, UriPermission> perms - = mGrantedUriPermissions.get(perm.uid); - if (perms != null) { - perms.remove(perm.uri); - if (perms.size() == 0) { - mGrantedUriPermissions.remove(perm.uid); - } - } - } - } - - private void removeActivityUriPermissionsLocked(HistoryRecord activity) { - if (activity.readUriPermissions != null) { - for (UriPermission perm : activity.readUriPermissions) { - perm.readActivities.remove(activity); - if (perm.readActivities.size() == 0 && (perm.globalModeFlags - &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) { - perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; - removeUriPermissionIfNeededLocked(perm); - } - } - } - if (activity.writeUriPermissions != null) { - for (UriPermission perm : activity.writeUriPermissions) { - perm.writeActivities.remove(activity); - if (perm.writeActivities.size() == 0 && (perm.globalModeFlags - &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) { - perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; - removeUriPermissionIfNeededLocked(perm); - } - } - } - } - - private void revokeUriPermissionLocked(int callingUid, Uri uri, - int modeFlags) { - modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (modeFlags == 0) { - return; - } - - final IPackageManager pm = ActivityThread.getPackageManager(); - - final String authority = uri.getAuthority(); - ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(authority); - if (cpr != null) { - pi = cpr.info; - } else { - try { - pi = pm.resolveContentProvider(authority, - PackageManager.GET_URI_PERMISSION_PATTERNS); - } catch (RemoteException ex) { - } - } - if (pi == null) { - Log.w(TAG, "No content provider found for: " + authority); - return; - } - - // Does the caller have this permission on the URI? - if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) { - // Right now, if you are not the original owner of the permission, - // you are not allowed to revoke it. - //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) { - throw new SecurityException("Uid " + callingUid - + " does not have permission to uri " + uri); - //} - } - - // Go through all of the permissions and remove any that match. - final List<String> SEGMENTS = uri.getPathSegments(); - if (SEGMENTS != null) { - final int NS = SEGMENTS.size(); - int N = mGrantedUriPermissions.size(); - for (int i=0; i<N; i++) { - HashMap<Uri, UriPermission> perms - = mGrantedUriPermissions.valueAt(i); - Iterator<UriPermission> it = perms.values().iterator(); - toploop: - while (it.hasNext()) { - UriPermission perm = it.next(); - Uri targetUri = perm.uri; - if (!authority.equals(targetUri.getAuthority())) { - continue; - } - List<String> targetSegments = targetUri.getPathSegments(); - if (targetSegments == null) { - continue; - } - if (targetSegments.size() < NS) { - continue; - } - for (int j=0; j<NS; j++) { - if (!SEGMENTS.get(j).equals(targetSegments.get(j))) { - continue toploop; - } - } - perm.clearModes(modeFlags); - if (perm.modeFlags == 0) { - it.remove(); - } - } - if (perms.size() == 0) { - mGrantedUriPermissions.remove( - mGrantedUriPermissions.keyAt(i)); - N--; - i--; - } - } - } - } - - public void revokeUriPermission(IApplicationThread caller, Uri uri, - int modeFlags) { - synchronized(this) { - final ProcessRecord r = getRecordForAppLocked(caller); - if (r == null) { - throw new SecurityException("Unable to find app for caller " - + caller - + " when revoking permission to uri " + uri); - } - if (uri == null) { - Log.w(TAG, "revokeUriPermission: null uri"); - return; - } - - modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - if (modeFlags == 0) { - return; - } - - final IPackageManager pm = ActivityThread.getPackageManager(); - - final String authority = uri.getAuthority(); - ProviderInfo pi = null; - ContentProviderRecord cpr - = (ContentProviderRecord)mProvidersByName.get(authority); - if (cpr != null) { - pi = cpr.info; - } else { - try { - pi = pm.resolveContentProvider(authority, - PackageManager.GET_URI_PERMISSION_PATTERNS); - } catch (RemoteException ex) { - } - } - if (pi == null) { - Log.w(TAG, "No content provider found for: " + authority); - return; - } - - revokeUriPermissionLocked(r.info.uid, uri, modeFlags); - } - } - - public void showWaitingForDebugger(IApplicationThread who, boolean waiting) { - synchronized (this) { - ProcessRecord app = - who != null ? getRecordForAppLocked(who) : null; - if (app == null) return; - - Message msg = Message.obtain(); - msg.what = WAIT_FOR_DEBUGGER_MSG; - msg.obj = app; - msg.arg1 = waiting ? 1 : 0; - mHandler.sendMessage(msg); - } - } - - public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { - outInfo.availMem = Process.getFreeMemory(); - outInfo.threshold = SECONDARY_SERVER_MEM; - outInfo.lowMemory = outInfo.availMem < - (SECONDARY_SERVER_MEM + ((HIDDEN_APP_MEM-SECONDARY_SERVER_MEM)/2)); - } - - // ========================================================= - // TASK MANAGEMENT - // ========================================================= - - public List getTasks(int maxNum, int flags, - IThumbnailReceiver receiver) { - ArrayList list = new ArrayList(); - - PendingThumbnailsRecord pending = null; - IApplicationThread topThumbnail = null; - HistoryRecord topRecord = null; - - synchronized(this) { - if (localLOGV) Log.v( - TAG, "getTasks: max=" + maxNum + ", flags=" + flags - + ", receiver=" + receiver); - - if (checkCallingPermission(android.Manifest.permission.GET_TASKS) - != PackageManager.PERMISSION_GRANTED) { - if (receiver != null) { - // If the caller wants to wait for pending thumbnails, - // it ain't gonna get them. - try { - receiver.finished(); - } catch (RemoteException ex) { - } - } - String msg = "Permission Denial: getTasks() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + android.Manifest.permission.GET_TASKS; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - int pos = mHistory.size()-1; - HistoryRecord next = - pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null; - HistoryRecord top = null; - CharSequence topDescription = null; - TaskRecord curTask = null; - int numActivities = 0; - int numRunning = 0; - while (pos >= 0 && maxNum > 0) { - final HistoryRecord r = next; - pos--; - next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null; - - // Initialize state for next task if needed. - if (top == null || - (top.state == ActivityState.INITIALIZING - && top.task == r.task)) { - top = r; - topDescription = r.description; - curTask = r.task; - numActivities = numRunning = 0; - } - - // Add 'r' into the current task. - numActivities++; - if (r.app != null && r.app.thread != null) { - numRunning++; - } - if (topDescription == null) { - topDescription = r.description; - } - - if (localLOGV) Log.v( - TAG, r.intent.getComponent().flattenToShortString() - + ": task=" + r.task); - - // If the next one is a different task, generate a new - // TaskInfo entry for what we have. - if (next == null || next.task != curTask) { - ActivityManager.RunningTaskInfo ci - = new ActivityManager.RunningTaskInfo(); - ci.id = curTask.taskId; - ci.baseActivity = r.intent.getComponent(); - ci.topActivity = top.intent.getComponent(); - ci.thumbnail = top.thumbnail; - ci.description = topDescription; - ci.numActivities = numActivities; - ci.numRunning = numRunning; - //System.out.println( - // "#" + maxNum + ": " + " descr=" + ci.description); - if (ci.thumbnail == null && receiver != null) { - if (localLOGV) Log.v( - TAG, "State=" + top.state + "Idle=" + top.idle - + " app=" + top.app - + " thr=" + (top.app != null ? top.app.thread : null)); - if (top.state == ActivityState.RESUMED - || top.state == ActivityState.PAUSING) { - if (top.idle && top.app != null - && top.app.thread != null) { - topRecord = top; - topThumbnail = top.app.thread; - } else { - top.thumbnailNeeded = true; - } - } - if (pending == null) { - pending = new PendingThumbnailsRecord(receiver); - } - pending.pendingRecords.add(top); - } - list.add(ci); - maxNum--; - top = null; - } - } - - if (pending != null) { - mPendingThumbnails.add(pending); - } - } - - if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending); - - if (topThumbnail != null) { - if (localLOGV) Log.v(TAG, "Requesting top thumbnail"); - try { - topThumbnail.requestThumbnail(topRecord); - } catch (Exception e) { - Log.w(TAG, "Exception thrown when requesting thumbnail", e); - sendPendingThumbnail(null, topRecord, null, null, true); - } - } - - if (pending == null && receiver != null) { - // In this case all thumbnails were available and the client - // is being asked to be told when the remaining ones come in... - // which is unusually, since the top-most currently running - // activity should never have a canned thumbnail! Oh well. - try { - receiver.finished(); - } catch (RemoteException ex) { - } - } - - return list; - } - - public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, - int flags) { - synchronized (this) { - enforceCallingPermission(android.Manifest.permission.GET_TASKS, - "getRecentTasks()"); - - final int N = mRecentTasks.size(); - ArrayList<ActivityManager.RecentTaskInfo> res - = new ArrayList<ActivityManager.RecentTaskInfo>( - maxNum < N ? maxNum : N); - for (int i=0; i<N && maxNum > 0; i++) { - TaskRecord tr = mRecentTasks.get(i); - if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0) - || (tr.intent == null) - || ((tr.intent.getFlags() - &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) { - ActivityManager.RecentTaskInfo rti - = new ActivityManager.RecentTaskInfo(); - rti.id = tr.numActivities > 0 ? tr.taskId : -1; - rti.baseIntent = new Intent( - tr.intent != null ? tr.intent : tr.affinityIntent); - rti.origActivity = tr.origActivity; - res.add(rti); - maxNum--; - } - } - return res; - } - } - - private final int findAffinityTaskTopLocked(int startIndex, String affinity) { - int j; - TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task; - TaskRecord jt = startTask; - - // First look backwards - for (j=startIndex-1; j>=0; j--) { - HistoryRecord r = (HistoryRecord)mHistory.get(j); - if (r.task != jt) { - jt = r.task; - if (affinity.equals(jt.affinity)) { - return j; - } - } - } - - // Now look forwards - final int N = mHistory.size(); - jt = startTask; - for (j=startIndex+1; j<N; j++) { - HistoryRecord r = (HistoryRecord)mHistory.get(j); - if (r.task != jt) { - if (affinity.equals(jt.affinity)) { - return j; - } - jt = r.task; - } - } - - // Might it be at the top? - if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) { - return N-1; - } - - return -1; - } - - /** - * Perform a reset of the given task, if needed as part of launching it. - * Returns the new HistoryRecord at the top of the task. - */ - private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop, - HistoryRecord newActivity) { - boolean forceReset = (newActivity.info.flags - &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; - if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) { - if ((newActivity.info.flags - &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) { - forceReset = true; - } - } - - final TaskRecord task = taskTop.task; - - // We are going to move through the history list so that we can look - // at each activity 'target' with 'below' either the interesting - // activity immediately below it in the stack or null. - HistoryRecord target = null; - int targetI = 0; - int taskTopI = -1; - int replyChainEnd = -1; - int lastReparentPos = -1; - for (int i=mHistory.size()-1; i>=-1; i--) { - HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null; - - if (below != null && below.finishing) { - continue; - } - if (target == null) { - target = below; - targetI = i; - // If we were in the middle of a reply chain before this - // task, it doesn't appear like the root of the chain wants - // anything interesting, so drop it. - replyChainEnd = -1; - continue; - } - - final int flags = target.info.flags; - - final boolean finishOnTaskLaunch = - (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0; - final boolean allowTaskReparenting = - (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0; - - if (target.task == task) { - // We are inside of the task being reset... we'll either - // finish this activity, push it out for another task, - // or leave it as-is. We only do this - // for activities that are not the root of the task (since - // if we finish the root, we may no longer have the task!). - if (taskTopI < 0) { - taskTopI = targetI; - } - if (below != null && below.task == task) { - final boolean clearWhenTaskReset = - (target.intent.getFlags() - &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0; - if (!finishOnTaskLaunch && target.resultTo != null) { - // If this activity is sending a reply to a previous - // activity, we can't do anything with it now until - // we reach the start of the reply chain. - // XXX note that we are assuming the result is always - // to the previous activity, which is almost always - // the case but we really shouldn't count on. - if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - } else if (!finishOnTaskLaunch && allowTaskReparenting - && target.taskAffinity != null - && !target.taskAffinity.equals(task.affinity)) { - // If this activity has an affinity for another - // task, then we need to move it out of here. We will - // move it as far out of the way as possible, to the - // bottom of the activity stack. This also keeps it - // correctly ordered with any activities we previously - // moved. - HistoryRecord p = (HistoryRecord)mHistory.get(0); - if (target.taskAffinity != null - && target.taskAffinity.equals(p.task.affinity)) { - // If the activity currently at the bottom has the - // same task affinity as the one we are moving, - // then merge it into the same task. - target.task = p.task; - if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target - + " out to bottom task " + p.task); - } else { - mCurTask++; - if (mCurTask <= 0) { - mCurTask = 1; - } - target.task = new TaskRecord(mCurTask, target.info, null, - (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0); - target.task.affinityIntent = target.intent; - if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target - + " out to new task " + target.task); - } - mWindowManager.setAppGroupId(target, task.taskId); - if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - int dstPos = 0; - for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { - p = (HistoryRecord)mHistory.get(srcPos); - if (p.finishing) { - continue; - } - if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p - + " out to target's task " + target.task); - task.numActivities--; - p.task = target.task; - target.task.numActivities++; - mHistory.remove(srcPos); - mHistory.add(dstPos, p); - mWindowManager.moveAppToken(dstPos, p); - mWindowManager.setAppGroupId(p, p.task.taskId); - dstPos++; - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - i++; - } - if (taskTop == p) { - taskTop = below; - } - if (taskTopI == replyChainEnd) { - taskTopI = -1; - } - replyChainEnd = -1; - addRecentTask(target.task); - } else if (forceReset || finishOnTaskLaunch - || clearWhenTaskReset) { - // If the activity should just be removed -- either - // because it asks for it, or the task should be - // cleared -- then finish it and anything that is - // part of its reply chain. - if (clearWhenTaskReset) { - // In this case, we want to finish this activity - // and everything above it, so be sneaky and pretend - // like these are all in the reply chain. - replyChainEnd = targetI+1; - while (replyChainEnd < mHistory.size() && - ((HistoryRecord)mHistory.get( - replyChainEnd)).task == task) { - replyChainEnd++; - } - replyChainEnd--; - } else if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - HistoryRecord p = null; - for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { - p = (HistoryRecord)mHistory.get(srcPos); - if (p.finishing) { - continue; - } - if (finishActivityLocked(p, srcPos, - Activity.RESULT_CANCELED, null, "reset")) { - replyChainEnd--; - srcPos--; - } - } - if (taskTop == p) { - taskTop = below; - } - if (taskTopI == replyChainEnd) { - taskTopI = -1; - } - replyChainEnd = -1; - } else { - // If we were in the middle of a chain, well the - // activity that started it all doesn't want anything - // special, so leave it all as-is. - replyChainEnd = -1; - } - } else { - // Reached the bottom of the task -- any reply chain - // should be left as-is. - replyChainEnd = -1; - } - - } else if (target.resultTo != null) { - // If this activity is sending a reply to a previous - // activity, we can't do anything with it now until - // we reach the start of the reply chain. - // XXX note that we are assuming the result is always - // to the previous activity, which is almost always - // the case but we really shouldn't count on. - if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - - } else if (taskTopI >= 0 && allowTaskReparenting - && task.affinity != null - && task.affinity.equals(target.taskAffinity)) { - // We are inside of another task... if this activity has - // an affinity for our task, then either remove it if we are - // clearing or move it over to our task. Note that - // we currently punt on the case where we are resetting a - // task that is not at the top but who has activities above - // with an affinity to it... this is really not a normal - // case, and we will need to later pull that task to the front - // and usually at that point we will do the reset and pick - // up those remaining activities. (This only happens if - // someone starts an activity in a new task from an activity - // in a task that is not currently on top.) - if (forceReset || finishOnTaskLaunch) { - if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - HistoryRecord p = null; - for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) { - p = (HistoryRecord)mHistory.get(srcPos); - if (p.finishing) { - continue; - } - if (finishActivityLocked(p, srcPos, - Activity.RESULT_CANCELED, null, "reset")) { - taskTopI--; - lastReparentPos--; - replyChainEnd--; - srcPos--; - } - } - replyChainEnd = -1; - } else { - if (replyChainEnd < 0) { - replyChainEnd = targetI; - } - for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) { - HistoryRecord p = (HistoryRecord)mHistory.get(srcPos); - if (p.finishing) { - continue; - } - if (lastReparentPos < 0) { - lastReparentPos = taskTopI; - taskTop = p; - } else { - lastReparentPos--; - } - mHistory.remove(srcPos); - p.task.numActivities--; - p.task = task; - mHistory.add(lastReparentPos, p); - if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p - + " in to resetting task " + task); - task.numActivities++; - mWindowManager.moveAppToken(lastReparentPos, p); - mWindowManager.setAppGroupId(p, p.task.taskId); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - } - replyChainEnd = -1; - - // Now we've moved it in to place... but what if this is - // a singleTop activity and we have put it on top of another - // instance of the same activity? Then we drop the instance - // below so it remains singleTop. - if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { - for (int j=lastReparentPos-1; j>=0; j--) { - HistoryRecord p = (HistoryRecord)mHistory.get(j); - if (p.finishing) { - continue; - } - if (p.intent.getComponent().equals(target.intent.getComponent())) { - if (finishActivityLocked(p, j, - Activity.RESULT_CANCELED, null, "replace")) { - taskTopI--; - lastReparentPos--; - } - } - } - } - } - } - - target = below; - targetI = i; - } - - return taskTop; - } - - /** - * TODO: Add mWatcher hook - */ - public void moveTaskToFront(int task) { - enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, - "moveTaskToFront()"); - - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - try { - int N = mRecentTasks.size(); - for (int i=0; i<N; i++) { - TaskRecord tr = mRecentTasks.get(i); - if (tr.taskId == task) { - moveTaskToFrontLocked(tr); - return; - } - } - for (int i=mHistory.size()-1; i>=0; i--) { - HistoryRecord hr = (HistoryRecord)mHistory.get(i); - if (hr.task.taskId == task) { - moveTaskToFrontLocked(hr.task); - return; - } - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - private final void moveTaskToFrontLocked(TaskRecord tr) { - if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr); - - final int task = tr.taskId; - int top = mHistory.size()-1; - - if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) { - // nothing to do! - return; - } - - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare to front transition: task=" + tr); - mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT); - - ArrayList moved = new ArrayList(); - - // Applying the affinities may have removed entries from the history, - // so get the size again. - top = mHistory.size()-1; - int pos = top; - - // Shift all activities with this task up to the top - // of the stack, keeping them in the same internal order. - while (pos >= 0) { - HistoryRecord r = (HistoryRecord)mHistory.get(pos); - if (localLOGV) Log.v( - TAG, "At " + pos + " ckp " + r.task + ": " + r); - boolean first = true; - if (r.task.taskId == task) { - if (localLOGV) Log.v(TAG, "Removing and adding at " + top); - mHistory.remove(pos); - mHistory.add(top, r); - moved.add(0, r); - top--; - if (first) { - addRecentTask(r.task); - first = false; - } - } - pos--; - } - - mWindowManager.moveAppTokensToTop(moved); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - - finishTaskMove(task); - EventLog.writeEvent(LOG_TASK_TO_FRONT, task); - } - - private final void finishTaskMove(int task) { - resumeTopActivityLocked(null); - } - - public void moveTaskToBack(int task) { - enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, - "moveTaskToBack()"); - - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - moveTaskToBackLocked(task); - Binder.restoreCallingIdentity(origId); - } - } - - /** - * Moves an activity, and all of the other activities within the same task, to the bottom - * of the history stack. The activity's order within the task is unchanged. - * - * @param token A reference to the activity we wish to move - * @param nonRoot If false then this only works if the activity is the root - * of a task; if true it will work for any activity in a task. - * @return Returns true if the move completed, false if not. - */ - public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) { - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - int taskId = getTaskForActivityLocked(token, !nonRoot); - if (taskId >= 0) { - return moveTaskToBackLocked(taskId); - } - Binder.restoreCallingIdentity(origId); - } - return false; - } - - /** - * Worker method for rearranging history stack. Implements the function of moving all - * activities for a specific task (gathering them if disjoint) into a single group at the - * bottom of the stack. - * - * If a watcher is installed, the action is preflighted and the watcher has an opportunity - * to premeptively cancel the move. - * - * @param task The taskId to collect and move to the bottom. - * @return Returns true if the move completed, false if not. - */ - private final boolean moveTaskToBackLocked(int task) { - Log.i(TAG, "moveTaskToBack: " + task); - - // If we have a watcher, preflight the move before committing to it. First check - // for *other* available tasks, but if none are available, then try again allowing the - // current task to be selected. - if (mWatcher != null) { - HistoryRecord next = topRunningActivityLocked(null, task); - if (next == null) { - next = topRunningActivityLocked(null, 0); - } - if (next != null) { - // ask watcher if this is allowed - boolean moveOK = true; - try { - moveOK = mWatcher.activityResuming(next.packageName); - } catch (RemoteException e) { - mWatcher = null; - } - if (!moveOK) { - return false; - } - } - } - - ArrayList moved = new ArrayList(); - - if (DEBUG_TRANSITION) Log.v(TAG, - "Prepare to back transition: task=" + task); - mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK); - - final int N = mHistory.size(); - int bottom = 0; - int pos = 0; - - // Shift all activities with this task down to the bottom - // of the stack, keeping them in the same internal order. - while (pos < N) { - HistoryRecord r = (HistoryRecord)mHistory.get(pos); - if (localLOGV) Log.v( - TAG, "At " + pos + " ckp " + r.task + ": " + r); - if (r.task.taskId == task) { - if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1)); - mHistory.remove(pos); - mHistory.add(bottom, r); - moved.add(r); - bottom++; - } - pos++; - } - - mWindowManager.moveAppTokensToBottom(moved); - if (VALIDATE_TOKENS) { - mWindowManager.validateAppTokens(mHistory); - } - - finishTaskMove(task); - return true; - } - - public void moveTaskBackwards(int task) { - enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, - "moveTaskBackwards()"); - - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - moveTaskBackwardsLocked(task); - Binder.restoreCallingIdentity(origId); - } - } - - private final void moveTaskBackwardsLocked(int task) { - Log.e(TAG, "moveTaskBackwards not yet implemented!"); - } - - public int getTaskForActivity(IBinder token, boolean onlyRoot) { - synchronized(this) { - return getTaskForActivityLocked(token, onlyRoot); - } - } - - int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { - final int N = mHistory.size(); - TaskRecord lastTask = null; - for (int i=0; i<N; i++) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r == token) { - if (!onlyRoot || lastTask != r.task) { - return r.task.taskId; - } - return -1; - } - lastTask = r.task; - } - - return -1; - } - - /** - * Returns the top activity in any existing task matching the given - * Intent. Returns null if no such task is found. - */ - private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) { - ComponentName cls = intent.getComponent(); - if (info.targetActivity != null) { - cls = new ComponentName(info.packageName, info.targetActivity); - } - - TaskRecord cp = null; - - final int N = mHistory.size(); - for (int i=(N-1); i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (!r.finishing && r.task != cp - && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) { - cp = r.task; - //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString() - // + "/aff=" + r.task.affinity + " to new cls=" - // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity); - if (r.task.affinity != null) { - if (r.task.affinity.equals(info.taskAffinity)) { - //Log.i(TAG, "Found matching affinity!"); - return r; - } - } else if (r.task.intent != null - && r.task.intent.getComponent().equals(cls)) { - //Log.i(TAG, "Found matching class!"); - //dump(); - //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent); - return r; - } else if (r.task.affinityIntent != null - && r.task.affinityIntent.getComponent().equals(cls)) { - //Log.i(TAG, "Found matching class!"); - //dump(); - //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent); - return r; - } - } - } - - return null; - } - - /** - * Returns the first activity (starting from the top of the stack) that - * is the same as the given activity. Returns null if no such activity - * is found. - */ - private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) { - ComponentName cls = intent.getComponent(); - if (info.targetActivity != null) { - cls = new ComponentName(info.packageName, info.targetActivity); - } - - final int N = mHistory.size(); - for (int i=(N-1); i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (!r.finishing) { - if (r.intent.getComponent().equals(cls)) { - //Log.i(TAG, "Found matching class!"); - //dump(); - //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent); - return r; - } - } - } - - return null; - } - - public void finishOtherInstances(IBinder token, ComponentName className) { - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - - int N = mHistory.size(); - TaskRecord lastTask = null; - for (int i=0; i<N; i++) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.realActivity.equals(className) - && r != token && lastTask != r.task) { - if (finishActivityLocked(r, i, Activity.RESULT_CANCELED, - null, "others")) { - i--; - N--; - } - } - lastTask = r.task; - } - - Binder.restoreCallingIdentity(origId); - } - } - - // ========================================================= - // THUMBNAILS - // ========================================================= - - public void reportThumbnail(IBinder token, - Bitmap thumbnail, CharSequence description) { - //System.out.println("Report thumbnail for " + token + ": " + thumbnail); - final long origId = Binder.clearCallingIdentity(); - sendPendingThumbnail(null, token, thumbnail, description, true); - Binder.restoreCallingIdentity(origId); - } - - final void sendPendingThumbnail(HistoryRecord r, IBinder token, - Bitmap thumbnail, CharSequence description, boolean always) { - TaskRecord task = null; - ArrayList receivers = null; - - //System.out.println("Send pending thumbnail: " + r); - - synchronized(this) { - if (r == null) { - int index = indexOfTokenLocked(token, false); - if (index < 0) { - return; - } - r = (HistoryRecord)mHistory.get(index); - } - if (thumbnail == null) { - thumbnail = r.thumbnail; - description = r.description; - } - if (thumbnail == null && !always) { - // If there is no thumbnail, and this entry is not actually - // going away, then abort for now and pick up the next - // thumbnail we get. - return; - } - task = r.task; - - int N = mPendingThumbnails.size(); - int i=0; - while (i<N) { - PendingThumbnailsRecord pr = - (PendingThumbnailsRecord)mPendingThumbnails.get(i); - //System.out.println("Looking in " + pr.pendingRecords); - if (pr.pendingRecords.remove(r)) { - if (receivers == null) { - receivers = new ArrayList(); - } - receivers.add(pr); - if (pr.pendingRecords.size() == 0) { - pr.finished = true; - mPendingThumbnails.remove(i); - N--; - continue; - } - } - i++; - } - } - - if (receivers != null) { - final int N = receivers.size(); - for (int i=0; i<N; i++) { - try { - PendingThumbnailsRecord pr = - (PendingThumbnailsRecord)receivers.get(i); - pr.receiver.newThumbnail( - task != null ? task.taskId : -1, thumbnail, description); - if (pr.finished) { - pr.receiver.finished(); - } - } catch (Exception e) { - Log.w(TAG, "Exception thrown when sending thumbnail", e); - } - } - } - } - - // ========================================================= - // CONTENT PROVIDERS - // ========================================================= - - private final List generateApplicationProvidersLocked(ProcessRecord app) { - List providers = null; - try { - providers = ActivityThread.getPackageManager(). - queryContentProviders(app.processName, app.info.uid, - PackageManager.GET_SHARED_LIBRARY_FILES - | PackageManager.GET_URI_PERMISSION_PATTERNS); - } catch (RemoteException ex) { - } - if (providers != null) { - final int N = providers.size(); - for (int i=0; i<N; i++) { - ProviderInfo cpi = - (ProviderInfo)providers.get(i); - ContentProviderRecord cpr = - (ContentProviderRecord)mProvidersByClass.get(cpi.name); - if (cpr == null) { - cpr = new ContentProviderRecord(cpi, app.info); - mProvidersByClass.put(cpi.name, cpr); - } - app.pubProviders.put(cpi.name, cpr); - app.addPackage(cpi.applicationInfo.packageName); - } - } - return providers; - } - - private final String checkContentProviderPermissionLocked( - ProviderInfo cpi, ProcessRecord r, int mode) { - final int callingPid = (r != null) ? r.pid : Binder.getCallingPid(); - final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid(); - if (checkComponentPermission(cpi.readPermission, callingPid, callingUid, - cpi.exported ? -1 : cpi.applicationInfo.uid) - == PackageManager.PERMISSION_GRANTED - && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) { - return null; - } - if (checkComponentPermission(cpi.writePermission, callingPid, callingUid, - cpi.exported ? -1 : cpi.applicationInfo.uid) - == PackageManager.PERMISSION_GRANTED) { - return null; - } - String msg = "Permission Denial: opening provider " + cpi.name - + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid - + ", uid=" + callingUid + ") requires " - + cpi.readPermission + " or " + cpi.writePermission; - Log.w(TAG, msg); - return msg; - } - - private final ContentProviderHolder getContentProviderImpl( - IApplicationThread caller, String name) { - ContentProviderRecord cpr; - ProviderInfo cpi = null; - - synchronized(this) { - ProcessRecord r = null; - if (caller != null) { - r = getRecordForAppLocked(caller); - if (r == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when getting content provider " + name); - } - } - - // First check if this content provider has been published... - cpr = (ContentProviderRecord)mProvidersByName.get(name); - if (cpr != null) { - cpi = cpr.info; - if (checkContentProviderPermissionLocked(cpi, r, -1) != null) { - return new ContentProviderHolder(cpi, - cpi.readPermission != null - ? cpi.readPermission : cpi.writePermission); - } - - if (r != null && cpr.canRunHere(r)) { - // This provider has been published or is in the process - // of being published... but it is also allowed to run - // in the caller's process, so don't make a connection - // and just let the caller instantiate its own instance. - if (cpr.provider != null) { - // don't give caller the provider object, it needs - // to make its own. - cpr = new ContentProviderRecord(cpr); - } - return cpr; - } - - final long origId = Binder.clearCallingIdentity(); - - // In this case the provider is a single instance, so we can - // return it right away. - if (r != null) { - r.conProviders.add(cpr); - cpr.clients.add(r); - } else { - cpr.externals++; - } - - if (cpr.app != null) { - updateOomAdjLocked(cpr.app); - } - - Binder.restoreCallingIdentity(origId); - - } else { - try { - cpi = ActivityThread.getPackageManager(). - resolveContentProvider(name, PackageManager.GET_URI_PERMISSION_PATTERNS); - } catch (RemoteException ex) { - } - if (cpi == null) { - return null; - } - - if (checkContentProviderPermissionLocked(cpi, r, -1) != null) { - return new ContentProviderHolder(cpi, - cpi.readPermission != null - ? cpi.readPermission : cpi.writePermission); - } - - cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name); - final boolean firstClass = cpr == null; - if (firstClass) { - try { - ApplicationInfo ai = - ActivityThread.getPackageManager(). - getApplicationInfo( - cpi.applicationInfo.packageName, - PackageManager.GET_SHARED_LIBRARY_FILES); - if (ai == null) { - Log.w(TAG, "No package info for content provider " - + cpi.name); - return null; - } - cpr = new ContentProviderRecord(cpi, ai); - } catch (RemoteException ex) { - // pm is in same process, this will never happen. - } - } - - if (r != null && cpr.canRunHere(r)) { - // If this is a multiprocess provider, then just return its - // info and allow the caller to instantiate it. Only do - // this if the provider is the same user as the caller's - // process, or can run as root (so can be in any process). - return cpr; - } - - if (false) { - RuntimeException e = new RuntimeException("foo"); - //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid - // + " pruid " + ai.uid + "): " + cpi.className, e); - } - - // This is single process, and our app is now connecting to it. - // See if we are already in the process of launching this - // provider. - final int N = mLaunchingProviders.size(); - int i; - for (i=0; i<N; i++) { - if (mLaunchingProviders.get(i) == cpr) { - break; - } - if (false) { - final ContentProviderRecord rec = - (ContentProviderRecord)mLaunchingProviders.get(i); - if (rec.info.name.equals(cpr.info.name)) { - cpr = rec; - break; - } - } - } - - // If the provider is not already being launched, then get it - // started. - if (i >= N) { - final long origId = Binder.clearCallingIdentity(); - ProcessRecord proc = startProcessLocked(cpi.processName, - cpr.appInfo, false, 0, "content provider", - new ComponentName(cpi.applicationInfo.packageName, - cpi.name)); - if (proc == null) { - Log.w(TAG, "Unable to launch app " - + cpi.applicationInfo.packageName + "/" - + cpi.applicationInfo.uid + " for provider " - + name + ": process is bad"); - return null; - } - cpr.launchingApp = proc; - mLaunchingProviders.add(cpr); - Binder.restoreCallingIdentity(origId); - } - - // Make sure the provider is published (the same provider class - // may be published under multiple names). - if (firstClass) { - mProvidersByClass.put(cpi.name, cpr); - } - mProvidersByName.put(name, cpr); - - if (r != null) { - r.conProviders.add(cpr); - cpr.clients.add(r); - } else { - cpr.externals++; - } - } - } - - // Wait for the provider to be published... - synchronized (cpr) { - while (cpr.provider == null) { - if (cpr.launchingApp == null) { - Log.w(TAG, "Unable to launch app " - + cpi.applicationInfo.packageName + "/" - + cpi.applicationInfo.uid + " for provider " - + name + ": launching app became null"); - EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS, - cpi.applicationInfo.packageName, - cpi.applicationInfo.uid, name); - return null; - } - try { - cpr.wait(); - } catch (InterruptedException ex) { - } - } - } - return cpr; - } - - public final ContentProviderHolder getContentProvider( - IApplicationThread caller, String name) { - if (caller == null) { - String msg = "null IApplicationThread when getting content provider " - + name; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - - return getContentProviderImpl(caller, name); - } - - private ContentProviderHolder getContentProviderExternal(String name) { - return getContentProviderImpl(null, name); - } - - /** - * Drop a content provider from a ProcessRecord's bookkeeping - * @param cpr - */ - public void removeContentProvider(IApplicationThread caller, String name) { - synchronized (this) { - ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name); - if(cpr == null) { - //remove from mProvidersByClass - if(localLOGV) Log.v(TAG, name+" content provider not found in providers list"); - return; - } - final ProcessRecord r = getRecordForAppLocked(caller); - if (r == null) { - throw new SecurityException( - "Unable to find app for caller " + caller + - " when removing content provider " + name); - } - //update content provider record entry info - ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name); - if(localLOGV) Log.v(TAG, "Removing content provider requested by "+ - r.info.processName+" from process "+localCpr.appInfo.processName); - if(localCpr.appInfo.processName == r.info.processName) { - //should not happen. taken care of as a local provider - if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names"); - return; - } else { - localCpr.clients.remove(r); - r.conProviders.remove(localCpr); - } - updateOomAdjLocked(); - } - } - - private void removeContentProviderExternal(String name) { - synchronized (this) { - ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name); - if(cpr == null) { - //remove from mProvidersByClass - if(localLOGV) Log.v(TAG, name+" content provider not found in providers list"); - return; - } - - //update content provider record entry info - ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name); - localCpr.externals--; - if (localCpr.externals < 0) { - Log.e(TAG, "Externals < 0 for content provider " + localCpr); - } - updateOomAdjLocked(); - } - } - - public final void publishContentProviders(IApplicationThread caller, - List<ContentProviderHolder> providers) { - if (providers == null) { - return; - } - - synchronized(this) { - final ProcessRecord r = getRecordForAppLocked(caller); - if (r == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when publishing content providers"); - } - - final long origId = Binder.clearCallingIdentity(); - - final int N = providers.size(); - for (int i=0; i<N; i++) { - ContentProviderHolder src = providers.get(i); - if (src == null || src.info == null || src.provider == null) { - continue; - } - ContentProviderRecord dst = - (ContentProviderRecord)r.pubProviders.get(src.info.name); - if (dst != null) { - mProvidersByClass.put(dst.info.name, dst); - String names[] = dst.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - mProvidersByName.put(names[j], dst); - } - - int NL = mLaunchingProviders.size(); - int j; - for (j=0; j<NL; j++) { - if (mLaunchingProviders.get(j) == dst) { - mLaunchingProviders.remove(j); - j--; - NL--; - } - } - synchronized (dst) { - dst.provider = src.provider; - dst.app = r; - dst.notifyAll(); - } - updateOomAdjLocked(r); - } - } - - Binder.restoreCallingIdentity(origId); - } - } - - public static final void installSystemProviders() { - ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID); - List providers = mSelf.generateApplicationProvidersLocked(app); - mSystemThread.installSystemProviders(providers); - } - - // ========================================================= - // GLOBAL MANAGEMENT - // ========================================================= - - final ProcessRecord newProcessRecordLocked(IApplicationThread thread, - ApplicationInfo info, String customProcess) { - String proc = customProcess != null ? customProcess : info.processName; - BatteryStatsImpl.Uid.Proc ps = null; - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - synchronized (stats) { - ps = stats.getProcessStatsLocked(info.uid, proc); - } - return new ProcessRecord(ps, thread, info, proc); - } - - final ProcessRecord addAppLocked(ApplicationInfo info) { - ProcessRecord app = getProcessRecordLocked(info.processName, info.uid); - - if (app == null) { - app = newProcessRecordLocked(null, info, null); - mProcessNames.put(info.processName, info.uid, app); - updateLRUListLocked(app, true); - } - - if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) - == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { - app.persistent = true; - app.maxAdj = CORE_SERVER_ADJ; - } - if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { - mPersistentStartingProcesses.add(app); - startProcessLocked(app, "added application", app.processName); - } - - return app; - } - - public void unhandledBack() { - enforceCallingPermission(android.Manifest.permission.FORCE_BACK, - "unhandledBack()"); - - synchronized(this) { - int count = mHistory.size(); - if (Config.LOGD) Log.d( - TAG, "Performing unhandledBack(): stack size = " + count); - if (count > 1) { - final long origId = Binder.clearCallingIdentity(); - finishActivityLocked((HistoryRecord)mHistory.get(count-1), - count-1, Activity.RESULT_CANCELED, null, "unhandled-back"); - Binder.restoreCallingIdentity(origId); - } - } - } - - public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException { - String name = uri.getAuthority(); - ContentProviderHolder cph = getContentProviderExternal(name); - ParcelFileDescriptor pfd = null; - if (cph != null) { - // We record the binder invoker's uid in thread-local storage before - // going to the content provider to open the file. Later, in the code - // that handles all permissions checks, we look for this uid and use - // that rather than the Activity Manager's own uid. The effect is that - // we do the check against the caller's permissions even though it looks - // to the content provider like the Activity Manager itself is making - // the request. - sCallerIdentity.set(new Identity( - Binder.getCallingPid(), Binder.getCallingUid())); - try { - pfd = cph.provider.openFile(uri, "r"); - } catch (FileNotFoundException e) { - // do nothing; pfd will be returned null - } finally { - // Ensure that whatever happens, we clean up the identity state - sCallerIdentity.remove(); - } - - // We've got the fd now, so we're done with the provider. - removeContentProviderExternal(name); - } else { - Log.d(TAG, "Failed to get provider for authority '" + name + "'"); - } - return pfd; - } - - public void goingToSleep() { - synchronized(this) { - mSleeping = true; - mWindowManager.setEventDispatching(false); - - if (mResumedActivity != null) { - pauseIfSleepingLocked(); - } else { - Log.w(TAG, "goingToSleep with no resumed activity!"); - } - } - } - - void pauseIfSleepingLocked() { - if (mSleeping) { - if (!mGoingToSleep.isHeld()) { - mGoingToSleep.acquire(); - if (mLaunchingActivity.isHeld()) { - mLaunchingActivity.release(); - mHandler.removeMessages(LAUNCH_TIMEOUT_MSG); - } - } - - // If we are not currently pausing an activity, get the current - // one to pause. If we are pausing one, we will just let that stuff - // run and release the wake lock when all done. - if (mPausingActivity == null) { - if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause..."); - if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false"); - startPausingLocked(false, true); - } - } - } - - public void wakingUp() { - synchronized(this) { - if (mGoingToSleep.isHeld()) { - mGoingToSleep.release(); - } - mWindowManager.setEventDispatching(true); - mSleeping = false; - resumeTopActivityLocked(null); - } - } - - public void setDebugApp(String packageName, boolean waitForDebugger, - boolean persistent) { - enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, - "setDebugApp()"); - - // Note that this is not really thread safe if there are multiple - // callers into it at the same time, but that's not a situation we - // care about. - if (persistent) { - final ContentResolver resolver = mContext.getContentResolver(); - Settings.System.putString( - resolver, Settings.System.DEBUG_APP, - packageName); - Settings.System.putInt( - resolver, Settings.System.WAIT_FOR_DEBUGGER, - waitForDebugger ? 1 : 0); - } - - synchronized (this) { - if (!persistent) { - mOrigDebugApp = mDebugApp; - mOrigWaitForDebugger = mWaitForDebugger; - } - mDebugApp = packageName; - mWaitForDebugger = waitForDebugger; - mDebugTransient = !persistent; - if (packageName != null) { - final long origId = Binder.clearCallingIdentity(); - uninstallPackageLocked(packageName, -1, false); - Binder.restoreCallingIdentity(origId); - } - } - } - - public void setAlwaysFinish(boolean enabled) { - enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH, - "setAlwaysFinish()"); - - Settings.System.putInt( - mContext.getContentResolver(), - Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0); - - synchronized (this) { - mAlwaysFinishActivities = enabled; - } - } - - public void setActivityWatcher(IActivityWatcher watcher) { - enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, - "setActivityWatcher()"); - synchronized (this) { - mWatcher = watcher; - } - } - - public final void enterSafeMode() { - synchronized(this) { - // It only makes sense to do this before the system is ready - // and started launching other packages. - if (!mSystemReady) { - try { - ActivityThread.getPackageManager().enterSafeMode(); - } catch (RemoteException e) { - } - - View v = LayoutInflater.from(mContext).inflate( - com.android.internal.R.layout.safe_mode, null); - WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); - lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; - lp.width = WindowManager.LayoutParams.WRAP_CONTENT; - lp.height = WindowManager.LayoutParams.WRAP_CONTENT; - lp.gravity = Gravity.BOTTOM | Gravity.LEFT; - lp.format = v.getBackground().getOpacity(); - lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - ((WindowManager)mContext.getSystemService( - Context.WINDOW_SERVICE)).addView(v, lp); - } - } - } - - public void noteWakeupAlarm(IIntentSender sender) { - if (!(sender instanceof PendingIntentRecord)) { - return; - } - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - synchronized (stats) { - if (mBatteryStatsService.isOnBattery()) { - mBatteryStatsService.enforceCallingPermission(); - PendingIntentRecord rec = (PendingIntentRecord)sender; - int MY_UID = Binder.getCallingUid(); - int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid; - BatteryStatsImpl.Uid.Pkg pkg = - stats.getPackageStatsLocked(uid, rec.key.packageName); - pkg.incWakeupsLocked(); - } - } - } - - public boolean killPidsForMemory(int[] pids) { - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("killPidsForMemory only available to the system"); - } - - // XXX Note: don't acquire main activity lock here, because the window - // manager calls in with its locks held. - - boolean killed = false; - synchronized (mPidsSelfLocked) { - int[] types = new int[pids.length]; - int worstType = 0; - for (int i=0; i<pids.length; i++) { - ProcessRecord proc = mPidsSelfLocked.get(pids[i]); - if (proc != null) { - int type = proc.setAdj; - types[i] = type; - if (type > worstType) { - worstType = type; - } - } - } - - // If the worse oom_adj is somewhere in the hidden proc LRU range, - // then constrain it so we will kill all hidden procs. - if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) { - worstType = HIDDEN_APP_MIN_ADJ; - } - Log.w(TAG, "Killing processes for memory at adjustment " + worstType); - for (int i=0; i<pids.length; i++) { - ProcessRecord proc = mPidsSelfLocked.get(pids[i]); - if (proc == null) { - continue; - } - int adj = proc.setAdj; - if (adj >= worstType) { - Log.w(TAG, "Killing for memory: " + proc + " (adj " - + adj + ")"); - EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid, - proc.processName, adj); - killed = true; - Process.killProcess(pids[i]); - } - } - } - return killed; - } - - public void reportPss(IApplicationThread caller, int pss) { - Watchdog.PssRequestor req; - String name; - ProcessRecord callerApp; - synchronized (this) { - if (caller == null) { - return; - } - callerApp = getRecordForAppLocked(caller); - if (callerApp == null) { - return; - } - callerApp.lastPss = pss; - req = callerApp; - name = callerApp.processName; - } - Watchdog.getInstance().reportPss(req, name, pss); - if (!callerApp.persistent) { - removeRequestedPss(callerApp); - } - } - - public void requestPss(Runnable completeCallback) { - ArrayList<ProcessRecord> procs; - synchronized (this) { - mRequestPssCallback = completeCallback; - mRequestPssList.clear(); - for (int i=mLRUProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = mLRUProcesses.get(i); - if (!proc.persistent) { - mRequestPssList.add(proc); - } - } - procs = new ArrayList<ProcessRecord>(mRequestPssList); - } - - int oldPri = Process.getThreadPriority(Process.myTid()); - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - for (int i=procs.size()-1; i>=0; i--) { - ProcessRecord proc = procs.get(i); - proc.lastPss = 0; - proc.requestPss(); - } - Process.setThreadPriority(oldPri); - } - - void removeRequestedPss(ProcessRecord proc) { - Runnable callback = null; - synchronized (this) { - if (mRequestPssList.remove(proc)) { - if (mRequestPssList.size() == 0) { - callback = mRequestPssCallback; - mRequestPssCallback = null; - } - } - } - - if (callback != null) { - callback.run(); - } - } - - public void collectPss(Watchdog.PssStats stats) { - stats.mEmptyPss = 0; - stats.mEmptyCount = 0; - stats.mBackgroundPss = 0; - stats.mBackgroundCount = 0; - stats.mServicePss = 0; - stats.mServiceCount = 0; - stats.mVisiblePss = 0; - stats.mVisibleCount = 0; - stats.mForegroundPss = 0; - stats.mForegroundCount = 0; - stats.mNoPssCount = 0; - synchronized (this) { - int i; - int NPD = mProcDeaths.length < stats.mProcDeaths.length - ? mProcDeaths.length : stats.mProcDeaths.length; - int aggr = 0; - for (i=0; i<NPD; i++) { - aggr += mProcDeaths[i]; - stats.mProcDeaths[i] = aggr; - } - while (i<stats.mProcDeaths.length) { - stats.mProcDeaths[i] = 0; - i++; - } - - for (i=mLRUProcesses.size()-1; i>=0; i--) { - ProcessRecord proc = mLRUProcesses.get(i); - if (proc.persistent) { - continue; - } - //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss); - if (proc.lastPss == 0) { - stats.mNoPssCount++; - continue; - } - if (proc.setAdj == EMPTY_APP_ADJ) { - stats.mEmptyPss += proc.lastPss; - stats.mEmptyCount++; - } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) { - stats.mEmptyPss += proc.lastPss; - stats.mEmptyCount++; - } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) { - stats.mBackgroundPss += proc.lastPss; - stats.mBackgroundCount++; - } else if (proc.setAdj >= VISIBLE_APP_ADJ) { - stats.mVisiblePss += proc.lastPss; - stats.mVisibleCount++; - } else { - stats.mForegroundPss += proc.lastPss; - stats.mForegroundCount++; - } - } - } - } - - public final void startRunning(String pkg, String cls, String action, - String data) { - synchronized(this) { - if (mStartRunning) { - return; - } - mStartRunning = true; - mTopComponent = pkg != null && cls != null - ? new ComponentName(pkg, cls) : null; - mTopAction = action != null ? action : Intent.ACTION_MAIN; - mTopData = data; - if (!mSystemReady) { - return; - } - } - - systemReady(); - } - - private void retrieveSettings() { - final ContentResolver resolver = mContext.getContentResolver(); - String debugApp = Settings.System.getString( - resolver, Settings.System.DEBUG_APP); - boolean waitForDebugger = Settings.System.getInt( - resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0; - boolean alwaysFinishActivities = Settings.System.getInt( - resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0; - - Configuration configuration = new Configuration(); - Settings.System.getConfiguration(resolver, configuration); - - synchronized (this) { - mDebugApp = mOrigDebugApp = debugApp; - mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger; - mAlwaysFinishActivities = alwaysFinishActivities; - // This happens before any activities are started, so we can - // change mConfiguration in-place. - mConfiguration.updateFrom(configuration); - } - } - - 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. - if (!Process.supportsProcesses()) { - mStartRunning = true; - mTopAction = Intent.ACTION_MAIN; - } - - synchronized(this) { - if (mSystemReady) { - return; - } - mSystemReady = true; - if (!mStartRunning) { - return; - } - } - - if (Config.LOGD) Log.d(TAG, "Start running!"); - EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY, - SystemClock.uptimeMillis()); - - synchronized(this) { - if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { - ResolveInfo ri = mContext.getPackageManager() - .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST), - 0); - CharSequence errorMsg = null; - if (ri != null) { - ActivityInfo ai = ri.activityInfo; - ApplicationInfo app = ai.applicationInfo; - if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - mTopAction = Intent.ACTION_FACTORY_TEST; - mTopData = null; - mTopComponent = new ComponentName(app.packageName, - ai.name); - } else { - errorMsg = mContext.getResources().getText( - com.android.internal.R.string.factorytest_not_system); - } - } else { - errorMsg = mContext.getResources().getText( - com.android.internal.R.string.factorytest_no_action); - } - if (errorMsg != null) { - mTopAction = null; - mTopData = null; - mTopComponent = null; - Message msg = Message.obtain(); - msg.what = SHOW_FACTORY_ERROR_MSG; - msg.getData().putCharSequence("msg", errorMsg); - mHandler.sendMessage(msg); - } - } - } - - retrieveSettings(); - - synchronized (this) { - if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { - try { - List apps = ActivityThread.getPackageManager(). - getPersistentApplications(PackageManager.GET_SHARED_LIBRARY_FILES); - if (apps != null) { - int N = apps.size(); - int i; - for (i=0; i<N; i++) { - ApplicationInfo info - = (ApplicationInfo)apps.get(i); - if (info != null && - !info.packageName.equals("android")) { - addAppLocked(info); - } - } - } - } catch (RemoteException ex) { - // pm is in same process, this will never happen. - } - } - - try { - if (ActivityThread.getPackageManager().hasSystemUidErrors()) { - Message msg = Message.obtain(); - msg.what = SHOW_UID_ERROR_MSG; - mHandler.sendMessage(msg); - } - } catch (RemoteException e) { - } - - // Start up initial activity. - mBooting = true; - resumeTopActivityLocked(null); - } - } - - boolean makeAppCrashingLocked(ProcessRecord app, - String tag, String shortMsg, String longMsg, byte[] crashData) { - app.crashing = true; - app.crashingReport = generateProcessError(app, - ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData); - startAppProblemLocked(app); - app.stopFreezingAllLocked(); - return handleAppCrashLocked(app); - } - - void makeAppNotRespondingLocked(ProcessRecord app, - String tag, String shortMsg, String longMsg, byte[] crashData) { - app.notResponding = true; - app.notRespondingReport = generateProcessError(app, - ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg, - crashData); - startAppProblemLocked(app); - app.stopFreezingAllLocked(); - } - - /** - * Generate a process error record, suitable for attachment to a ProcessRecord. - * - * @param app The ProcessRecord in which the error occurred. - * @param condition Crashing, Application Not Responding, etc. Values are defined in - * ActivityManager.AppErrorStateInfo - * @param tag The tag that was passed into handleApplicationError(). Typically the classname. - * @param shortMsg Short message describing the crash. - * @param longMsg Long message describing the crash. - * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace. - * - * @return Returns a fully-formed AppErrorStateInfo record. - */ - private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app, - int condition, String tag, String shortMsg, String longMsg, byte[] crashData) { - ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo(); - - report.condition = condition; - report.processName = app.processName; - report.pid = app.pid; - report.uid = app.info.uid; - report.tag = tag; - report.shortMsg = shortMsg; - report.longMsg = longMsg; - report.crashData = crashData; - - return report; - } - - void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog, - boolean crashed) { - synchronized (this) { - app.crashing = false; - app.crashingReport = null; - app.notResponding = false; - app.notRespondingReport = null; - if (app.anrDialog == fromDialog) { - app.anrDialog = null; - } - if (app.waitDialog == fromDialog) { - app.waitDialog = null; - } - if (app.pid > 0 && app.pid != MY_PID) { - if (crashed) { - handleAppCrashLocked(app); - } - Log.i(ActivityManagerService.TAG, "Killing process " - + app.processName - + " (pid=" + app.pid + ") at user's request"); - Process.killProcess(app.pid); - } - - } - } - - boolean handleAppCrashLocked(ProcessRecord app) { - long now = SystemClock.uptimeMillis(); - - Long crashTime = mProcessCrashTimes.get(app.info.processName, - app.info.uid); - if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) { - // This process loses! - Log.w(TAG, "Process " + app.info.processName - + " has crashed too many times: killing!"); - EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH, - app.info.processName, app.info.uid); - killServicesLocked(app, false); - for (int i=mHistory.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)mHistory.get(i); - if (r.app == app) { - if (Config.LOGD) Log.d( - TAG, " Force finishing activity " - + r.intent.getComponent().flattenToShortString()); - finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed"); - } - } - if (!app.persistent) { - // We don't want to start this process again until the user - // explicitly does so... but for persistent process, we really - // need to keep it running. If a persistent process is actually - // repeatedly crashing, then badness for everyone. - EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid, - app.info.processName); - mBadProcesses.put(app.info.processName, app.info.uid, now); - app.bad = true; - mProcessCrashTimes.remove(app.info.processName, app.info.uid); - app.removed = true; - removeProcessLocked(app, false); - return false; - } - } - - // Bump up the crash count of any services currently running in the proc. - if (app.services.size() != 0) { - // Any services running in the application need to be placed - // back in the pending list. - Iterator it = app.services.iterator(); - while (it.hasNext()) { - ServiceRecord sr = (ServiceRecord)it.next(); - sr.crashCount++; - } - } - - mProcessCrashTimes.put(app.info.processName, app.info.uid, now); - return true; - } - - void startAppProblemLocked(ProcessRecord app) { - skipCurrentReceiverLocked(app); - } - - void skipCurrentReceiverLocked(ProcessRecord app) { - boolean reschedule = false; - BroadcastRecord r = app.curReceiver; - if (r != null) { - // The current broadcast is waiting for this app's receiver - // to be finished. Looks like that's not going to happen, so - // let the broadcast continue. - logBroadcastReceiverDiscard(r); - finishReceiverLocked(r.receiver, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - reschedule = true; - } - r = mPendingBroadcast; - if (r != null && r.curApp == app) { - if (DEBUG_BROADCAST) Log.v(TAG, - "skip & discard pending app " + r); - logBroadcastReceiverDiscard(r); - finishReceiverLocked(r.receiver, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - reschedule = true; - } - if (reschedule) { - scheduleBroadcastsLocked(); - } - } - - public int handleApplicationError(IBinder app, int flags, - String tag, String shortMsg, String longMsg, byte[] crashData) { - AppErrorResult result = new AppErrorResult(); - - ProcessRecord r = null; - synchronized (this) { - if (app != null) { - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { - final int NA = apps.size(); - for (int ia=0; ia<NA; ia++) { - ProcessRecord p = apps.valueAt(ia); - if (p.thread != null && p.thread.asBinder() == app) { - r = p; - break; - } - } - } - } - - if (r != null) { - // The application has crashed. Send the SIGQUIT to the process so - // that it can dump its state. - Process.sendSignal(r.pid, Process.SIGNAL_QUIT); - //Log.i(TAG, "Current system threads:"); - //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT); - } - - if (mWatcher != null) { - try { - String name = r != null ? r.processName : null; - int pid = r != null ? r.pid : Binder.getCallingPid(); - if (!mWatcher.appCrashed(name, pid, - shortMsg, longMsg, crashData)) { - Log.w(TAG, "Force-killing crashed app " + name - + " at watcher's request"); - Process.killProcess(pid); - return 0; - } - } catch (RemoteException e) { - mWatcher = null; - } - } - - final long origId = Binder.clearCallingIdentity(); - - // If this process is running instrumentation, finish it. - if (r != null && r.instrumentationClass != null) { - Log.w(TAG, "Error in app " + r.processName - + " running instrumentation " + r.instrumentationClass + ":"); - if (shortMsg != null) Log.w(TAG, " " + shortMsg); - if (longMsg != null) Log.w(TAG, " " + longMsg); - Bundle info = new Bundle(); - info.putString("shortMsg", shortMsg); - info.putString("longMsg", longMsg); - finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info); - Binder.restoreCallingIdentity(origId); - return 0; - } - - if (r != null) { - if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) { - return 0; - } - } else { - Log.w(TAG, "Some application object " + app + " tag " + tag - + " has crashed, but I don't know who it is."); - Log.w(TAG, "ShortMsg:" + shortMsg); - Log.w(TAG, "LongMsg:" + longMsg); - Binder.restoreCallingIdentity(origId); - return 0; - } - - Message msg = Message.obtain(); - msg.what = SHOW_ERROR_MSG; - HashMap data = new HashMap(); - data.put("result", result); - data.put("app", r); - data.put("flags", flags); - data.put("shortMsg", shortMsg); - data.put("longMsg", longMsg); - if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - // For system processes, submit crash data to the server. - data.put("crashData", crashData); - } - msg.obj = data; - mHandler.sendMessage(msg); - - Binder.restoreCallingIdentity(origId); - } - - int res = result.get(); - - synchronized (this) { - if (r != null) { - mProcessCrashTimes.put(r.info.processName, r.info.uid, - SystemClock.uptimeMillis()); - } - } - - return res; - } - - public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { - // assume our apps are happy - lazy create the list - List<ActivityManager.ProcessErrorStateInfo> errList = null; - - synchronized (this) { - - // iterate across all processes - final int N = mLRUProcesses.size(); - for (int i = 0; i < N; i++) { - ProcessRecord app = mLRUProcesses.get(i); - if ((app.thread != null) && (app.crashing || app.notResponding)) { - // This one's in trouble, so we'll generate a report for it - // crashes are higher priority (in case there's a crash *and* an anr) - ActivityManager.ProcessErrorStateInfo report = null; - if (app.crashing) { - report = app.crashingReport; - } else if (app.notResponding) { - report = app.notRespondingReport; - } - - if (report != null) { - if (errList == null) { - errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1); - } - errList.add(report); - } else { - Log.w(TAG, "Missing app error report, app = " + app.processName + - " crashing = " + app.crashing + - " notResponding = " + app.notResponding); - } - } - } - } - - return errList; - } - - public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { - // Lazy instantiation of list - List<ActivityManager.RunningAppProcessInfo> runList = null; - synchronized (this) { - // Iterate across all processes - final int N = mLRUProcesses.size(); - for (int i = 0; i < N; i++) { - ProcessRecord app = mLRUProcesses.get(i); - if ((app.thread != null) && (!app.crashing && !app.notResponding)) { - // Generate process state info for running application - 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<ActivityManager.RunningAppProcessInfo>(); - } - runList.add(currApp); - } - } - } - return runList; - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - if (args.length != 0 && "service".equals(args[0])) { - dumpService(fd, pw, args); - return; - } - pw.println("Activities in Current Activity Manager State:"); - dumpHistoryList(pw, mHistory, " ", "History"); - pw.println(" "); - pw.println(" Running activities (most recent first):"); - dumpHistoryList(pw, mLRUActivities, " ", "Running"); - if (mWaitingVisibleActivities.size() > 0) { - pw.println(" "); - pw.println(" Activities waiting for another to become visible:"); - dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Waiting"); - } - if (mStoppingActivities.size() > 0) { - pw.println(" "); - pw.println(" Activities waiting to stop:"); - dumpHistoryList(pw, mStoppingActivities, " ", "Stopping"); - } - if (mFinishingActivities.size() > 0) { - pw.println(" "); - pw.println(" Activities waiting to finish:"); - dumpHistoryList(pw, mFinishingActivities, " ", "Finishing"); - } - - pw.println(" "); - pw.println(" mPausingActivity: " + mPausingActivity); - pw.println(" mResumedActivity: " + mResumedActivity); - pw.println(" mFocusedActivity: " + mFocusedActivity); - - if (mRecentTasks.size() > 0) { - pw.println(" "); - pw.println("Recent tasks in Current Activity Manager State:"); - - final int N = mRecentTasks.size(); - for (int i=0; i<N; i++) { - pw.println(" Recent Task #" + i); - mRecentTasks.get(i).dump(pw, " "); - } - } - - pw.println(" "); - pw.println(" mCurTask: " + mCurTask); - - pw.println(" "); - pw.println("Processes in Current Activity Manager State:"); - - boolean needSep = false; - int numPers = 0; - - for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) { - final int NA = procs.size(); - for (int ia=0; ia<NA; ia++) { - if (!needSep) { - pw.println(" All known processes:"); - needSep = true; - } - ProcessRecord r = procs.valueAt(ia); - pw.println((r.persistent ? " *PERSISTENT* Process [" : " Process [") - + r.processName + "] UID " + procs.keyAt(ia)); - r.dump(pw, " "); - if (r.persistent) { - numPers++; - } - } - } - - if (mLRUProcesses.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Running processes (most recent first):"); - dumpProcessList(pw, mLRUProcesses, " ", - "Running Norm Proc", "Running PERS Proc", true); - needSep = true; - } - - synchronized (mPidsSelfLocked) { - if (mPidsSelfLocked.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" PID mappings:"); - for (int i=0; i<mPidsSelfLocked.size(); i++) { - pw.println(" PID #" + mPidsSelfLocked.keyAt(i) - + ": " + mPidsSelfLocked.valueAt(i)); - } - } - } - - if (mForegroundProcesses.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Foreground Processes:"); - for (int i=0; i<mForegroundProcesses.size(); i++) { - pw.println(" PID #" + mForegroundProcesses.keyAt(i) - + ": " + mForegroundProcesses.valueAt(i)); - } - } - - if (mPersistentStartingProcesses.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Persisent processes that are starting:"); - dumpProcessList(pw, mPersistentStartingProcesses, " ", - "Starting Initial Proc", "Restarting PERS Proc", false); - } - - if (mStartingProcesses.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are starting:"); - dumpProcessList(pw, mStartingProcesses, " ", - "Starting Norm Proc", "Starting PERS Proc", false); - } - - if (mRemovedProcesses.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are being removed:"); - dumpProcessList(pw, mRemovedProcesses, " ", - "Removed Norm Proc", "Removed PERS Proc", false); - } - - if (mProcessesOnHold.size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Processes that are on old until the system is ready:"); - dumpProcessList(pw, mProcessesOnHold, " ", - "OnHold Norm Proc", "OnHold PERS Proc", false); - } - - if (mProcessCrashTimes.getMap().size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Time since processes crashed:"); - long now = SystemClock.uptimeMillis(); - for (Map.Entry<String, SparseArray<Long>> procs - : mProcessCrashTimes.getMap().entrySet()) { - SparseArray<Long> uids = procs.getValue(); - final int N = uids.size(); - for (int i=0; i<N; i++) { - pw.println(" Process " + procs.getKey() - + " uid " + uids.keyAt(i) - + ": last crashed " - + (now-uids.valueAt(i)) + " ms ago"); - } - } - } - - if (mBadProcesses.getMap().size() > 0) { - if (needSep) pw.println(" "); - needSep = true; - pw.println(" Bad processes:"); - for (Map.Entry<String, SparseArray<Long>> procs - : mBadProcesses.getMap().entrySet()) { - SparseArray<Long> uids = procs.getValue(); - final int N = uids.size(); - for (int i=0; i<N; i++) { - pw.println(" Bad process " + procs.getKey() - + " uid " + uids.keyAt(i) - + ": crashed at time " + uids.valueAt(i)); - } - } - } - - pw.println(" "); - pw.println(" Total persistent processes: " + numPers); - pw.println(" mConfiguration: " + mConfiguration); - pw.println(" mStartRunning=" + mStartRunning - + " mSystemReady=" + mSystemReady - + " mBooting=" + mBooting - + " mBooted=" + mBooted - + " mFactoryTest=" + mFactoryTest); - pw.println(" mSleeping=" + mSleeping); - pw.println(" mGoingToSleep=" + mGoingToSleep); - pw.println(" mLaunchingActivity=" + mLaunchingActivity); - pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp - + " mDebugTransient=" + mDebugTransient - + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); - pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities - + " mWatcher=" + mWatcher); - } - } - - /** - * There are three ways to call this: - * - no service specified: dump all the services - * - a flattened component name that matched an existing service was specified as the - * first arg: dump that one service - * - the first arg isn't the flattened component name of an existing service: - * dump all services whose component contains the first arg as a substring - */ - protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) { - String[] newArgs; - String componentNameString; - ServiceRecord r; - if (args.length == 1) { - componentNameString = null; - newArgs = EMPTY_STRING_ARRAY; - r = null; - } else { - componentNameString = args[1]; - ComponentName componentName = ComponentName.unflattenFromString(componentNameString); - r = componentName != null ? mServices.get(componentName) : null; - newArgs = new String[args.length - 2]; - if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2); - } - - if (r != null) { - dumpService(fd, pw, r, newArgs); - } else { - for (ServiceRecord r1 : mServices.values()) { - if (componentNameString == null - || r1.name.flattenToString().contains(componentNameString)) { - dumpService(fd, pw, r1, newArgs); - } - } - } - } - - /** - * Invokes IApplicationThread.dumpService() on the thread of the specified service if - * there is a thread associated with the service. - */ - private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) { - pw.println(" Service " + r.name.flattenToString()); - if (r.app != null && r.app.thread != null) { - try { - // flush anything that is already in the PrintWriter since the thread is going - // to write to the file descriptor directly - pw.flush(); - r.app.thread.dumpService(fd, r, args); - pw.print("\n"); - } catch (RemoteException e) { - pw.println("got a RemoteException while dumping the service"); - } - } - } - - void dumpBroadcasts(PrintWriter pw) { - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - pw.println("Broadcasts in Current Activity Manager State:"); - - if (mRegisteredReceivers.size() > 0) { - pw.println(" "); - pw.println(" Registered Receivers:"); - Iterator it = mRegisteredReceivers.values().iterator(); - while (it.hasNext()) { - ReceiverList r = (ReceiverList)it.next(); - pw.println(" Receiver " + r.receiver); - r.dump(pw, " "); - } - } - - pw.println(" "); - pw.println("Receiver Resolver Table:"); - mReceiverResolver.dump(new PrintWriterPrinter(pw), " "); - - if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0 - || mPendingBroadcast != null) { - if (mParallelBroadcasts.size() > 0) { - pw.println(" "); - pw.println(" Active broadcasts:"); - } - for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { - pw.println(" Broadcast #" + i + ":"); - mParallelBroadcasts.get(i).dump(pw, " "); - } - if (mOrderedBroadcasts.size() > 0) { - pw.println(" "); - pw.println(" Active serialized broadcasts:"); - } - for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) { - pw.println(" Serialized Broadcast #" + i + ":"); - mOrderedBroadcasts.get(i).dump(pw, " "); - } - pw.println(" "); - pw.println(" Pending broadcast:"); - if (mPendingBroadcast != null) { - mPendingBroadcast.dump(pw, " "); - } else { - pw.println(" (null)"); - } - } - - pw.println(" "); - pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled); - if (mStickyBroadcasts != null) { - pw.println(" "); - pw.println(" Sticky broadcasts:"); - for (Map.Entry<String, ArrayList<Intent>> ent - : mStickyBroadcasts.entrySet()) { - pw.println(" Sticky action " + ent.getKey() + ":"); - ArrayList<Intent> intents = ent.getValue(); - final int N = intents.size(); - for (int i=0; i<N; i++) { - pw.println(" " + intents.get(i)); - } - } - } - - pw.println(" "); - pw.println(" mHandler:"); - mHandler.dump(new PrintWriterPrinter(pw), " "); - } - } - - void dumpServices(PrintWriter pw) { - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - pw.println("Services in Current Activity Manager State:"); - - boolean needSep = false; - - if (mServices.size() > 0) { - pw.println(" Active services:"); - Iterator<ServiceRecord> it = mServices.values().iterator(); - while (it.hasNext()) { - ServiceRecord r = it.next(); - pw.println(" Service " + r.shortName); - r.dump(pw, " "); - } - needSep = true; - } - - if (mPendingServices.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Pending services:"); - for (int i=0; i<mPendingServices.size(); i++) { - ServiceRecord r = mPendingServices.get(i); - pw.println(" Pending Service " + r.shortName); - r.dump(pw, " "); - } - needSep = true; - } - - if (mRestartingServices.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Restarting services:"); - for (int i=0; i<mRestartingServices.size(); i++) { - ServiceRecord r = mRestartingServices.get(i); - pw.println(" Restarting Service " + r.shortName); - r.dump(pw, " "); - } - needSep = true; - } - - if (mStoppingServices.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Stopping services:"); - for (int i=0; i<mStoppingServices.size(); i++) { - ServiceRecord r = mStoppingServices.get(i); - pw.println(" Stopping Service " + r.shortName); - r.dump(pw, " "); - } - needSep = true; - } - - if (mServiceConnections.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Connection bindings to services:"); - Iterator<ConnectionRecord> it - = mServiceConnections.values().iterator(); - while (it.hasNext()) { - ConnectionRecord r = it.next(); - pw.println(" " + r.binding.service.shortName - + " -> " + r.conn.asBinder()); - r.dump(pw, " "); - } - } - } - } - - void dumpProviders(PrintWriter pw) { - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - - pw.println("Content Providers in Current Activity Manager State:"); - - boolean needSep = false; - - if (mProvidersByName.size() > 0) { - pw.println(" Published content providers (by name):"); - Iterator it = mProvidersByName.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = (Map.Entry)it.next(); - ContentProviderRecord r = (ContentProviderRecord)e.getValue(); - pw.println(" Provider " + (String)e.getKey()); - r.dump(pw, " "); - } - needSep = true; - } - - if (mProvidersByClass.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Published content providers (by class):"); - Iterator it = mProvidersByClass.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = (Map.Entry)it.next(); - ContentProviderRecord r = (ContentProviderRecord)e.getValue(); - pw.println(" Provider " + (String)e.getKey()); - r.dump(pw, " "); - } - needSep = true; - } - - if (mLaunchingProviders.size() > 0) { - if (needSep) pw.println(" "); - pw.println(" Launching content providers:"); - for (int i=mLaunchingProviders.size()-1; i>=0; i--) { - pw.println(" Provider #" + i + ":"); - ((ContentProviderRecord)mLaunchingProviders.get(i)).dump(pw, " "); - } - needSep = true; - } - - pw.println(); - pw.println("Granted Uri Permissions:"); - for (int i=0; i<mGrantedUriPermissions.size(); i++) { - int uid = mGrantedUriPermissions.keyAt(i); - HashMap<Uri, UriPermission> perms - = mGrantedUriPermissions.valueAt(i); - pw.println(" Uris granted to uid " + uid + ":"); - for (UriPermission perm : perms.values()) { - perm.dump(pw, " "); - } - } - } - } - - void dumpSenders(PrintWriter pw) { - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ActivityManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " without permission " - + android.Manifest.permission.DUMP); - return; - } - - pw.println("Intent Senders in Current Activity Manager State:"); - - if (this.mIntentSenderRecords.size() > 0) { - Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> ref = it.next(); - PendingIntentRecord rec = ref != null ? ref.get(): null; - if (rec != null) { - pw.println(" IntentSender " + rec); - rec.dump(pw, " "); - } else { - pw.println(" IntentSender " + ref); - } - } - } - } - } - - private static final void dumpHistoryList(PrintWriter pw, List list, - String prefix, String label) { - TaskRecord lastTask = null; - for (int i=list.size()-1; i>=0; i--) { - HistoryRecord r = (HistoryRecord)list.get(i); - if (lastTask != r.task) { - lastTask = r.task; - lastTask.dump(pw, prefix + " "); - } - pw.println(prefix + " " + label + " #" + i + ":"); - r.dump(pw, prefix + " "); - } - } - - private static final int dumpProcessList(PrintWriter pw, List list, - String prefix, String normalLabel, String persistentLabel, - boolean inclOomAdj) { - int numPers = 0; - for (int i=list.size()-1; i>=0; i--) { - ProcessRecord r = (ProcessRecord)list.get(i); - if (false) { - pw.println(prefix + (r.persistent ? persistentLabel : normalLabel) - + " #" + i + ":"); - r.dump(pw, prefix + " "); - } else if (inclOomAdj) { - pw.println(String.format("%s%s #%2d: oom_adj=%3d %s", - prefix, (r.persistent ? persistentLabel : normalLabel), - i, r.setAdj, r.toString())); - } else { - pw.println(String.format("%s%s #%2d: %s", - prefix, (r.persistent ? persistentLabel : normalLabel), - i, r.toString())); - } - if (r.persistent) { - numPers++; - } - } - return numPers; - } - - private static final void dumpApplicationMemoryUsage(FileDescriptor fd, - 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) { - if (!isCheckinRequest) { - pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **"); - pw.flush(); - } - try { - r.thread.asBinder().dump(fd, args); - } catch (RemoteException e) { - if (!isCheckinRequest) { - pw.println("Got RemoteException!"); - pw.flush(); - } - } - } - } - } - - /** - * 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) { - int count = mHistory.size(); - - // convert the token to an entry in the history. - HistoryRecord r = null; - int index = -1; - for (int i=count-1; i>=0; i--) { - Object o = mHistory.get(i); - if (o == token) { - r = (HistoryRecord)o; - index = i; - break; - } - } - if (index < 0 && required) { - RuntimeInit.crash(TAG, new InvalidTokenException(token)); - } - - return index; - } - - static class InvalidTokenException extends Exception { - InvalidTokenException(IBinder token) { - super("Bad activity token: " + token); - } - } - - private final void killServicesLocked(ProcessRecord app, - boolean allowRestart) { - // Report disconnected services. - if (false) { - // XXX we are letting the client link to the service for - // death notifications. - if (app.services.size() > 0) { - Iterator it = app.services.iterator(); - while (it.hasNext()) { - ServiceRecord r = (ServiceRecord)it.next(); - if (r.connections.size() > 0) { - Iterator<ConnectionRecord> jt - = r.connections.values().iterator(); - while (jt.hasNext()) { - ConnectionRecord c = jt.next(); - if (c.binding.client != app) { - try { - //c.conn.connected(r.className, null); - } catch (Exception e) { - // todo: this should be asynchronous! - Log.w(TAG, "Exception thrown disconnected servce " - + r.shortName - + " from app " + app.processName, e); - } - } - } - } - } - } - } - - // Clean up any connections this application has to other services. - if (app.connections.size() > 0) { - Iterator<ConnectionRecord> it = app.connections.iterator(); - while (it.hasNext()) { - ConnectionRecord r = it.next(); - removeConnectionLocked(r, app, null); - } - } - app.connections.clear(); - - if (app.services.size() != 0) { - // Any services running in the application need to be placed - // back in the pending list. - Iterator it = app.services.iterator(); - while (it.hasNext()) { - ServiceRecord sr = (ServiceRecord)it.next(); - synchronized (sr.stats.getBatteryStats()) { - sr.stats.stopLaunchedLocked(); - } - sr.app = null; - sr.executeNesting = 0; - mStoppingServices.remove(sr); - if (sr.bindings.size() > 0) { - Iterator<IntentBindRecord> bindings - = sr.bindings.values().iterator(); - while (bindings.hasNext()) { - IntentBindRecord b = bindings.next(); - if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b - + ": shouldUnbind=" + b.hasBound); - b.binder = null; - b.requested = b.received = b.hasBound = false; - } - } - - if (sr.crashCount >= 2) { - Log.w(TAG, "Service crashed " + sr.crashCount - + " times, stopping: " + sr); - EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH, - sr.crashCount, sr.shortName, app.pid); - bringDownServiceLocked(sr, true); - } else if (!allowRestart) { - bringDownServiceLocked(sr, true); - } else { - scheduleServiceRestartLocked(sr); - } - } - - if (!allowRestart) { - app.services.clear(); - } - } - - app.executingServices.clear(); - } - - private final void removeDyingProviderLocked(ProcessRecord proc, - ContentProviderRecord cpr) { - synchronized (cpr) { - cpr.launchingApp = null; - cpr.notifyAll(); - } - - mProvidersByClass.remove(cpr.info.name); - String names[] = cpr.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - mProvidersByName.remove(names[j]); - } - - Iterator<ProcessRecord> cit = cpr.clients.iterator(); - while (cit.hasNext()) { - ProcessRecord capp = cit.next(); - if (!capp.persistent && capp.thread != null - && capp.pid != 0 - && capp.pid != MY_PID) { - Log.i(TAG, "Killing app " + capp.processName - + " (pid " + capp.pid - + ") because provider " + cpr.info.name - + " is in dying process " + proc.processName); - Process.killProcess(capp.pid); - } - } - - mLaunchingProviders.remove(cpr); - } - - /** - * Main code for cleaning up a process when it has gone away. This is - * called both as a result of the process dying, or directly when stopping - * a process when running in single process mode. - */ - private final void cleanUpApplicationRecordLocked(ProcessRecord app, - boolean restarting, int index) { - if (index >= 0) { - mLRUProcesses.remove(index); - } - - // Dismiss any open dialogs. - if (app.crashDialog != null) { - app.crashDialog.dismiss(); - app.crashDialog = null; - } - if (app.anrDialog != null) { - app.anrDialog.dismiss(); - app.anrDialog = null; - } - if (app.waitDialog != null) { - app.waitDialog.dismiss(); - app.waitDialog = null; - } - - app.crashing = false; - app.notResponding = false; - - app.resetPackageList(); - app.thread = null; - app.forcingToForeground = null; - app.foregroundServices = false; - - killServicesLocked(app, true); - - boolean restart = false; - - int NL = mLaunchingProviders.size(); - - // Remove published content providers. - if (!app.pubProviders.isEmpty()) { - Iterator it = app.pubProviders.values().iterator(); - while (it.hasNext()) { - ContentProviderRecord cpr = (ContentProviderRecord)it.next(); - cpr.provider = null; - cpr.app = null; - - // See if someone is waiting for this provider... in which - // case we don't remove it, but just let it restart. - int i = 0; - if (!app.bad) { - for (; i<NL; i++) { - if (mLaunchingProviders.get(i) == cpr) { - restart = true; - break; - } - } - } else { - i = NL; - } - - if (i >= NL) { - removeDyingProviderLocked(app, cpr); - NL = mLaunchingProviders.size(); - } - } - app.pubProviders.clear(); - } - - // Look through the content providers we are waiting to have launched, - // and if any run in this process then either schedule a restart of - // the process or kill the client waiting for it if this process has - // gone bad. - for (int i=0; i<NL; i++) { - ContentProviderRecord cpr = (ContentProviderRecord) - mLaunchingProviders.get(i); - if (cpr.launchingApp == app) { - if (!app.bad) { - restart = true; - } else { - removeDyingProviderLocked(app, cpr); - NL = mLaunchingProviders.size(); - } - } - } - - // Unregister from connected content providers. - if (!app.conProviders.isEmpty()) { - Iterator it = app.conProviders.iterator(); - while (it.hasNext()) { - ContentProviderRecord cpr = (ContentProviderRecord)it.next(); - cpr.clients.remove(app); - } - app.conProviders.clear(); - } - - skipCurrentReceiverLocked(app); - - // Unregister any receivers. - if (app.receivers.size() > 0) { - Iterator<ReceiverList> it = app.receivers.iterator(); - while (it.hasNext()) { - removeReceiverLocked(it.next()); - } - app.receivers.clear(); - } - - // If the caller is restarting this app, then leave it in its - // current lists and let the caller take care of it. - if (restarting) { - return; - } - - if (!app.persistent) { - if (DEBUG_PROCESSES) Log.v(TAG, - "Removing non-persistent process during cleanup: " + app); - mProcessNames.remove(app.processName, app.info.uid); - } else if (!app.removed) { - // This app is persistent, so we need to keep its record around. - // If it is not already on the pending app list, add it there - // and start a new process for it. - app.thread = null; - app.forcingToForeground = null; - app.foregroundServices = false; - if (mPersistentStartingProcesses.indexOf(app) < 0) { - mPersistentStartingProcesses.add(app); - restart = true; - } - } - mProcessesOnHold.remove(app); - - if (restart) { - // We have components that still need to be running in the - // process, so re-launch it. - mProcessNames.put(app.processName, app.info.uid, app); - startProcessLocked(app, "restart", app.processName); - } else if (app.pid > 0 && app.pid != MY_PID) { - // Goodbye! - synchronized (mPidsSelfLocked) { - mPidsSelfLocked.remove(app.pid); - mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - } - app.pid = 0; - } - } - - // ========================================================= - // SERVICES - // ========================================================= - - ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) { - ActivityManager.RunningServiceInfo info = - new ActivityManager.RunningServiceInfo(); - info.service = r.name; - if (r.app != null) { - info.pid = r.app.pid; - } - info.process = r.processName; - info.foreground = r.isForeground; - info.activeSince = r.createTime; - info.started = r.startRequested; - info.clientCount = r.connections.size(); - info.crashCount = r.crashCount; - info.lastActivityTime = r.lastActivity; - return info; - } - - public List<ActivityManager.RunningServiceInfo> getServices(int maxNum, - int flags) { - synchronized (this) { - ArrayList<ActivityManager.RunningServiceInfo> res - = new ArrayList<ActivityManager.RunningServiceInfo>(); - - if (mServices.size() > 0) { - Iterator<ServiceRecord> it = mServices.values().iterator(); - while (it.hasNext() && res.size() < maxNum) { - res.add(makeRunningServiceInfoLocked(it.next())); - } - } - - for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) { - ServiceRecord r = mRestartingServices.get(i); - ActivityManager.RunningServiceInfo info = - makeRunningServiceInfoLocked(r); - info.restarting = r.nextRestartTime; - res.add(info); - } - - return res; - } - } - - private final ServiceRecord findServiceLocked(ComponentName name, - IBinder token) { - ServiceRecord r = mServices.get(name); - return r == token ? r : null; - } - - private final class ServiceLookupResult { - final ServiceRecord record; - final String permission; - - ServiceLookupResult(ServiceRecord _record, String _permission) { - record = _record; - permission = _permission; - } - }; - - private ServiceLookupResult findServiceLocked(Intent service, - String resolvedType) { - ServiceRecord r = null; - if (service.getComponent() != null) { - r = mServices.get(service.getComponent()); - } - if (r == null) { - Intent.FilterComparison filter = new Intent.FilterComparison(service); - r = mServicesByIntent.get(filter); - } - - if (r == null) { - try { - ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveService( - service, resolvedType, 0); - ServiceInfo sInfo = - rInfo != null ? rInfo.serviceInfo : null; - if (sInfo == null) { - return null; - } - - ComponentName name = new ComponentName( - sInfo.applicationInfo.packageName, sInfo.name); - r = mServices.get(name); - } catch (RemoteException ex) { - // pm is in same process, this will never happen. - } - } - if (r != null) { - int callingPid = Binder.getCallingPid(); - int callingUid = Binder.getCallingUid(); - if (checkComponentPermission(r.permission, - callingPid, callingUid, r.exported ? -1 : r.appInfo.uid) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: Accessing service " + r.name - + " from pid=" + callingPid - + ", uid=" + callingUid - + " requires " + r.permission); - return new ServiceLookupResult(null, r.permission); - } - return new ServiceLookupResult(r, null); - } - return null; - } - - private class ServiceRestarter implements Runnable { - private ServiceRecord mService; - - void setService(ServiceRecord service) { - mService = service; - } - - public void run() { - synchronized(ActivityManagerService.this) { - performServiceRestartLocked(mService); - } - } - } - - private ServiceLookupResult retrieveServiceLocked(Intent service, - String resolvedType, int callingPid, int callingUid) { - ServiceRecord r = null; - if (service.getComponent() != null) { - r = mServices.get(service.getComponent()); - } - Intent.FilterComparison filter = new Intent.FilterComparison(service); - r = mServicesByIntent.get(filter); - if (r == null) { - try { - ResolveInfo rInfo = - ActivityThread.getPackageManager().resolveService( - service, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES); - ServiceInfo sInfo = - rInfo != null ? rInfo.serviceInfo : null; - if (sInfo == null) { - Log.w(TAG, "Unable to start service " + service + - ": not found"); - return null; - } - - ComponentName name = new ComponentName( - sInfo.applicationInfo.packageName, sInfo.name); - r = mServices.get(name); - if (r == null) { - filter = new Intent.FilterComparison(service.cloneFilter()); - ServiceRestarter res = new ServiceRestarter(); - BatteryStatsImpl.Uid.Pkg.Serv ss = null; - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - synchronized (stats) { - ss = stats.getServiceStatsLocked( - sInfo.applicationInfo.uid, sInfo.packageName, - sInfo.name); - } - r = new ServiceRecord(ss, name, filter, sInfo, res); - res.setService(r); - mServices.put(name, r); - mServicesByIntent.put(filter, r); - - // Make sure this component isn't in the pending list. - int N = mPendingServices.size(); - for (int i=0; i<N; i++) { - ServiceRecord pr = mPendingServices.get(i); - if (pr.name.equals(name)) { - mPendingServices.remove(i); - i--; - N--; - } - } - } - } catch (RemoteException ex) { - // pm is in same process, this will never happen. - } - } - if (r != null) { - if (checkComponentPermission(r.permission, - callingPid, callingUid, r.exported ? -1 : r.appInfo.uid) - != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: Accessing service " + r.name - + " from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + r.permission); - return new ServiceLookupResult(null, r.permission); - } - return new ServiceLookupResult(r, null); - } - return null; - } - - private final void bumpServiceExecutingLocked(ServiceRecord r) { - long now = SystemClock.uptimeMillis(); - if (r.executeNesting == 0 && r.app != null) { - if (r.app.executingServices.size() == 0) { - Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG); - msg.obj = r.app; - mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT); - } - r.app.executingServices.add(r); - } - r.executeNesting++; - r.executingStart = now; - } - - private final void sendServiceArgsLocked(ServiceRecord r, - boolean oomAdjusted) { - final int N = r.startArgs.size(); - if (N == 0) { - return; - } - - final int BASEID = r.lastStartId - N + 1; - int i = 0; - while (i < N) { - try { - Intent args = r.startArgs.get(i); - if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: " - + r.name + " " + r.intent + " args=" + args); - bumpServiceExecutingLocked(r); - if (!oomAdjusted) { - oomAdjusted = true; - updateOomAdjLocked(r.app); - } - r.app.thread.scheduleServiceArgs(r, BASEID+i, args); - i++; - } catch (Exception e) { - break; - } - } - if (i == N) { - r.startArgs.clear(); - } else { - while (i > 0) { - r.startArgs.remove(0); - i--; - } - } - } - - private final boolean requestServiceBindingLocked(ServiceRecord r, - IntentBindRecord i, boolean rebind) { - if (r.app == null || r.app.thread == null) { - // If service is not currently running, can't yet bind. - return false; - } - if ((!i.requested || rebind) && i.apps.size() > 0) { - try { - bumpServiceExecutingLocked(r); - if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i - + ": shouldUnbind=" + i.hasBound); - r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind); - if (!rebind) { - i.requested = true; - } - i.hasBound = true; - i.doRebind = false; - } catch (RemoteException e) { - return false; - } - } - return true; - } - - private final void requestServiceBindingsLocked(ServiceRecord r) { - Iterator<IntentBindRecord> bindings = r.bindings.values().iterator(); - while (bindings.hasNext()) { - IntentBindRecord i = bindings.next(); - if (!requestServiceBindingLocked(r, i, false)) { - break; - } - } - } - - private final void realStartServiceLocked(ServiceRecord r, - ProcessRecord app) throws RemoteException { - if (app.thread == null) { - throw new RemoteException(); - } - - r.app = app; - r.restartTime = SystemClock.uptimeMillis(); - - app.services.add(r); - bumpServiceExecutingLocked(r); - updateLRUListLocked(app, true); - - boolean created = false; - try { - if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: " - + r.name + " " + r.intent); - EventLog.writeEvent(LOG_AM_CREATE_SERVICE, - System.identityHashCode(r), r.shortName, - r.intent.getIntent().toString(), r.app.pid); - synchronized (r.stats.getBatteryStats()) { - r.stats.startLaunchedLocked(); - } - app.thread.scheduleCreateService(r, r.serviceInfo); - created = true; - } finally { - if (!created) { - app.services.remove(r); - scheduleServiceRestartLocked(r); - } - } - - requestServiceBindingsLocked(r); - sendServiceArgsLocked(r, true); - } - - private final void scheduleServiceRestartLocked(ServiceRecord r) { - r.totalRestartCount++; - if (r.restartDelay == 0) { - r.restartCount++; - r.restartDelay = SERVICE_RESTART_DURATION; - } else { - // If it has been a "reasonably long time" since the service - // was started, then reset our restart duration back to - // the beginning, so we don't infinitely increase the duration - // on a service that just occasionally gets killed (which is - // a normal case, due to process being killed to reclaim memory). - long now = SystemClock.uptimeMillis(); - if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) { - r.restartCount = 1; - r.restartDelay = SERVICE_RESTART_DURATION; - } else { - r.restartDelay *= 2; - } - } - if (!mRestartingServices.contains(r)) { - mRestartingServices.add(r); - } - mHandler.removeCallbacks(r.restarter); - mHandler.postDelayed(r.restarter, r.restartDelay); - r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay; - Log.w(TAG, "Scheduling restart of crashed service " - + r.shortName + " in " + r.restartDelay + "ms"); - EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART, - r.shortName, r.restartDelay); - - Message msg = Message.obtain(); - msg.what = SERVICE_ERROR_MSG; - msg.obj = r; - mHandler.sendMessage(msg); - } - - final void performServiceRestartLocked(ServiceRecord r) { - if (!mRestartingServices.contains(r)) { - return; - } - bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true); - } - - private final boolean unscheduleServiceRestartLocked(ServiceRecord r) { - if (r.restartDelay == 0) { - return false; - } - r.resetRestartCounter(); - mRestartingServices.remove(r); - mHandler.removeCallbacks(r.restarter); - return true; - } - - private final boolean bringUpServiceLocked(ServiceRecord r, - int intentFlags, boolean whileRestarting) { - //Log.i(TAG, "Bring up service:"); - //r.dump(" "); - - if (r.app != null) { - sendServiceArgsLocked(r, false); - return true; - } - - if (!whileRestarting && r.restartDelay > 0) { - // If waiting for a restart, then do nothing. - return true; - } - - if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name - + " " + r.intent); - - final String appName = r.processName; - ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid); - if (app != null && app.thread != null) { - try { - realStartServiceLocked(r, app); - return true; - } catch (RemoteException e) { - Log.w(TAG, "Exception when starting service " + r.shortName, e); - } - - // If a dead object exception was thrown -- fall through to - // restart the application. - } - - if (!mPendingServices.contains(r)) { - // Not running -- get it started, and enqueue this service record - // to be executed when the app comes up. - if (startProcessLocked(appName, r.appInfo, true, intentFlags, - "service", r.name) == null) { - Log.w(TAG, "Unable to launch app " - + r.appInfo.packageName + "/" - + r.appInfo.uid + " for service " - + r.intent.getIntent() + ": process is bad"); - bringDownServiceLocked(r, true); - return false; - } - mPendingServices.add(r); - } - return true; - } - - private final void bringDownServiceLocked(ServiceRecord r, boolean force) { - //Log.i(TAG, "Bring down service:"); - //r.dump(" "); - - // Does it still need to run? - if (!force && r.startRequested) { - return; - } - if (r.connections.size() > 0) { - if (!force) { - // XXX should probably keep a count of the number of auto-create - // connections directly in the service. - Iterator<ConnectionRecord> it = r.connections.values().iterator(); - while (it.hasNext()) { - ConnectionRecord cr = it.next(); - if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { - return; - } - } - } - - // Report to all of the connections that the service is no longer - // available. - Iterator<ConnectionRecord> it = r.connections.values().iterator(); - while (it.hasNext()) { - ConnectionRecord c = it.next(); - try { - // todo: shouldn't be a synchronous call! - c.conn.connected(r.name, null); - } catch (Exception e) { - Log.w(TAG, "Failure disconnecting service " + r.name + - " to connection " + c.conn.asBinder() + - " (in " + c.binding.client.processName + ")", e); - } - } - } - - // Tell the service that it has been unbound. - if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) { - Iterator<IntentBindRecord> it = r.bindings.values().iterator(); - while (it.hasNext()) { - IntentBindRecord ibr = it.next(); - if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr - + ": hasBound=" + ibr.hasBound); - if (r.app != null && r.app.thread != null && ibr.hasBound) { - try { - bumpServiceExecutingLocked(r); - updateOomAdjLocked(r.app); - ibr.hasBound = false; - r.app.thread.scheduleUnbindService(r, - ibr.intent.getIntent()); - } catch (Exception e) { - Log.w(TAG, "Exception when unbinding service " - + r.shortName, e); - serviceDoneExecutingLocked(r, true); - } - } - } - } - - if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name - + " " + r.intent); - EventLog.writeEvent(LOG_AM_DESTROY_SERVICE, - System.identityHashCode(r), r.shortName, - (r.app != null) ? r.app.pid : -1); - - mServices.remove(r.name); - mServicesByIntent.remove(r.intent); - if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName); - r.totalRestartCount = 0; - unscheduleServiceRestartLocked(r); - - // Also make sure it is not on the pending list. - int N = mPendingServices.size(); - for (int i=0; i<N; i++) { - if (mPendingServices.get(i) == r) { - mPendingServices.remove(i); - if (DEBUG_SERVICE) Log.v( - TAG, "Removed pending service: " + r.shortName); - i--; - N--; - } - } - - if (r.app != null) { - synchronized (r.stats.getBatteryStats()) { - r.stats.stopLaunchedLocked(); - } - r.app.services.remove(r); - if (r.app.thread != null) { - updateServiceForegroundLocked(r.app, false); - try { - Log.i(TAG, "Stopping service: " + r.shortName); - bumpServiceExecutingLocked(r); - mStoppingServices.add(r); - updateOomAdjLocked(r.app); - r.app.thread.scheduleStopService(r); - } catch (Exception e) { - Log.w(TAG, "Exception when stopping service " - + r.shortName, e); - serviceDoneExecutingLocked(r, true); - } - } else { - if (DEBUG_SERVICE) Log.v( - TAG, "Removed service that has no process: " + r.shortName); - } - } else { - if (DEBUG_SERVICE) Log.v( - TAG, "Removed service that is not running: " + r.shortName); - } - } - - ComponentName startServiceLocked(IApplicationThread caller, - Intent service, String resolvedType, - int callingPid, int callingUid) { - synchronized(this) { - if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service - + " type=" + resolvedType + " args=" + service.getExtras()); - - if (caller != null) { - final ProcessRecord callerApp = getRecordForAppLocked(caller); - if (callerApp == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when starting service " + service); - } - } - - ServiceLookupResult res = - retrieveServiceLocked(service, resolvedType, - callingPid, callingUid); - if (res == null) { - return null; - } - if (res.record == null) { - return new ComponentName("!", res.permission != null - ? res.permission : "private to package"); - } - ServiceRecord r = res.record; - if (unscheduleServiceRestartLocked(r)) { - if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: " - + r.shortName); - } - r.startRequested = true; - r.startArgs.add(service); - r.lastStartId++; - if (r.lastStartId < 1) { - r.lastStartId = 1; - } - r.lastActivity = SystemClock.uptimeMillis(); - synchronized (r.stats.getBatteryStats()) { - r.stats.startRunningLocked(); - } - if (!bringUpServiceLocked(r, service.getFlags(), false)) { - return new ComponentName("!", "Service process is bad"); - } - return r.name; - } - } - - public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType) { - // Refuse possible leaked file descriptors - if (service != null && service.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); - final long origId = Binder.clearCallingIdentity(); - ComponentName res = startServiceLocked(caller, service, - resolvedType, callingPid, callingUid); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - ComponentName startServiceInPackage(int uid, - Intent service, String resolvedType) { - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - ComponentName res = startServiceLocked(null, service, - resolvedType, -1, uid); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - public int stopService(IApplicationThread caller, Intent service, - String resolvedType) { - // Refuse possible leaked file descriptors - if (service != null && service.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service - + " type=" + resolvedType); - - final ProcessRecord callerApp = getRecordForAppLocked(caller); - if (caller != null && callerApp == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when stopping service " + service); - } - - // If this service is active, make sure it is stopped. - ServiceLookupResult r = findServiceLocked(service, resolvedType); - if (r != null) { - if (r.record != null) { - synchronized (r.record.stats.getBatteryStats()) { - r.record.stats.stopRunningLocked(); - } - r.record.startRequested = false; - final long origId = Binder.clearCallingIdentity(); - bringDownServiceLocked(r.record, false); - Binder.restoreCallingIdentity(origId); - return 1; - } - return -1; - } - } - - 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) { - if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className - + " " + token + " startId=" + startId); - ServiceRecord r = findServiceLocked(className, token); - if (r != null && (startId < 0 || r.lastStartId == startId)) { - synchronized (r.stats.getBatteryStats()) { - r.stats.stopRunningLocked(); - r.startRequested = false; - } - final long origId = Binder.clearCallingIdentity(); - bringDownServiceLocked(r, false); - Binder.restoreCallingIdentity(origId); - return true; - } - } - return false; - } - - public void setServiceForeground(ComponentName className, IBinder token, - boolean isForeground) { - synchronized(this) { - ServiceRecord r = findServiceLocked(className, token); - if (r != null) { - if (r.isForeground != isForeground) { - final long origId = Binder.clearCallingIdentity(); - r.isForeground = isForeground; - if (r.app != null) { - updateServiceForegroundLocked(r.app, true); - } - Binder.restoreCallingIdentity(origId); - } - } - } - } - - public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) { - boolean anyForeground = false; - for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) { - if (sr.isForeground) { - anyForeground = true; - break; - } - } - if (anyForeground != proc.foregroundServices) { - proc.foregroundServices = anyForeground; - if (oomAdj) { - updateOomAdjLocked(); - } - } - } - - public int bindService(IApplicationThread caller, IBinder token, - Intent service, String resolvedType, - IServiceConnection connection, int flags) { - // Refuse possible leaked file descriptors - if (service != null && service.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service - + " type=" + resolvedType + " conn=" + connection.asBinder() - + " flags=0x" + Integer.toHexString(flags)); - final ProcessRecord callerApp = getRecordForAppLocked(caller); - if (callerApp == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when binding service " + service); - } - - HistoryRecord activity = null; - if (token != null) { - int aindex = indexOfTokenLocked(token, false); - if (aindex < 0) { - Log.w(TAG, "Binding with unknown activity: " + token); - return 0; - } - activity = (HistoryRecord)mHistory.get(aindex); - } - - ServiceLookupResult res = - retrieveServiceLocked(service, resolvedType, - Binder.getCallingPid(), Binder.getCallingUid()); - if (res == null) { - return 0; - } - if (res.record == null) { - return -1; - } - ServiceRecord s = res.record; - - final long origId = Binder.clearCallingIdentity(); - - if (unscheduleServiceRestartLocked(s)) { - if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " - + s.shortName); - } - - AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); - ConnectionRecord c = new ConnectionRecord(b, activity, - connection, flags); - - IBinder binder = connection.asBinder(); - s.connections.put(binder, c); - b.connections.add(c); - if (activity != null) { - if (activity.connections == null) { - activity.connections = new HashSet<ConnectionRecord>(); - } - activity.connections.add(c); - } - b.client.connections.add(c); - mServiceConnections.put(binder, c); - - if ((flags&Context.BIND_AUTO_CREATE) != 0) { - s.lastActivity = SystemClock.uptimeMillis(); - if (!bringUpServiceLocked(s, service.getFlags(), false)) { - return 0; - } - } - - if (s.app != null) { - // This could have made the service more important. - updateOomAdjLocked(s.app); - } - - if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b - + ": received=" + b.intent.received - + " apps=" + b.intent.apps.size() - + " doRebind=" + b.intent.doRebind); - - if (s.app != null && b.intent.received) { - // Service is already running, so we can immediately - // publish the connection. - try { - c.conn.connected(s.name, b.intent.binder); - } catch (Exception e) { - Log.w(TAG, "Failure sending service " + s.shortName - + " to connection " + c.conn.asBinder() - + " (in " + c.binding.client.processName + ")", e); - } - - // If this is the first app connected back to this binding, - // and the service had previously asked to be told when - // rebound, then do so. - if (b.intent.apps.size() == 1 && b.intent.doRebind) { - requestServiceBindingLocked(s, b.intent, true); - } - } else if (!b.intent.requested) { - requestServiceBindingLocked(s, b.intent, false); - } - - Binder.restoreCallingIdentity(origId); - } - - return 1; - } - - private void removeConnectionLocked( - ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) { - IBinder binder = c.conn.asBinder(); - AppBindRecord b = c.binding; - ServiceRecord s = b.service; - s.connections.remove(binder); - b.connections.remove(c); - if (c.activity != null && c.activity != skipAct) { - if (c.activity.connections != null) { - c.activity.connections.remove(c); - } - } - if (b.client != skipApp) { - b.client.connections.remove(c); - } - mServiceConnections.remove(binder); - - if (b.connections.size() == 0) { - b.intent.apps.remove(b.client); - } - - if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent - + ": shouldUnbind=" + b.intent.hasBound); - if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 - && b.intent.hasBound) { - try { - bumpServiceExecutingLocked(s); - updateOomAdjLocked(s.app); - b.intent.hasBound = false; - // Assume the client doesn't want to know about a rebind; - // we will deal with that later if it asks for one. - b.intent.doRebind = false; - s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent()); - } catch (Exception e) { - Log.w(TAG, "Exception when unbinding service " + s.shortName, e); - serviceDoneExecutingLocked(s, true); - } - } - - if ((c.flags&Context.BIND_AUTO_CREATE) != 0) { - bringDownServiceLocked(s, false); - } - } - - public boolean unbindService(IServiceConnection connection) { - synchronized (this) { - IBinder binder = connection.asBinder(); - if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder); - ConnectionRecord r = mServiceConnections.get(binder); - if (r == null) { - Log.w(TAG, "Unbind failed: could not find connection for " - + connection.asBinder()); - return false; - } - - final long origId = Binder.clearCallingIdentity(); - - removeConnectionLocked(r, null, null); - - if (r.binding.service.app != null) { - // This could have made the service less important. - updateOomAdjLocked(r.binding.service.app); - } - - Binder.restoreCallingIdentity(origId); - } - - return true; - } - - public void publishService(IBinder token, Intent intent, IBinder service) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (!(token instanceof ServiceRecord)) { - throw new IllegalArgumentException("Invalid service token"); - } - ServiceRecord r = (ServiceRecord)token; - - final long origId = Binder.clearCallingIdentity(); - - if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name - + " " + intent + ": " + service); - if (r != null) { - Intent.FilterComparison filter - = new Intent.FilterComparison(intent); - IntentBindRecord b = r.bindings.get(filter); - if (b != null && !b.received) { - b.binder = service; - b.requested = true; - b.received = true; - if (r.connections.size() > 0) { - Iterator<ConnectionRecord> it - = r.connections.values().iterator(); - while (it.hasNext()) { - ConnectionRecord c = it.next(); - if (!filter.equals(c.binding.intent.intent)) { - if (DEBUG_SERVICE) Log.v( - TAG, "Not publishing to: " + c); - if (DEBUG_SERVICE) Log.v( - TAG, "Bound intent: " + c.binding.intent.intent); - if (DEBUG_SERVICE) Log.v( - TAG, "Published intent: " + intent); - continue; - } - if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c); - try { - c.conn.connected(r.name, service); - } catch (Exception e) { - Log.w(TAG, "Failure sending service " + r.name + - " to connection " + c.conn.asBinder() + - " (in " + c.binding.client.processName + ")", e); - } - } - } - } - - serviceDoneExecutingLocked(r, mStoppingServices.contains(r)); - - Binder.restoreCallingIdentity(origId); - } - } - } - - public void unbindFinished(IBinder token, Intent intent, boolean doRebind) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (!(token instanceof ServiceRecord)) { - throw new IllegalArgumentException("Invalid service token"); - } - ServiceRecord r = (ServiceRecord)token; - - final long origId = Binder.clearCallingIdentity(); - - if (r != null) { - Intent.FilterComparison filter - = new Intent.FilterComparison(intent); - IntentBindRecord b = r.bindings.get(filter); - if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r - + " at " + b + ": apps=" - + (b != null ? b.apps.size() : 0)); - if (b != null) { - if (b.apps.size() > 0) { - // Applications have already bound since the last - // unbind, so just rebind right here. - requestServiceBindingLocked(r, b, true); - } else { - // Note to tell the service the next time there is - // a new client. - b.doRebind = true; - } - } - - serviceDoneExecutingLocked(r, mStoppingServices.contains(r)); - - Binder.restoreCallingIdentity(origId); - } - } - } - - public void serviceDoneExecuting(IBinder token) { - synchronized(this) { - if (!(token instanceof ServiceRecord)) { - throw new IllegalArgumentException("Invalid service token"); - } - ServiceRecord r = (ServiceRecord)token; - boolean inStopping = mStoppingServices.contains(token); - if (r != null) { - if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name - + ": nesting=" + r.executeNesting - + ", inStopping=" + inStopping); - if (r != token) { - Log.w(TAG, "Done executing service " + r.name - + " with incorrect token: given " + token - + ", expected " + r); - return; - } - - final long origId = Binder.clearCallingIdentity(); - serviceDoneExecutingLocked(r, inStopping); - Binder.restoreCallingIdentity(origId); - } else { - Log.w(TAG, "Done executing unknown service " + r.name - + " with token " + token); - } - } - } - - public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) { - r.executeNesting--; - if (r.executeNesting <= 0 && r.app != null) { - r.app.executingServices.remove(r); - if (r.app.executingServices.size() == 0) { - mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); - } - if (inStopping) { - mStoppingServices.remove(r); - } - updateOomAdjLocked(r.app); - } - } - - void serviceTimeout(ProcessRecord proc) { - synchronized(this) { - if (proc.executingServices.size() == 0 || proc.thread == null) { - return; - } - long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT; - Iterator<ServiceRecord> it = proc.executingServices.iterator(); - ServiceRecord timeout = null; - long nextTime = 0; - while (it.hasNext()) { - ServiceRecord sr = it.next(); - if (sr.executingStart < maxTime) { - timeout = sr; - break; - } - if (sr.executingStart > nextTime) { - nextTime = sr.executingStart; - } - } - if (timeout != null && mLRUProcesses.contains(proc)) { - Log.w(TAG, "Timeout executing service: " + timeout); - appNotRespondingLocked(proc, null, "Executing service " - + timeout.name); - } else { - Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG); - msg.obj = proc; - mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT); - } - } - } - - // ========================================================= - // BROADCASTS - // ========================================================= - - private final List getStickies(String action, IntentFilter filter, - List cur) { - final ContentResolver resolver = mContext.getContentResolver(); - final ArrayList<Intent> list = mStickyBroadcasts.get(action); - if (list == null) { - return cur; - } - int N = list.size(); - for (int i=0; i<N; i++) { - Intent intent = list.get(i); - if (filter.match(resolver, intent, true, TAG) >= 0) { - if (cur == null) { - cur = new ArrayList<Intent>(); - } - cur.add(intent); - } - } - return cur; - } - - private final void scheduleBroadcastsLocked() { - if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current=" - + mBroadcastsScheduled); - - if (mBroadcastsScheduled) { - return; - } - mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG); - mBroadcastsScheduled = true; - } - - public Intent registerReceiver(IApplicationThread caller, - IIntentReceiver receiver, IntentFilter filter, String permission) { - synchronized(this) { - ProcessRecord callerApp = null; - if (caller != null) { - callerApp = getRecordForAppLocked(caller); - if (callerApp == null) { - throw new SecurityException( - "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() - + ") when registering receiver " + receiver); - } - } - - List allSticky = null; - - // Look for any matching sticky broadcasts... - Iterator actions = filter.actionsIterator(); - if (actions != null) { - while (actions.hasNext()) { - String action = (String)actions.next(); - allSticky = getStickies(action, filter, allSticky); - } - } else { - allSticky = getStickies(null, filter, allSticky); - } - - // The first sticky in the list is returned directly back to - // the client. - Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null; - - if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter - + ": " + sticky); - - if (receiver == null) { - return sticky; - } - - ReceiverList rl - = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); - if (rl == null) { - rl = new ReceiverList(this, callerApp, - Binder.getCallingPid(), - Binder.getCallingUid(), receiver); - if (rl.app != null) { - rl.app.receivers.add(rl); - } else { - try { - receiver.asBinder().linkToDeath(rl, 0); - } catch (RemoteException e) { - return sticky; - } - rl.linkedToDeath = true; - } - mRegisteredReceivers.put(receiver.asBinder(), rl); - } - BroadcastFilter bf = new BroadcastFilter(filter, rl, permission); - rl.add(bf); - if (!bf.debugCheck()) { - Log.w(TAG, "==> For Dynamic broadast"); - } - mReceiverResolver.addFilter(bf); - - // Enqueue broadcasts for all existing stickies that match - // this filter. - if (allSticky != null) { - ArrayList receivers = new ArrayList(); - receivers.add(bf); - - int N = allSticky.size(); - for (int i=0; i<N; i++) { - Intent intent = (Intent)allSticky.get(i); - BroadcastRecord r = new BroadcastRecord(intent, null, - null, -1, -1, null, receivers, null, 0, null, null, - false); - if (mParallelBroadcasts.size() == 0) { - scheduleBroadcastsLocked(); - } - mParallelBroadcasts.add(r); - } - } - - return sticky; - } - } - - public void unregisterReceiver(IIntentReceiver receiver) { - if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver); - - boolean doNext = false; - - synchronized(this) { - ReceiverList rl - = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); - if (rl != null) { - if (rl.curBroadcast != null) { - BroadcastRecord r = rl.curBroadcast; - doNext = finishReceiverLocked( - receiver.asBinder(), r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - } - - if (rl.app != null) { - rl.app.receivers.remove(rl); - } - removeReceiverLocked(rl); - if (rl.linkedToDeath) { - rl.linkedToDeath = false; - rl.receiver.asBinder().unlinkToDeath(rl, 0); - } - } - } - - if (!doNext) { - return; - } - - final long origId = Binder.clearCallingIdentity(); - processNextBroadcast(false); - trimApplications(); - Binder.restoreCallingIdentity(origId); - } - - void removeReceiverLocked(ReceiverList rl) { - mRegisteredReceivers.remove(rl.receiver.asBinder()); - int N = rl.size(); - for (int i=0; i<N; i++) { - mReceiverResolver.removeFilter(rl.get(i)); - } - } - - private final int broadcastIntentLocked(ProcessRecord callerApp, - String callerPackage, Intent intent, String resolvedType, - IIntentReceiver resultTo, int resultCode, String resultData, - Bundle map, String requiredPermission, - boolean ordered, boolean sticky, int callingPid, int callingUid) { - intent = new Intent(intent); - - if (DEBUG_BROADCAST) Log.v( - TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent - + " ordered=" + ordered); - if ((resultTo != null) && !ordered) { - Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); - } - - // Handle special intents: if this broadcast is from the package - // manager about a package being removed, we need to remove all of - // its activities from the history stack. - final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals( - intent.getAction()); - if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) - || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) - || uidRemoved) { - if (checkComponentPermission( - android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, - callingPid, callingUid, -1) - == PackageManager.PERMISSION_GRANTED) { - if (uidRemoved) { - final Bundle intentExtras = intent.getExtras(); - final int uid = intentExtras != null - ? intentExtras.getInt(Intent.EXTRA_UID) : -1; - if (uid >= 0) { - BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics(); - synchronized (bs) { - bs.removeUidStatsLocked(uid); - } - } - } else { - Uri data = intent.getData(); - String ssp; - if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { - if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { - uninstallPackageLocked(ssp, - intent.getIntExtra(Intent.EXTRA_UID, -1), false); - } - } - } - } else { - String msg = "Permission Denial: " + intent.getAction() - + " broadcast from " + callerPackage + " (pid=" + callingPid - + ", uid=" + callingUid + ")" - + " requires " - + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - } - - /* - * If this is the time zone changed action, queue up a message that will reset the timezone - * of all currently running processes. This message will get queued up before the broadcast - * happens. - */ - if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { - mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); - } - - // Add to the sticky list if requested. - if (sticky) { - if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, - callingPid, callingUid) - != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid=" - + callingPid + ", uid=" + callingUid - + " requires " + android.Manifest.permission.BROADCAST_STICKY; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - if (requiredPermission != null) { - Log.w(TAG, "Can't broadcast sticky intent " + intent - + " and enforce permission " + requiredPermission); - return BROADCAST_STICKY_CANT_HAVE_PERMISSION; - } - if (intent.getComponent() != null) { - throw new SecurityException( - "Sticky broadcasts can't target a specific component"); - } - ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction()); - if (list == null) { - list = new ArrayList<Intent>(); - mStickyBroadcasts.put(intent.getAction(), list); - } - int N = list.size(); - int i; - for (i=0; i<N; i++) { - if (intent.filterEquals(list.get(i))) { - // This sticky already exists, replace it. - list.set(i, new Intent(intent)); - break; - } - } - if (i >= N) { - list.add(new Intent(intent)); - } - } - - final ContentResolver resolver = mContext.getContentResolver(); - - // Figure out who all will receive this broadcast. - List receivers = null; - List<BroadcastFilter> registeredReceivers = null; - try { - if (intent.getComponent() != null) { - // Broadcast is going to one specific receiver class... - ActivityInfo ai = ActivityThread.getPackageManager(). - getReceiverInfo(intent.getComponent(), 0); - if (ai != null) { - receivers = new ArrayList(); - ResolveInfo ri = new ResolveInfo(); - ri.activityInfo = ai; - receivers.add(ri); - } - } else { - // Need to resolve the intent to interested receivers... - if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) - == 0) { - receivers = - ActivityThread.getPackageManager().queryIntentReceivers( - intent, resolvedType, PackageManager.GET_SHARED_LIBRARY_FILES); - } - registeredReceivers = mReceiverResolver.queryIntent(resolver, - intent, resolvedType, false); - } - } catch (RemoteException ex) { - // pm is in same process, this will never happen. - } - - int NR = registeredReceivers != null ? registeredReceivers.size() : 0; - if (!ordered && NR > 0) { - // If we are not serializing this broadcast, then send the - // registered receivers separately so they don't wait for the - // components to be launched. - BroadcastRecord r = new BroadcastRecord(intent, callerApp, - callerPackage, callingPid, callingUid, requiredPermission, - registeredReceivers, resultTo, resultCode, resultData, map, - ordered); - if (DEBUG_BROADCAST) Log.v( - TAG, "Enqueueing parallel broadcast " + r - + ": prev had " + mParallelBroadcasts.size()); - mParallelBroadcasts.add(r); - scheduleBroadcastsLocked(); - registeredReceivers = null; - NR = 0; - } - - // Merge into one list. - int ir = 0; - if (receivers != null) { - // A special case for PACKAGE_ADDED: do not allow the package - // being added to see this broadcast. This prevents them from - // using this as a back door to get run as soon as they are - // installed. Maybe in the future we want to have a special install - // broadcast or such for apps, but we'd like to deliberately make - // this decision. - String skipPackage = (intent.ACTION_PACKAGE_ADDED.equals( - intent.getAction()) && intent.getData() != null) - ? intent.getData().getSchemeSpecificPart() - : null; - if (skipPackage != null && receivers != null) { - int NT = receivers.size(); - for (int it=0; it<NT; it++) { - ResolveInfo curt = (ResolveInfo)receivers.get(it); - if (curt.activityInfo.packageName.equals(skipPackage)) { - receivers.remove(it); - it--; - NT--; - } - } - } - - int NT = receivers != null ? receivers.size() : 0; - int it = 0; - ResolveInfo curt = null; - BroadcastFilter curr = null; - while (it < NT && ir < NR) { - if (curt == null) { - curt = (ResolveInfo)receivers.get(it); - } - if (curr == null) { - curr = registeredReceivers.get(ir); - } - if (curr.getPriority() >= curt.priority) { - // Insert this broadcast record into the final list. - receivers.add(it, curr); - ir++; - curr = null; - it++; - NT++; - } else { - // Skip to the next ResolveInfo in the final list. - it++; - curt = null; - } - } - } - while (ir < NR) { - if (receivers == null) { - receivers = new ArrayList(); - } - receivers.add(registeredReceivers.get(ir)); - ir++; - } - - if ((receivers != null && receivers.size() > 0) - || resultTo != null) { - BroadcastRecord r = new BroadcastRecord(intent, callerApp, - callerPackage, callingPid, callingUid, requiredPermission, - receivers, resultTo, resultCode, resultData, map, ordered); - if (DEBUG_BROADCAST) Log.v( - TAG, "Enqueueing ordered broadcast " + r - + ": prev had " + mOrderedBroadcasts.size()); - if (DEBUG_BROADCAST) { - int seq = r.intent.getIntExtra("seq", -1); - Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq); - } - mOrderedBroadcasts.add(r); - scheduleBroadcastsLocked(); - } - - return BROADCAST_SUCCESS; - } - - public final int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - 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(); - final long origId = Binder.clearCallingIdentity(); - int res = broadcastIntentLocked(callerApp, - callerApp != null ? callerApp.info.packageName : null, - intent, resolvedType, resultTo, - resultCode, resultData, map, requiredPermission, serialized, - sticky, callingPid, callingUid); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - int broadcastIntentInPackage(String packageName, int uid, - Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky) { - synchronized(this) { - final long origId = Binder.clearCallingIdentity(); - int res = broadcastIntentLocked(null, packageName, intent, resolvedType, - resultTo, resultCode, resultData, map, requiredPermission, - serialized, sticky, -1, uid); - Binder.restoreCallingIdentity(origId); - return res; - } - } - - public final void unbroadcastIntent(IApplicationThread caller, - Intent intent) { - // Refuse possible leaked file descriptors - if (intent != null && intent.hasFileDescriptors() == true) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY) - != PackageManager.PERMISSION_GRANTED) { - String msg = "Permission Denial: unbroadcastIntent() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " requires " + android.Manifest.permission.BROADCAST_STICKY; - Log.w(TAG, msg); - throw new SecurityException(msg); - } - ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction()); - if (list != null) { - int N = list.size(); - int i; - for (i=0; i<N; i++) { - if (intent.filterEquals(list.get(i))) { - list.remove(i); - break; - } - } - } - } - } - - private final boolean finishReceiverLocked(IBinder receiver, int resultCode, - String resultData, Bundle resultExtras, boolean resultAbort, - boolean explicit) { - if (mOrderedBroadcasts.size() == 0) { - if (explicit) { - Log.w(TAG, "finishReceiver called but no pending broadcasts"); - } - return false; - } - BroadcastRecord r = mOrderedBroadcasts.get(0); - if (r.receiver == null) { - if (explicit) { - Log.w(TAG, "finishReceiver called but none active"); - } - return false; - } - if (r.receiver != receiver) { - Log.w(TAG, "finishReceiver called but active receiver is different"); - return false; - } - int state = r.state; - r.state = r.IDLE; - if (state == r.IDLE) { - if (explicit) { - Log.w(TAG, "finishReceiver called but state is IDLE"); - } - } - r.receiver = null; - r.intent.setComponent(null); - if (r.curApp != null) { - r.curApp.curReceiver = null; - } - if (r.curFilter != null) { - r.curFilter.receiverList.curBroadcast = null; - } - r.curFilter = null; - r.curApp = null; - r.curComponent = null; - r.curReceiver = null; - mPendingBroadcast = null; - - r.resultCode = resultCode; - r.resultData = resultData; - r.resultExtras = resultExtras; - r.resultAbort = resultAbort; - - // We will process the next receiver right now if this is finishing - // an app receiver (which is always asynchronous) or after we have - // come back from calling a receiver. - return state == BroadcastRecord.APP_RECEIVE - || state == BroadcastRecord.CALL_DONE_RECEIVE; - } - - public void finishReceiver(IBinder who, int resultCode, String resultData, - Bundle resultExtras, boolean resultAbort) { - if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who); - - // Refuse possible leaked file descriptors - if (resultExtras != null && resultExtras.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Bundle"); - } - - boolean doNext; - - final long origId = Binder.clearCallingIdentity(); - - synchronized(this) { - doNext = finishReceiverLocked( - who, resultCode, resultData, resultExtras, resultAbort, true); - } - - if (doNext) { - processNextBroadcast(false); - } - trimApplications(); - - Binder.restoreCallingIdentity(origId); - } - - private final void logBroadcastReceiverDiscard(BroadcastRecord r) { - if (r.nextReceiver > 0) { - Object curReceiver = r.receivers.get(r.nextReceiver-1); - if (curReceiver instanceof BroadcastFilter) { - BroadcastFilter bf = (BroadcastFilter) curReceiver; - EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER, - System.identityHashCode(r), - r.intent.getAction(), - r.nextReceiver - 1, - System.identityHashCode(bf)); - } else { - EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP, - System.identityHashCode(r), - r.intent.getAction(), - r.nextReceiver - 1, - ((ResolveInfo)curReceiver).toString()); - } - } else { - Log.w(TAG, "Discarding broadcast before first receiver is invoked: " - + r); - EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP, - System.identityHashCode(r), - r.intent.getAction(), - r.nextReceiver, - "NONE"); - } - } - - private final void broadcastTimeout() { - synchronized (this) { - if (mOrderedBroadcasts.size() == 0) { - return; - } - long now = SystemClock.uptimeMillis(); - BroadcastRecord r = mOrderedBroadcasts.get(0); - if ((r.startTime+BROADCAST_TIMEOUT) > now) { - if (DEBUG_BROADCAST) Log.v(TAG, - "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for " - + (r.startTime + BROADCAST_TIMEOUT)); - Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); - mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT); - return; - } - - Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver); - r.startTime = now; - r.anrCount++; - - // Current receiver has passed its expiration date. - if (r.nextReceiver <= 0) { - Log.w(TAG, "Timeout on receiver with nextReceiver <= 0"); - return; - } - - ProcessRecord app = null; - - Object curReceiver = r.receivers.get(r.nextReceiver-1); - Log.w(TAG, "Receiver during timeout: " + curReceiver); - logBroadcastReceiverDiscard(r); - if (curReceiver instanceof BroadcastFilter) { - BroadcastFilter bf = (BroadcastFilter)curReceiver; - if (bf.receiverList.pid != 0 - && bf.receiverList.pid != MY_PID) { - synchronized (this.mPidsSelfLocked) { - app = this.mPidsSelfLocked.get( - bf.receiverList.pid); - } - } - } else { - app = r.curApp; - } - - if (app != null) { - appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString()); - } - - if (mPendingBroadcast == r) { - mPendingBroadcast = null; - } - - // Move on to the next receiver. - finishReceiverLocked(r.receiver, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - scheduleBroadcastsLocked(); - } - } - - private final void processCurBroadcastLocked(BroadcastRecord r, - ProcessRecord app) throws RemoteException { - if (app.thread == null) { - throw new RemoteException(); - } - r.receiver = app.thread.asBinder(); - r.curApp = app; - app.curReceiver = r; - updateLRUListLocked(app, true); - - // Tell the application to launch this receiver. - r.intent.setComponent(r.curComponent); - - boolean started = false; - try { - if (DEBUG_BROADCAST) Log.v(TAG, - "Delivering to component " + r.curComponent - + ": " + r); - app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, - r.resultCode, r.resultData, r.resultExtras, r.ordered); - started = true; - } finally { - if (!started) { - r.receiver = null; - r.curApp = null; - app.curReceiver = null; - } - } - - } - - static void performReceive(ProcessRecord app, IIntentReceiver receiver, - Intent intent, int resultCode, String data, - Bundle extras, boolean ordered) throws RemoteException { - if (app != null && app.thread != null) { - // If we have an app thread, do the call through that so it is - // correctly ordered with other one-way calls. - app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, - data, extras, ordered); - } else { - receiver.performReceive(intent, resultCode, data, extras, ordered); - } - } - - private final void deliverToRegisteredReceiver(BroadcastRecord r, - BroadcastFilter filter, boolean ordered) { - boolean skip = false; - if (filter.requiredPermission != null) { - int perm = checkComponentPermission(filter.requiredPermission, - r.callingPid, r.callingUid, -1); - if (perm != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: broadcasting " - + r.intent.toString() - + " from " + r.callerPackage + " (pid=" - + r.callingPid + ", uid=" + r.callingUid + ")" - + " requires " + filter.requiredPermission - + " due to registered receiver " + filter); - skip = true; - } - } - if (r.requiredPermission != null) { - int perm = checkComponentPermission(r.requiredPermission, - filter.receiverList.pid, filter.receiverList.uid, -1); - if (perm != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: receiving " - + r.intent.toString() - + " to " + filter.receiverList.app - + " (pid=" + filter.receiverList.pid - + ", uid=" + filter.receiverList.uid + ")" - + " requires " + r.requiredPermission - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - } - - if (!skip) { - // If this is not being sent as an ordered broadcast, then we - // don't want to touch the fields that keep track of the current - // state of ordered broadcasts. - if (ordered) { - r.receiver = filter.receiverList.receiver.asBinder(); - r.curFilter = filter; - filter.receiverList.curBroadcast = r; - r.state = BroadcastRecord.CALL_IN_RECEIVE; - } - try { - if (DEBUG_BROADCAST) { - int seq = r.intent.getIntExtra("seq", -1); - Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq - + " app=" + filter.receiverList.app); - } - performReceive(filter.receiverList.app, filter.receiverList.receiver, - new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, r.ordered); - if (ordered) { - r.state = BroadcastRecord.CALL_DONE_RECEIVE; - } - } catch (RemoteException e) { - Log.w(TAG, "Failure sending broadcast " + r.intent, e); - if (ordered) { - r.receiver = null; - r.curFilter = null; - filter.receiverList.curBroadcast = null; - } - } - } - } - - private final void processNextBroadcast(boolean fromMsg) { - synchronized(this) { - BroadcastRecord r; - - if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: " - + mParallelBroadcasts.size() + " broadcasts, " - + mOrderedBroadcasts.size() + " serialized broadcasts"); - - updateCpuStats(); - - if (fromMsg) { - mBroadcastsScheduled = false; - } - - // First, deliver any non-serialized broadcasts right away. - while (mParallelBroadcasts.size() > 0) { - r = mParallelBroadcasts.remove(0); - final int N = r.receivers.size(); - for (int i=0; i<N; i++) { - Object target = r.receivers.get(i); - if (DEBUG_BROADCAST) Log.v(TAG, - "Delivering non-serialized to registered " - + target + ": " + r); - deliverToRegisteredReceiver(r, (BroadcastFilter)target, false); - } - } - - // Now take care of the next serialized one... - - // If we are waiting for a process to come up to handle the next - // broadcast, then do nothing at this point. Just in case, we - // check that the process we're waiting for still exists. - if (mPendingBroadcast != null) { - Log.i(TAG, "processNextBroadcast: waiting for " - + mPendingBroadcast.curApp); - - boolean isDead; - synchronized (mPidsSelfLocked) { - isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null); - } - if (!isDead) { - // It's still alive, so keep waiting - return; - } else { - Log.w(TAG, "pending app " + mPendingBroadcast.curApp - + " died before responding to broadcast"); - mPendingBroadcast = null; - } - } - - do { - if (mOrderedBroadcasts.size() == 0) { - // No more broadcasts pending, so all done! - scheduleAppGcsLocked(); - return; - } - r = mOrderedBroadcasts.get(0); - boolean forceReceive = false; - - // Ensure that even if something goes awry with the timeout - // detection, we catch "hung" broadcasts here, discard them, - // and continue to make progress. - int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; - long now = SystemClock.uptimeMillis(); - if (r.dispatchTime > 0) { - if ((numReceivers > 0) && - (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) { - Log.w(TAG, "Hung broadcast discarded after timeout failure:" - + " now=" + now - + " dispatchTime=" + r.dispatchTime - + " startTime=" + r.startTime - + " intent=" + r.intent - + " numReceivers=" + numReceivers - + " nextReceiver=" + r.nextReceiver - + " state=" + r.state); - broadcastTimeout(); // forcibly finish this broadcast - forceReceive = true; - r.state = BroadcastRecord.IDLE; - } - } - - if (r.state != BroadcastRecord.IDLE) { - if (DEBUG_BROADCAST) Log.d(TAG, - "processNextBroadcast() called when not idle (state=" - + r.state + ")"); - return; - } - - if (r.receivers == null || r.nextReceiver >= numReceivers - || r.resultAbort || forceReceive) { - // No more receivers for this broadcast! Send the final - // result if requested... - if (r.resultTo != null) { - try { - if (DEBUG_BROADCAST) { - int seq = r.intent.getIntExtra("seq", -1); - Log.i(TAG, "Finishing broadcast " + r.intent.getAction() - + " seq=" + seq + " app=" + r.callerApp); - } - performReceive(r.callerApp, r.resultTo, - new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false); - } catch (RemoteException e) { - Log.w(TAG, "Failure sending broadcast result of " + r.intent, e); - } - } - - if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG"); - mHandler.removeMessages(BROADCAST_TIMEOUT_MSG); - - // ... and on to the next... - mOrderedBroadcasts.remove(0); - r = null; - continue; - } - } while (r == null); - - // Get the next receiver... - int recIdx = r.nextReceiver++; - - // Keep track of when this receiver started, and make sure there - // is a timeout message pending to kill it if need be. - r.startTime = SystemClock.uptimeMillis(); - if (recIdx == 0) { - r.dispatchTime = r.startTime; - - if (DEBUG_BROADCAST) Log.v(TAG, - "Submitting BROADCAST_TIMEOUT_MSG for " - + (r.startTime + BROADCAST_TIMEOUT)); - Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); - mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT); - } - - Object nextReceiver = r.receivers.get(recIdx); - if (nextReceiver instanceof BroadcastFilter) { - // Simple case: this is a registered receiver who gets - // a direct call. - BroadcastFilter filter = (BroadcastFilter)nextReceiver; - if (DEBUG_BROADCAST) Log.v(TAG, - "Delivering serialized to registered " - + filter + ": " + r); - deliverToRegisteredReceiver(r, filter, r.ordered); - if (r.receiver == null || !r.ordered) { - // The receiver has already finished, so schedule to - // process the next one. - r.state = BroadcastRecord.IDLE; - scheduleBroadcastsLocked(); - } - return; - } - - // Hard case: need to instantiate the receiver, possibly - // starting its application process to host it. - - ResolveInfo info = - (ResolveInfo)nextReceiver; - - boolean skip = false; - int perm = checkComponentPermission(info.activityInfo.permission, - r.callingPid, r.callingUid, - info.activityInfo.exported - ? -1 : info.activityInfo.applicationInfo.uid); - if (perm != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: broadcasting " - + r.intent.toString() - + " from " + r.callerPackage + " (pid=" + r.callingPid - + ", uid=" + r.callingUid + ")" - + " requires " + info.activityInfo.permission - + " due to receiver " + info.activityInfo.packageName - + "/" + info.activityInfo.name); - skip = true; - } - if (r.callingUid != Process.SYSTEM_UID && - r.requiredPermission != null) { - try { - perm = ActivityThread.getPackageManager(). - checkPermission(r.requiredPermission, - info.activityInfo.applicationInfo.packageName); - } catch (RemoteException e) { - perm = PackageManager.PERMISSION_DENIED; - } - if (perm != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "Permission Denial: receiving " - + r.intent + " to " - + info.activityInfo.applicationInfo.packageName - + " requires " + r.requiredPermission - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - } - if (r.curApp != null && r.curApp.crashing) { - // If the target process is crashing, just skip it. - skip = true; - } - - if (skip) { - r.receiver = null; - r.curFilter = null; - r.state = BroadcastRecord.IDLE; - scheduleBroadcastsLocked(); - return; - } - - r.state = BroadcastRecord.APP_RECEIVE; - String targetProcess = info.activityInfo.processName; - r.curComponent = new ComponentName( - info.activityInfo.applicationInfo.packageName, - info.activityInfo.name); - r.curReceiver = info.activityInfo; - - // Is this receiver's application already running? - ProcessRecord app = getProcessRecordLocked(targetProcess, - info.activityInfo.applicationInfo.uid); - if (app != null && app.thread != null) { - try { - processCurBroadcastLocked(r, app); - return; - } catch (RemoteException e) { - Log.w(TAG, "Exception when sending broadcast to " - + r.curComponent, e); - } - - // If a dead object exception was thrown -- fall through to - // restart the application. - } - - // Not running -- get it started, and enqueue this history record - // to be executed when the app comes up. - if ((r.curApp=startProcessLocked(targetProcess, - info.activityInfo.applicationInfo, true, - r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - "broadcast", r.curComponent)) == null) { - // Ah, this recipient is unavailable. Finish it if necessary, - // and mark the broadcast record as ready for the next. - Log.w(TAG, "Unable to launch app " - + info.activityInfo.applicationInfo.packageName + "/" - + info.activityInfo.applicationInfo.uid + " for broadcast " - + r.intent + ": process is bad"); - logBroadcastReceiverDiscard(r); - finishReceiverLocked(r.receiver, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); - scheduleBroadcastsLocked(); - r.state = BroadcastRecord.IDLE; - return; - } - - mPendingBroadcast = r; - } - } - - // ========================================================= - // INSTRUMENTATION - // ========================================================= - - public boolean startInstrumentation(ComponentName className, - String profileFile, int flags, Bundle arguments, - IInstrumentationWatcher watcher) { - // Refuse possible leaked file descriptors - if (arguments != null && arguments.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Bundle"); - } - - synchronized(this) { - InstrumentationInfo ii = null; - ApplicationInfo ai = null; - try { - ii = mContext.getPackageManager().getInstrumentationInfo( - className, 0); - ai = mContext.getPackageManager().getApplicationInfo( - ii.targetPackage, PackageManager.GET_SHARED_LIBRARY_FILES); - } catch (PackageManager.NameNotFoundException e) { - } - if (ii == null) { - reportStartInstrumentationFailure(watcher, className, - "Unable to find instrumentation info for: " + className); - return false; - } - if (ai == null) { - reportStartInstrumentationFailure(watcher, className, - "Unable to find instrumentation target package: " + ii.targetPackage); - return false; - } - - int match = mContext.getPackageManager().checkSignatures( - ii.targetPackage, ii.packageName); - if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) { - String msg = "Permission Denial: starting instrumentation " - + className + " from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingPid() - + " not allowed because package " + ii.packageName - + " does not have a signature matching the target " - + ii.targetPackage; - reportStartInstrumentationFailure(watcher, className, msg); - throw new SecurityException(msg); - } - - final long origId = Binder.clearCallingIdentity(); - uninstallPackageLocked(ii.targetPackage, -1, true); - ProcessRecord app = addAppLocked(ai); - app.instrumentationClass = className; - app.instrumentationProfileFile = profileFile; - app.instrumentationArguments = arguments; - app.instrumentationWatcher = watcher; - app.instrumentationResultClass = className; - Binder.restoreCallingIdentity(origId); - } - - return true; - } - - /** - * Report errors that occur while attempting to start Instrumentation. Always writes the - * error to the logs, but if somebody is watching, send the report there too. This enables - * the "am" command to report errors with more information. - * - * @param watcher The IInstrumentationWatcher. Null if there isn't one. - * @param cn The component name of the instrumentation. - * @param report The error report. - */ - private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher, - ComponentName cn, String report) { - Log.w(TAG, report); - try { - if (watcher != null) { - Bundle results = new Bundle(); - results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService"); - results.putString("Error", report); - watcher.instrumentationStatus(cn, -1, results); - } - } catch (RemoteException e) { - Log.w(TAG, e); - } - } - - void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) { - if (app.instrumentationWatcher != null) { - try { - // NOTE: IInstrumentationWatcher *must* be oneway here - app.instrumentationWatcher.instrumentationFinished( - app.instrumentationClass, - resultCode, - results); - } catch (RemoteException e) { - } - } - app.instrumentationWatcher = null; - app.instrumentationClass = null; - app.instrumentationProfileFile = null; - app.instrumentationArguments = null; - - uninstallPackageLocked(app.processName, -1, false); - } - - public void finishInstrumentation(IApplicationThread target, - int resultCode, Bundle results) { - // Refuse possible leaked file descriptors - if (results != null && results.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - - synchronized(this) { - ProcessRecord app = getRecordForAppLocked(target); - if (app == null) { - Log.w(TAG, "finishInstrumentation: no app for " + target); - return; - } - final long origId = Binder.clearCallingIdentity(); - finishInstrumentationLocked(app, resultCode, results); - Binder.restoreCallingIdentity(origId); - } - } - - // ========================================================= - // 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; - synchronized(this) { - ci = new Configuration(mConfiguration); - } - return ci; - } - - public void updateConfiguration(Configuration values) { - enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, - "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); - } - } - - /** - * Do either or both things: (1) change the current configuration, and (2) - * make sure the given activity is running with the (now) current - * configuration. Returns true if the activity has been left running, or - * false if <var>starting</var> is being destroyed to match the new - * configuration. - */ - public boolean updateConfigurationLocked(Configuration values, - HistoryRecord starting) { - int changes = 0; - - boolean kept = true; - - if (values != null) { - Configuration newConfig = new Configuration(mConfiguration); - changes = newConfig.updateFrom(values); - if (changes != 0) { - if (DEBUG_SWITCH) { - Log.i(TAG, "Updating configuration to: " + values); - } - - EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes); - - if (values.locale != null) { - saveLocaleLocked(values.locale, - !values.locale.equals(mConfiguration.locale), - values.userSetLocale); - } - - mConfiguration = newConfig; - - Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG); - msg.obj = new Configuration(mConfiguration); - mHandler.sendMessage(msg); - - final int N = mLRUProcesses.size(); - for (int i=0; i<N; i++) { - ProcessRecord app = mLRUProcesses.get(i); - try { - if (app.thread != null) { - app.thread.scheduleConfigurationChanged(mConfiguration); - } - } catch (Exception e) { - } - } - Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED); - broadcastIntentLocked(null, null, intent, null, null, 0, null, null, - null, false, false, MY_PID, Process.SYSTEM_UID); - } - } - - if (changes != 0 && starting == null) { - // If the configuration changed, and the caller is not already - // in the process of starting an activity, then find the top - // activity to check if its configuration needs to change. - starting = topRunningActivityLocked(null); - } - - if (starting != null) { - kept = ensureActivityConfigurationLocked(starting); - if (kept) { - // If this didn't result in the starting activity being - // destroyed, then we need to make sure at this point that all - // other activities are made visible. - if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting - + ", ensuring others are correct."); - ensureActivitiesVisibleLocked(starting, changes); - } - } - - return kept; - } - - private final boolean relaunchActivityLocked(HistoryRecord r, - int changes, boolean andResume) { - List<ResultInfo> results = null; - List<Intent> newIntents = null; - if (andResume) { - results = r.results; - newIntents = r.newIntents; - } - if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r - + " with results=" + results + " newIntents=" + newIntents - + " andResume=" + andResume); - EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY - : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r), - r.task.taskId, r.shortComponentName); - - r.startFreezingScreenLocked(r.app, 0); - - try { - if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r); - r.app.thread.scheduleRelaunchActivity(r, results, newIntents, - changes, !andResume); - // Note: don't need to call pauseIfSleepingLocked() here, because - // the caller will only pass in 'andResume' if this activity is - // currently resumed, which implies we aren't sleeping. - } catch (RemoteException e) { - return false; - } - - if (andResume) { - r.results = null; - r.newIntents = null; - } - - return true; - } - - /** - * Make sure the given activity matches the current configuration. Returns - * false if the activity had to be destroyed. Returns true if the - * configuration is the same, or the activity will remain running as-is - * for whatever reason. Ensures the HistoryRecord is updated with the - * correct configuration and all other bookkeeping is handled. - */ - private final boolean ensureActivityConfigurationLocked(HistoryRecord r) { - if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r); - - // Short circuit: if the two configurations are the exact same - // object (the common case), then there is nothing to do. - Configuration newConfig = mConfiguration; - if (r.configuration == newConfig) { - if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r); - return true; - } - - // We don't worry about activities that are finishing. - if (r.finishing) { - if (DEBUG_SWITCH) Log.i(TAG, - "Configuration doesn't matter in finishing " + r); - r.stopFreezingScreenLocked(false); - return true; - } - - // Okay we now are going to make this activity have the new config. - // But then we need to figure out how it needs to deal with that. - Configuration oldConfig = r.configuration; - r.configuration = newConfig; - - // If the activity isn't currently running, just leave the new - // configuration and it will pick that up next time it starts. - if (r.app == null || r.app.thread == null) { - if (DEBUG_SWITCH) Log.i(TAG, - "Configuration doesn't matter not running " + r); - r.stopFreezingScreenLocked(false); - return true; - } - - // If the activity isn't persistent, there is a chance we will - // need to restart it. - if (!r.persistent) { - - // Figure out what has changed between the two configurations. - int changes = oldConfig.diff(newConfig); - if (DEBUG_SWITCH) { - Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x" - + Integer.toHexString(changes) + ", handles=0x" - + Integer.toHexString(r.info.configChanges)); - } - if ((changes&(~r.info.configChanges)) != 0) { - // Aha, the activity isn't handling the change, so DIE DIE DIE. - r.configChangeFlags |= changes; - r.startFreezingScreenLocked(r.app, changes); - if (r.app == null || r.app.thread == null) { - if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r); - destroyActivityLocked(r, true); - } else if (r.state == ActivityState.PAUSING) { - // A little annoying: we are waiting for this activity to - // finish pausing. Let's not do anything now, but just - // flag that it needs to be restarted when done pausing. - r.configDestroy = true; - return true; - } else if (r.state == ActivityState.RESUMED) { - // Try to optimize this case: the configuration is changing - // and we need to restart the top, resumed activity. - // Instead of doing the normal handshaking, just say - // "restart!". - if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r); - relaunchActivityLocked(r, r.configChangeFlags, true); - r.configChangeFlags = 0; - } else { - if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r); - relaunchActivityLocked(r, r.configChangeFlags, false); - r.configChangeFlags = 0; - } - - // All done... tell the caller we weren't able to keep this - // activity around. - return false; - } - } - - // Default case: the activity can handle this new configuration, so - // hand it over. Note that we don't need to give it the new - // configuration, since we always send configuration changes to all - // process when they happen so it can just use whatever configuration - // it last got. - if (r.app != null && r.app.thread != null) { - try { - r.app.thread.scheduleActivityConfigurationChanged(r); - } catch (RemoteException e) { - // If process died, whatever. - } - } - r.stopFreezingScreenLocked(false); - - return true; - } - - /** - * Save the locale. You must be inside a synchronized (this) block. - */ - private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) { - if(isDiff) { - SystemProperties.set("user.language", l.getLanguage()); - SystemProperties.set("user.region", l.getCountry()); - } - - if(isPersist) { - SystemProperties.set("persist.sys.language", l.getLanguage()); - SystemProperties.set("persist.sys.country", l.getCountry()); - SystemProperties.set("persist.sys.localevar", l.getVariant()); - } - } - - // ========================================================= - // LIFETIME MANAGEMENT - // ========================================================= - - private final int computeOomAdjLocked( - ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) { - if (mAdjSeq == app.adjSeq) { - // This adjustment has already been computed. - return app.curAdj; - } - - if (app.thread == null) { - app.adjSeq = mAdjSeq; - return (app.curAdj=EMPTY_APP_ADJ); - } - - app.isForeground = false; - - // Right now there are three interesting states: it is - // either the foreground app, background with activities, - // or background without activities. - int adj; - int N; - if (app == TOP_APP || app.instrumentationClass != null - || app.persistentActivities > 0) { - // The last app on the list is the foreground app. - adj = FOREGROUND_APP_ADJ; - app.isForeground = true; - } else if (app.curReceiver != null || - (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) { - // An app that is currently receiving a broadcast also - // counts as being in the foreground. - adj = FOREGROUND_APP_ADJ; - } else if (app.executingServices.size() > 0) { - // An app that is currently executing a service callback also - // counts as being in the foreground. - adj = FOREGROUND_APP_ADJ; - } else if (app.foregroundServices || app.forcingToForeground != null) { - // The user is aware of this app, so make it visible. - adj = VISIBLE_APP_ADJ; - } else if ((N=app.activities.size()) != 0) { - // This app is in the background with paused activities. - adj = hiddenAdj; - for (int j=0; j<N; j++) { - if (((HistoryRecord)app.activities.get(j)).visible) { - // This app has a visible activity! - adj = VISIBLE_APP_ADJ; - break; - } - } - } else { - // A very not-needed process. - adj = EMPTY_APP_ADJ; - } - - // By default, we use the computed adjusted. It may be changed if - // there are applications dependent on our services or providers, but - // this gives us a baseline and makes sure we don't get into an - // infinite recursion. - app.adjSeq = mAdjSeq; - app.curRawAdj = adj; - app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj; - - if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) { - // If this process has active services running in it, we would - // like to avoid killing it unless it would prevent the current - // application from running. - if (adj > hiddenAdj) { - adj = hiddenAdj; - } - final long now = SystemClock.uptimeMillis(); - // This process is more important if the top activity is - // bound to the service. - Iterator jt = app.services.iterator(); - while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) { - ServiceRecord s = (ServiceRecord)jt.next(); - if (s.startRequested) { - if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { - // This service has seen some activity within - // recent memory, so we will keep its process ahead - // of the background processes. - if (adj > SECONDARY_SERVER_ADJ) { - adj = SECONDARY_SERVER_ADJ; - } - } else { - // This service has been inactive for too long, just - // put it with the rest of the background processes. - if (adj > hiddenAdj) { - adj = hiddenAdj; - } - } - } - if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) { - Iterator<ConnectionRecord> kt - = s.connections.values().iterator(); - while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) { - // XXX should compute this based on the max of - // all connected clients. - ConnectionRecord cr = kt.next(); - if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { - ProcessRecord client = cr.binding.client; - int myHiddenAdj = hiddenAdj; - if (myHiddenAdj > client.hiddenAdj) { - if (client.hiddenAdj > VISIBLE_APP_ADJ) { - myHiddenAdj = client.hiddenAdj; - } else { - myHiddenAdj = VISIBLE_APP_ADJ; - } - } - int clientAdj = computeOomAdjLocked( - client, myHiddenAdj, TOP_APP); - if (adj > clientAdj) { - adj = clientAdj > VISIBLE_APP_ADJ - ? clientAdj : VISIBLE_APP_ADJ; - } - } - HistoryRecord a = cr.activity; - //if (a != null) { - // Log.i(TAG, "Connection to " + a ": state=" + a.state); - //} - if (a != null && adj > FOREGROUND_APP_ADJ && - (a.state == ActivityState.RESUMED - || a.state == ActivityState.PAUSING)) { - adj = FOREGROUND_APP_ADJ; - } - } - } - } - } - - if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) { - // If this process has published any content providers, then - // its adjustment makes it at least as important as any of the - // processes using those providers, and no less important than - // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY. - if (adj > CONTENT_PROVIDER_ADJ) { - adj = CONTENT_PROVIDER_ADJ; - } - Iterator jt = app.pubProviders.values().iterator(); - while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) { - ContentProviderRecord cpr = (ContentProviderRecord)jt.next(); - if (cpr.clients.size() != 0) { - Iterator<ProcessRecord> kt = cpr.clients.iterator(); - while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) { - ProcessRecord client = kt.next(); - int myHiddenAdj = hiddenAdj; - if (myHiddenAdj > client.hiddenAdj) { - if (client.hiddenAdj > FOREGROUND_APP_ADJ) { - myHiddenAdj = client.hiddenAdj; - } else { - myHiddenAdj = FOREGROUND_APP_ADJ; - } - } - int clientAdj = computeOomAdjLocked( - client, myHiddenAdj, TOP_APP); - if (adj > clientAdj) { - adj = clientAdj > FOREGROUND_APP_ADJ - ? clientAdj : FOREGROUND_APP_ADJ; - } - } - } - // If the provider has external (non-framework) process - // dependencies, ensure that its adjustment is at least - // FOREGROUND_APP_ADJ. - if (cpr.externals != 0) { - if (adj > FOREGROUND_APP_ADJ) { - adj = FOREGROUND_APP_ADJ; - } - } - } - } - - app.curRawAdj = adj; - - //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid + - // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj); - if (adj > app.maxAdj) { - adj = app.maxAdj; - } - - app.curAdj = adj; - - return adj; - } - - /** - * Ask a given process to GC right now. - */ - final void performAppGcLocked(ProcessRecord app) { - try { - app.lastRequestedGc = SystemClock.uptimeMillis(); - if (app.thread != null) { - app.thread.processInBackground(); - } - } catch (Exception e) { - // whatever. - } - } - - /** - * Returns true if things are idle enough to perform GCs. - */ - private final boolean canGcNow() { - return mParallelBroadcasts.size() == 0 - && mOrderedBroadcasts.size() == 0 - && (mSleeping || (mResumedActivity != null && - mResumedActivity.idle)); - } - - /** - * Perform GCs on all processes that are waiting for it, but only - * if things are idle. - */ - final void performAppGcsLocked() { - final int N = mProcessesToGc.size(); - if (N <= 0) { - return; - } - if (canGcNow()) { - while (mProcessesToGc.size() > 0) { - ProcessRecord proc = mProcessesToGc.remove(0); - if (proc.curRawAdj > VISIBLE_APP_ADJ) { - // To avoid spamming the system, we will GC processes one - // at a time, waiting a few seconds between each. - performAppGcLocked(proc); - scheduleAppGcsLocked(); - return; - } - } - } - } - - /** - * If all looks good, perform GCs on all processes waiting for them. - */ - final void performAppGcsIfAppropriateLocked() { - if (canGcNow()) { - performAppGcsLocked(); - return; - } - // Still not idle, wait some more. - scheduleAppGcsLocked(); - } - - /** - * Schedule the execution of all pending app GCs. - */ - final void scheduleAppGcsLocked() { - mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG); - Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG); - mHandler.sendMessageDelayed(msg, GC_TIMEOUT); - } - - /** - * Set up to ask a process to GC itself. This will either do it - * immediately, or put it on the list of processes to gc the next - * time things are idle. - */ - final void scheduleAppGcLocked(ProcessRecord app) { - long now = SystemClock.uptimeMillis(); - if ((app.lastRequestedGc+5000) > now) { - return; - } - if (!mProcessesToGc.contains(app)) { - mProcessesToGc.add(app); - scheduleAppGcsLocked(); - } - } - - private final boolean updateOomAdjLocked( - ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) { - app.hiddenAdj = hiddenAdj; - - if (app.thread == null) { - return true; - } - - int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP); - - //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName); - //Thread priority adjustment is disabled out to see - //how the kernel scheduler performs. - if (false) { - if (app.pid != 0 && app.isForeground != app.setIsForeground) { - app.setIsForeground = app.isForeground; - if (app.pid != MY_PID) { - if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app - + " to " + (app.isForeground - ? Process.THREAD_PRIORITY_FOREGROUND - : Process.THREAD_PRIORITY_DEFAULT)); - try { - Process.setThreadPriority(app.pid, app.isForeground - ? Process.THREAD_PRIORITY_FOREGROUND - : Process.THREAD_PRIORITY_DEFAULT); - } catch (RuntimeException e) { - Log.w(TAG, "Exception trying to set priority of application thread " - + app.pid, e); - } - } - } - } - if (app.pid != 0 && app.pid != MY_PID) { - if (app.curRawAdj != app.setRawAdj) { - if (app.curRawAdj > FOREGROUND_APP_ADJ - && app.setRawAdj <= FOREGROUND_APP_ADJ) { - // If this app is transitioning from foreground to - // non-foreground, have it do a gc. - scheduleAppGcLocked(app); - } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ - && app.setRawAdj < HIDDEN_APP_MIN_ADJ) { - // Likewise do a gc when an app is moving in to the - // background (such as a service stopping). - scheduleAppGcLocked(app); - } - app.setRawAdj = app.curRawAdj; - } - if (adj != app.setAdj) { - if (Process.setOomAdj(app.pid, adj)) { - if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v( - TAG, "Set app " + app.processName + - " oom adj to " + adj); - app.setAdj = adj; - } else { - return false; - } - } - } - - return true; - } - - private final HistoryRecord resumedAppLocked() { - HistoryRecord resumedActivity = mResumedActivity; - if (resumedActivity == null || resumedActivity.app == null) { - resumedActivity = mPausingActivity; - if (resumedActivity == null || resumedActivity.app == null) { - resumedActivity = topRunningActivityLocked(null); - } - } - return resumedActivity; - } - - private final boolean updateOomAdjLocked(ProcessRecord app) { - final HistoryRecord TOP_ACT = resumedAppLocked(); - final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; - int curAdj = app.curAdj; - final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ - && app.curAdj <= HIDDEN_APP_MAX_ADJ; - - mAdjSeq++; - - final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP); - if (res) { - final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ - && app.curAdj <= HIDDEN_APP_MAX_ADJ; - if (nowHidden != wasHidden) { - // Changed to/from hidden state, so apps after it in the LRU - // list may also be changed. - updateOomAdjLocked(); - } - } - return res; - } - - private final boolean updateOomAdjLocked() { - boolean didOomAdj = true; - final HistoryRecord TOP_ACT = resumedAppLocked(); - final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; - - if (false) { - RuntimeException e = new RuntimeException(); - e.fillInStackTrace(); - Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e); - } - - mAdjSeq++; - - // First try updating the OOM adjustment for each of the - // application processes based on their current state. - int i = mLRUProcesses.size(); - int curHiddenAdj = HIDDEN_APP_MIN_ADJ; - while (i > 0) { - i--; - ProcessRecord app = mLRUProcesses.get(i); - if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) { - if (curHiddenAdj < HIDDEN_APP_MAX_ADJ - && app.curAdj == curHiddenAdj) { - curHiddenAdj++; - } - } else { - didOomAdj = false; - } - } - - // todo: for now pretend like OOM ADJ didn't work, because things - // aren't behaving as expected on Linux -- it's not killing processes. - return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj; - } - - private final void trimApplications() { - synchronized (this) { - int i; - - // First remove any unused application processes whose package - // has been removed. - for (i=mRemovedProcesses.size()-1; i>=0; i--) { - final ProcessRecord app = mRemovedProcesses.get(i); - if (app.activities.size() == 0 - && app.curReceiver == null && app.services.size() == 0) { - Log.i( - TAG, "Exiting empty application process " - + app.processName + " (" - + (app.thread != null ? app.thread.asBinder() : null) - + ")\n"); - if (app.pid > 0 && app.pid != MY_PID) { - Process.killProcess(app.pid); - } else { - try { - app.thread.scheduleExit(); - } catch (Exception e) { - // Ignore exceptions. - } - } - cleanUpApplicationRecordLocked(app, false, -1); - mRemovedProcesses.remove(i); - - if (app.persistent) { - if (app.persistent) { - addAppLocked(app.info); - } - } - } - } - - // Now try updating the OOM adjustment for each of the - // application processes based on their current state. - // If the setOomAdj() API is not supported, then go with our - // back-up plan... - if (!updateOomAdjLocked()) { - - // Count how many processes are running services. - int numServiceProcs = 0; - for (i=mLRUProcesses.size()-1; i>=0; i--) { - final ProcessRecord app = mLRUProcesses.get(i); - - if (app.persistent || app.services.size() != 0 - || app.curReceiver != null - || app.persistentActivities > 0) { - // Don't count processes holding services against our - // maximum process count. - if (localLOGV) Log.v( - TAG, "Not trimming app " + app + " with services: " - + app.services); - numServiceProcs++; - } - } - - int curMaxProcs = mProcessLimit; - if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES; - if (mAlwaysFinishActivities) { - curMaxProcs = 1; - } - curMaxProcs += numServiceProcs; - - // Quit as many processes as we can to get down to the desired - // process count. First remove any processes that no longer - // have activites running in them. - for ( i=0; - i<mLRUProcesses.size() - && mLRUProcesses.size() > curMaxProcs; - i++) { - final ProcessRecord app = mLRUProcesses.get(i); - // Quit an application only if it is not currently - // running any activities. - if (!app.persistent && app.activities.size() == 0 - && app.curReceiver == null && app.services.size() == 0) { - Log.i( - TAG, "Exiting empty application process " - + app.processName + " (" - + (app.thread != null ? app.thread.asBinder() : null) - + ")\n"); - if (app.pid > 0 && app.pid != MY_PID) { - Process.killProcess(app.pid); - } else { - try { - app.thread.scheduleExit(); - } catch (Exception e) { - // Ignore exceptions. - } - } - // todo: For now we assume the application is not buggy - // or evil, and will quit as a result of our request. - // Eventually we need to drive this off of the death - // notification, and kill the process if it takes too long. - cleanUpApplicationRecordLocked(app, false, i); - i--; - } - } - - // If we still have too many processes, now from the least - // recently used process we start finishing activities. - if (Config.LOGV) Log.v( - TAG, "*** NOW HAVE " + mLRUProcesses.size() + - " of " + curMaxProcs + " processes"); - for ( i=0; - i<mLRUProcesses.size() - && mLRUProcesses.size() > curMaxProcs; - i++) { - final ProcessRecord app = mLRUProcesses.get(i); - // Quit the application only if we have a state saved for - // all of its activities. - boolean canQuit = !app.persistent && app.curReceiver == null - && app.services.size() == 0 - && app.persistentActivities == 0; - int NUMA = app.activities.size(); - int j; - if (Config.LOGV) Log.v( - TAG, "Looking to quit " + app.processName); - for (j=0; j<NUMA && canQuit; j++) { - HistoryRecord r = (HistoryRecord)app.activities.get(j); - if (Config.LOGV) Log.v( - TAG, " " + r.intent.getComponent().flattenToShortString() - + ": frozen=" + r.haveState + ", visible=" + r.visible); - canQuit = (r.haveState || !r.stateNotNeeded) - && !r.visible && r.stopped; - } - if (canQuit) { - // Finish all of the activities, and then the app itself. - for (j=0; j<NUMA; j++) { - HistoryRecord r = (HistoryRecord)app.activities.get(j); - if (!r.finishing) { - destroyActivityLocked(r, false); - } - r.resultTo = null; - } - Log.i(TAG, "Exiting application process " - + app.processName + " (" - + (app.thread != null ? app.thread.asBinder() : null) - + ")\n"); - if (app.pid > 0 && app.pid != MY_PID) { - Process.killProcess(app.pid); - } else { - try { - app.thread.scheduleExit(); - } catch (Exception e) { - // Ignore exceptions. - } - } - // todo: For now we assume the application is not buggy - // or evil, and will quit as a result of our request. - // Eventually we need to drive this off of the death - // notification, and kill the process if it takes too long. - cleanUpApplicationRecordLocked(app, false, i); - i--; - //dump(); - } - } - - } - - int curMaxActivities = MAX_ACTIVITIES; - if (mAlwaysFinishActivities) { - curMaxActivities = 1; - } - - // Finally, if there are too many activities now running, try to - // finish as many as we can to get back down to the limit. - for ( i=0; - i<mLRUActivities.size() - && mLRUActivities.size() > curMaxActivities; - i++) { - final HistoryRecord r - = (HistoryRecord)mLRUActivities.get(i); - - // We can finish this one if we have its icicle saved and - // it is not persistent. - if ((r.haveState || !r.stateNotNeeded) && !r.visible - && r.stopped && !r.persistent && !r.finishing) { - final int origSize = mLRUActivities.size(); - destroyActivityLocked(r, true); - - // This will remove it from the LRU list, so keep - // our index at the same value. Note that this check to - // see if the size changes is just paranoia -- if - // something unexpected happens, we don't want to end up - // in an infinite loop. - if (origSize > mLRUActivities.size()) { - i--; - } - } - } - } - } - - /** This method sends the specified signal to each of the persistent apps */ - public void signalPersistentProcesses(int sig) throws RemoteException { - if (sig != Process.SIGNAL_USR1) { - throw new SecurityException("Only SIGNAL_USR1 is allowed"); - } - - synchronized (this) { - if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires permission " - + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES); - } - - for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) { - ProcessRecord r = mLRUProcesses.get(i); - if (r.thread != null && r.persistent) { - Process.sendSignal(r.pid, sig); - } - } - } - } - - /** In this method we try to acquire our lock to make sure that we have not deadlocked */ - public void monitor() { - synchronized (this) { } - } -} diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/java/com/android/server/am/ActivityResult.java deleted file mode 100644 index 3cc2725..0000000 --- a/services/java/com/android/server/am/ActivityResult.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.ResultInfo; -import android.content.Intent; -import android.os.Bundle; - -/** - * Pending result information to send back to an activity. - */ -class ActivityResult extends ResultInfo { - final HistoryRecord mFrom; - - public ActivityResult(HistoryRecord from, String resultWho, - int requestCode, int resultCode, Intent data) { - super(resultWho, requestCode, resultCode, data); - mFrom = from; - } -} diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java deleted file mode 100644 index ce6f6dc..0000000 --- a/services/java/com/android/server/am/AppBindRecord.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2006 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 java.io.PrintWriter; -import java.util.HashSet; -import java.util.Iterator; - -/** - * An association between a service and one of its client applications. - */ -class AppBindRecord { - final ServiceRecord service; // The running service. - final IntentBindRecord intent; // The intent we are bound to. - final ProcessRecord client; // Who has started/bound the service. - - final HashSet<ConnectionRecord> connections = new HashSet<ConnectionRecord>(); - // All ConnectionRecord for this client. - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "service=" + service); - pw.println(prefix + "client=" + client); - if (connections.size() > 0) { - pw.println(prefix + "Per-process Connections:"); - Iterator<ConnectionRecord> it = connections.iterator(); - while (it.hasNext()) { - ConnectionRecord c = it.next(); - pw.println(prefix + " " + c); - } - } - } - - AppBindRecord(ServiceRecord _service, IntentBindRecord _intent, - ProcessRecord _client) { - service = _service; - intent = _intent; - client = _client; - } - - public String toString() { - return "AppBindRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + service.shortName + ":" + client.processName + "}"; - } -} diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java deleted file mode 100644 index 3fcfad0..0000000 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2006 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 static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Handler; -import android.os.Message; - -class AppErrorDialog extends BaseErrorDialog { - private final AppErrorResult mResult; - private final ProcessRecord mProc; - - // Event 'what' codes - static final int FORCE_QUIT = 0; - static final int DEBUG = 1; - - // 5-minute timeout, then we automatically dismiss the crash dialog - static final long DISMISS_TIMEOUT = 1000 * 60 * 5; - - public AppErrorDialog(Context context, AppErrorResult result, - ProcessRecord app, int flags, - String shortMsg, String longMsg) { - super(context); - - Resources res = context.getResources(); - - mProc = app; - mResult = result; - CharSequence name; - if ((app.pkgList.size() == 1) && - (name=context.getPackageManager().getApplicationLabel(app.info)) != null) { - setMessage(res.getString( - com.android.internal.R.string.aerr_application, - name.toString(), app.info.processName)); - } else { - name = app.processName; - setMessage(res.getString( - com.android.internal.R.string.aerr_process, - name.toString())); - } - - setCancelable(false); - - setButton(res.getText(com.android.internal.R.string.force_close), - mHandler.obtainMessage(FORCE_QUIT)); - if ((flags&1) != 0) { - setButton(res.getText(com.android.internal.R.string.debug), - mHandler.obtainMessage(DEBUG)); - } - setTitle(res.getText(com.android.internal.R.string.aerr_title)); - getWindow().addFlags(FLAG_SYSTEM_ERROR); - getWindow().setTitle("Application Error: " + app.info.processName); - - // After the timeout, pretend the user clicked the quit button - mHandler.sendMessageDelayed( - mHandler.obtainMessage(FORCE_QUIT), - DISMISS_TIMEOUT); - } - - public void onStop() { - } - - private final Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - synchronized (mProc) { - if (mProc != null && mProc.crashDialog == AppErrorDialog.this) { - mProc.crashDialog = null; - } - } - mResult.set(msg.what); - - // If this is a timeout we won't be automatically closed, so go - // ahead and explicitly dismiss ourselves just in case. - dismiss(); - } - }; -} diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/java/com/android/server/am/AppErrorResult.java deleted file mode 100644 index ebfcfe2..0000000 --- a/services/java/com/android/server/am/AppErrorResult.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2006 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; - - -class AppErrorResult { - public void set(int res) { - synchronized (this) { - mHasResult = true; - mResult = res; - notifyAll(); - } - } - - public int get() { - synchronized (this) { - while (!mHasResult) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - return mResult; - } - - boolean mHasResult = false; - int mResult; -} diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java deleted file mode 100644 index 7390ed0..0000000 --- a/services/java/com/android/server/am/AppNotRespondingDialog.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2006 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 static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Handler; -import android.os.Message; -import android.os.Process; -import android.util.Log; - -class AppNotRespondingDialog extends BaseErrorDialog { - private final ActivityManagerService mService; - private final ProcessRecord mProc; - - public AppNotRespondingDialog(ActivityManagerService service, Context context, - ProcessRecord app, HistoryRecord activity) { - super(context); - - mService = service; - mProc = app; - Resources res = context.getResources(); - - setCancelable(false); - - int resid; - CharSequence name1 = activity != null - ? activity.info.loadLabel(context.getPackageManager()) - : null; - CharSequence name2 = null; - if ((app.pkgList.size() == 1) && - (name2=context.getPackageManager().getApplicationLabel(app.info)) != null) { - if (name1 != null) { - resid = com.android.internal.R.string.anr_activity_application; - } else { - name1 = name2; - name2 = app.processName; - resid = com.android.internal.R.string.anr_application_process; - } - } else { - if (name1 != null) { - name2 = app.processName; - resid = com.android.internal.R.string.anr_activity_process; - } else { - name1 = app.processName; - resid = com.android.internal.R.string.anr_process; - } - } - - setMessage(name2 != null - ? res.getString(resid, name1.toString(), name2.toString()) - : res.getString(resid, name1.toString())); - - setButton(res.getText(com.android.internal.R.string.force_close), - mHandler.obtainMessage(1)); - setButton2(res.getText(com.android.internal.R.string.wait), - mHandler.obtainMessage(2)); - setTitle(res.getText(com.android.internal.R.string.anr_title)); - getWindow().addFlags(FLAG_SYSTEM_ERROR); - getWindow().setTitle("Application Not Responding: " + app.info.processName); - } - - public void onStop() { - } - - private final Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - switch (msg.what) { - case 1: - // Kill the application. - mService.killAppAtUsersRequest(mProc, - AppNotRespondingDialog.this, true); - break; - case 2: - // Continue waiting for the application. - synchronized (mService) { - ProcessRecord app = mProc; - app.notResponding = false; - app.notRespondingReport = null; - if (app.anrDialog == AppNotRespondingDialog.this) { - app.anrDialog = null; - } - } - break; - } - } - }; -} diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java deleted file mode 100644 index 0992d4d..0000000 --- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.Context; -import android.os.Handler; -import android.os.Message; - -class AppWaitingForDebuggerDialog extends BaseErrorDialog { - final ActivityManagerService mService; - final ProcessRecord mProc; - private CharSequence mAppName; - - public AppWaitingForDebuggerDialog(ActivityManagerService service, - Context context, ProcessRecord app) { - super(context); - mService = service; - mProc = app; - mAppName = context.getPackageManager().getApplicationLabel(app.info); - - setCancelable(false); - - StringBuilder text = new StringBuilder(); - if (mAppName != null && mAppName.length() > 0) { - text.append("Application "); - text.append(mAppName); - text.append(" (process "); - text.append(app.processName); - text.append(")"); - } else { - text.append("Process "); - text.append(app.processName); - } - - text.append(" is waiting for the debugger to attach."); - - setMessage(text.toString()); - setButton("Force Close", mHandler.obtainMessage(1, app)); - setTitle("Waiting For Debugger"); - getWindow().setTitle("Waiting For Debugger: " + app.info.processName); - } - - public void onStop() { - } - - private final Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - switch (msg.what) { - case 1: - // Kill the application. - mService.killAppAtUsersRequest(mProc, - AppWaitingForDebuggerDialog.this, true); - break; - } - } - }; -} diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java deleted file mode 100644 index 4f62f62..0000000 --- a/services/java/com/android/server/am/BaseErrorDialog.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2006 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.R; - -import android.app.AlertDialog; -import android.content.Context; -import android.os.Handler; -import android.os.Message; -import android.view.KeyEvent; -import android.view.WindowManager; -import android.widget.Button; - -class BaseErrorDialog extends AlertDialog { - public BaseErrorDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Dialog_AppError); - - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - getWindow().setTitle("Error Dialog"); - setIcon(R.drawable.ic_dialog_alert); - } - - public void onStart() { - super.onStart(); - setEnabled(false); - mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 1000); - } - - public boolean dispatchKeyEvent(KeyEvent event) { - if (mConsuming) { - //Log.i(TAG, "Consuming: " + event); - return true; - } - //Log.i(TAG, "Dispatching: " + event); - return super.dispatchKeyEvent(event); - } - - private void setEnabled(boolean enabled) { - Button b = (Button)findViewById(R.id.button1); - if (b != null) { - b.setEnabled(enabled); - } - b = (Button)findViewById(R.id.button2); - if (b != null) { - b.setEnabled(enabled); - } - } - - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - if (msg.what == 0) { - mConsuming = false; - setEnabled(true); - } - } - }; - - private boolean mConsuming = true; -} diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java deleted file mode 100644 index 9ba1198..0000000 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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.IBatteryStats; -import com.android.internal.os.BatteryStatsImpl; - -import android.content.Context; -import android.os.Binder; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Process; -import android.os.ServiceManager; -import android.util.PrintWriterPrinter; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * All information we are collecting about things that can happen that impact - * battery life. - */ -public final class BatteryStatsService extends IBatteryStats.Stub { - static IBatteryStats sService; - - final BatteryStatsImpl mStats; - Context mContext; - - BatteryStatsService(String filename) { - mStats = new BatteryStatsImpl(filename); - } - - public void publish(Context context) { - mContext = context; - ServiceManager.addService("batteryinfo", asBinder()); - } - - public static IBatteryStats getService() { - if (sService != null) { - return sService; - } - IBinder b = ServiceManager.getService("batteryinfo"); - sService = asInterface(b); - return sService; - } - - /** - * @return the current statistics object, which may be modified - * to reflect events that affect battery usage. You must lock the - * stats object before doing anything with it. - */ - public BatteryStatsImpl getActiveStatistics() { - return mStats; - } - - public byte[] getStatistics() { - mContext.enforceCallingPermission( - android.Manifest.permission.BATTERY_STATS, null); - synchronized (mStats) { - //Log.i("foo", "SENDING BATTERY INFO:"); - //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo")); - Parcel out = Parcel.obtain(); - mStats.writeToParcel(out, 0); - byte[] data = out.marshall(); - out.recycle(); - return data; - } - } - - public void noteStartWakelock(int uid, String name, int type) { - enforceCallingPermission(); - synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type); - } - } - - public void noteStopWakelock(int uid, String name, int type) { - enforceCallingPermission(); - synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type); - } - } - - public void noteStartSensor(int uid, int sensor) { - enforceCallingPermission(); - synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStartSensor(sensor); - } - } - - public void noteStopSensor(int uid, int sensor) { - enforceCallingPermission(); - synchronized (mStats) { - mStats.getUidStatsLocked(uid).noteStopSensor(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 noteScreenOn() { - enforceCallingPermission(); - synchronized (mStats) { - mStats.noteScreenOnLocked(); - } - } - - public void noteScreenOff() { - enforceCallingPermission(); - synchronized (mStats) { - mStats.noteScreenOffLocked(); - } - } - - public boolean isOnBattery() { - return mStats.isOnBattery(); - } - - public void setOnBattery(boolean onBattery) { - enforceCallingPermission(); - mStats.setOnBattery(onBattery); - } - - 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(); - } - - public void enforceCallingPermission() { - if (Binder.getCallingPid() == Process.myPid()) { - return; - } - mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, - Binder.getCallingPid(), Binder.getCallingUid(), null); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - synchronized (mStats) { - boolean isCheckin = false; - if (args != null) { - for (String arg : args) { - if ("-c".equals(arg)) { - isCheckin = true; - break; - } - } - } - if (isCheckin) mStats.dumpCheckinLocked(pw, args); - else mStats.dumpLocked(new PrintWriterPrinter(pw)); - } - } -} diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java deleted file mode 100644 index cd7f720..0000000 --- a/services/java/com/android/server/am/BroadcastFilter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.IntentFilter; -import android.util.PrintWriterPrinter; - -import java.io.PrintWriter; - -class BroadcastFilter extends IntentFilter { - // Back-pointer to the list this filter is in. - final ReceiverList receiverList; - final String requiredPermission; - - BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, - String _requiredPermission) { - super(_filter); - receiverList = _receiverList; - requiredPermission = _requiredPermission; - } - - public void dumpLocal(PrintWriter pw, String prefix) { - super.dump(new PrintWriterPrinter(pw), prefix); - } - - public void dump(PrintWriter pw, String prefix) { - dumpLocal(pw, prefix); - pw.println(prefix + "requiredPermission=" + requiredPermission); - receiverList.dumpLocal(pw, prefix); - } - - public String toString() { - return "BroadcastFilter{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + receiverList + "}"; - } -} diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java deleted file mode 100644 index 4057ae8..0000000 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IIntentReceiver; -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.SystemClock; -import android.util.PrintWriterPrinter; - -import java.io.PrintWriter; -import java.util.List; - -/** - * An active intent broadcast. - */ -class BroadcastRecord extends Binder { - final Intent intent; // the original intent that generated us - final ProcessRecord callerApp; // process that sent this - final String callerPackage; // who sent this - final int callingPid; // the pid of who sent this - final int callingUid; // the uid of who sent this - String requiredPermission; // a permission the caller has required - final List receivers; // contains BroadcastFilter and ResolveInfo - final IIntentReceiver resultTo; // who receives final result if non-null - long dispatchTime; // when dispatch started on this set of receivers - long startTime; // when current receiver started for timeouts. - int resultCode; // current result code value. - String resultData; // current result data value. - Bundle resultExtras; // current result extra data values. - boolean resultAbort; // current result abortBroadcast value. - boolean ordered; // serialize the send to receivers? - int nextReceiver; // next receiver to be executed. - IBinder receiver; // who is currently running, null if none. - int state; - int anrCount; // has this broadcast record hit any ANRs? - - static final int IDLE = 0; - static final int APP_RECEIVE = 1; - static final int CALL_IN_RECEIVE = 2; - static final int CALL_DONE_RECEIVE = 3; - - // The following are set when we are calling a receiver (one that - // was found in our list of registered receivers). - BroadcastFilter curFilter; - - // The following are set only when we are launching a receiver (one - // that was found by querying the package manager). - ProcessRecord curApp; // hosting application of current receiver. - ComponentName curComponent; // the receiver class that is currently running. - ActivityInfo curReceiver; // info about the receiver that is currently running. - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + intent); - pw.println(prefix + "proc=" + callerApp); - pw.println(prefix + "caller=" + callerPackage - + " callingPid=" + callingPid - + " callingUid=" + callingUid); - pw.println(prefix + "requiredPermission=" + requiredPermission); - pw.println(prefix + "dispatchTime=" + dispatchTime + " (" - + (SystemClock.uptimeMillis()-dispatchTime) + " since now)"); - pw.println(prefix + "startTime=" + startTime + " (" - + (SystemClock.uptimeMillis()-startTime) + " since now)"); - pw.println(prefix + "anrCount=" + anrCount); - pw.println(prefix + "resultTo=" + resultTo - + " resultCode=" + resultCode + " resultData=" + resultData); - pw.println(prefix + "resultExtras=" + resultExtras); - pw.println(prefix + "resultAbort=" + resultAbort - + " ordered=" + ordered); - pw.println(prefix + "nextReceiver=" + nextReceiver - + " receiver=" + receiver); - pw.println(prefix + "curFilter=" + curFilter); - pw.println(prefix + "curReceiver=" - + ((curReceiver != null) ? curReceiver : "(null)")); - pw.println(prefix + "curApp=" + curApp); - if (curApp != null) { - pw.println(prefix + "curComponent=" - + (curComponent != null ? curComponent.toShortString() : "--")); - pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir); - } - String stateStr = " (?)"; - switch (state) { - case IDLE: stateStr=" (IDLE)"; break; - case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break; - case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break; - case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break; - } - pw.println(prefix + "state=" + state + stateStr); - final int N = receivers != null ? receivers.size() : 0; - String p2 = prefix + " "; - PrintWriterPrinter printer = new PrintWriterPrinter(pw); - for (int i=0; i<N; i++) { - Object o = receivers.get(i); - pw.println(prefix + "Receiver #" + i + ": " + o); - if (o instanceof BroadcastFilter) - ((BroadcastFilter)o).dump(pw, p2); - else if (o instanceof ResolveInfo) - ((ResolveInfo)o).dump(printer, p2); - } - } - - BroadcastRecord(Intent _intent, ProcessRecord _callerApp, String _callerPackage, - int _callingPid, int _callingUid, String _requiredPermission, - List _receivers, IIntentReceiver _resultTo, int _resultCode, - String _resultData, Bundle _resultExtras, boolean _serialized) { - intent = _intent; - callerApp = _callerApp; - callerPackage = _callerPackage; - callingPid = _callingPid; - callingUid = _callingUid; - requiredPermission = _requiredPermission; - receivers = _receivers; - resultTo = _resultTo; - resultCode = _resultCode; - resultData = _resultData; - resultExtras = _resultExtras; - ordered = _serialized; - nextReceiver = 0; - state = IDLE; - } - - public String toString() { - return "BroadcastRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + intent.getAction() + "}"; - } -} diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java deleted file mode 100644 index 41a783f..0000000 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IServiceConnection; - -import java.io.PrintWriter; - -/** - * Description of a single binding to a service. - */ -class ConnectionRecord { - final AppBindRecord binding; // The application/service binding. - final HistoryRecord activity; // If non-null, the owning activity. - final IServiceConnection conn; // The client connection. - final int flags; // Binding options. - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "binding=" + binding); - pw.println(prefix + "activity=" + activity); - pw.println(prefix + "conn=" + conn.asBinder() - + " flags=0x" + Integer.toHexString(flags)); - } - - ConnectionRecord(AppBindRecord _binding, HistoryRecord _activity, - IServiceConnection _conn, int _flags) { - binding = _binding; - activity = _activity; - conn = _conn; - flags = _flags; - } - - public String toString() { - return "ConnectionRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + binding.service.shortName - + ":@" + Integer.toHexString(System.identityHashCode(conn.asBinder())) + "}"; - } -} diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java deleted file mode 100644 index 9f37c14..0000000 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IActivityManager.ContentProviderHolder; -import android.content.pm.ApplicationInfo; -import android.content.pm.ProviderInfo; -import android.os.Process; - -import java.io.PrintWriter; -import java.util.HashSet; - -class ContentProviderRecord extends ContentProviderHolder { - // All attached clients - final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); - final int uid; - final ApplicationInfo appInfo; - int externals; // number of non-framework processes supported by this provider - ProcessRecord app; // if non-null, hosting application - ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. - - public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai) { - super(_info); - uid = ai.uid; - appInfo = ai; - noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID; - } - - public ContentProviderRecord(ContentProviderRecord cpr) { - super(cpr.info); - uid = cpr.uid; - appInfo = cpr.appInfo; - noReleaseNeeded = cpr.noReleaseNeeded; - } - - public boolean canRunHere(ProcessRecord app) { - return (info.multiprocess || info.processName.equals(app.processName)) - && (uid == Process.SYSTEM_UID || uid == app.info.uid); - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "package=" + info.applicationInfo.packageName - + " process=" + info.processName); - pw.println(prefix + "app=" + app); - pw.println(prefix + "launchingApp=" + launchingApp); - pw.println(prefix + "provider=" + provider); - pw.println(prefix + "name=" + info.authority); - pw.println(prefix + "isSyncable=" + info.isSyncable); - pw.println(prefix + "multiprocess=" + info.multiprocess - + " initOrder=" + info.initOrder - + " uid=" + uid); - pw.println(prefix + "clients=" + clients); - pw.println(prefix + "externals=" + externals); - } - - public String toString() { - return "ContentProviderRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + info.name + "}"; - } -} diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java deleted file mode 100644 index ce07430..0000000 --- a/services/java/com/android/server/am/DeviceMonitor.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.am; - -import android.util.Log; - -import java.io.*; -import java.util.Arrays; - -/** - * Monitors device resources periodically for some period of time. Useful for - * tracking down performance problems. - */ -class DeviceMonitor { - - private static final String LOG_TAG = DeviceMonitor.class.getName(); - - /** Number of samples to take. */ - private static final int SAMPLE_COUNT = 10; - - /** Time to wait in ms between samples. */ - private static final int INTERVAL = 1000; - - /** Time to wait in ms between samples. */ - private static final int MAX_FILES = 30; - - private final byte[] buffer = new byte[1024]; - - /** Is the monitor currently running? */ - private boolean running = false; - - private DeviceMonitor() { - new Thread() { - public void run() { - monitor(); - } - }.start(); - } - - /** - * Loops continuously. Pauses until someone tells us to start monitoring. - */ - @SuppressWarnings("InfiniteLoopStatement") - private void monitor() { - while (true) { - waitForStart(); - - purge(); - - for (int i = 0; i < SAMPLE_COUNT; i++) { - try { - dump(); - } catch (IOException e) { - Log.w(LOG_TAG, "Dump failed.", e); - } - pause(); - } - - stop(); - } - } - - private static final File PROC = new File("/proc"); - private static final File BASE = new File("/data/anr/"); - static { - if (!BASE.isDirectory() && !BASE.mkdirs()) { - throw new AssertionError("Couldn't create " + BASE + "."); - } - } - - private static final File[] PATHS = { - new File(PROC, "zoneinfo"), - new File(PROC, "interrupts"), - new File(PROC, "meminfo"), - new File(PROC, "slabinfo"), - }; - - - /** - * Deletes old files. - */ - private void purge() { - File[] files = BASE.listFiles(); - int count = files.length - MAX_FILES; - if (count > 0) { - Arrays.sort(files); - for (int i = 0; i < count; i++) { - if (!files[i].delete()) { - Log.w(LOG_TAG, "Couldn't delete " + files[i] + "."); - } - } - } - } - - /** - * Dumps the current device stats to a new file. - */ - private void dump() throws IOException { - OutputStream out = new FileOutputStream( - new File(BASE, String.valueOf(System.currentTimeMillis()))); - try { - // Copy /proc/*/stat - for (File processDirectory : PROC.listFiles()) { - if (isProcessDirectory(processDirectory)) { - dump(new File(processDirectory, "stat"), out); - } - } - - // Copy other files. - for (File file : PATHS) { - dump(file, out); - } - } finally { - closeQuietly(out); - } - } - - /** - * Returns true if the given file represents a process directory. - */ - private static boolean isProcessDirectory(File file) { - try { - Integer.parseInt(file.getName()); - return file.isDirectory(); - } catch (NumberFormatException e) { - return false; - } - } - - /** - * Copies from a file to an output stream. - */ - private void dump(File from, OutputStream out) throws IOException { - writeHeader(from, out); - - FileInputStream in = null; - try { - in = new FileInputStream(from); - int count; - while ((count = in.read(buffer)) != -1) { - out.write(buffer, 0, count); - } - } finally { - closeQuietly(in); - } - } - - /** - * Writes a header for the given file. - */ - private static void writeHeader(File file, OutputStream out) - throws IOException { - String header = "*** " + file.toString() + "\n"; - out.write(header.getBytes()); - } - - /** - * Closes the given resource. Logs exceptions. - * @param closeable - */ - private static void closeQuietly(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (IOException e) { - Log.w(LOG_TAG, e); - } - } - - /** - * Pauses momentarily before we start the next dump. - */ - private void pause() { - try { - Thread.sleep(INTERVAL); - } catch (InterruptedException e) { /* ignore */ } - } - - /** - * Stops dumping. - */ - private synchronized void stop() { - running = false; - } - - /** - * Waits until someone starts us. - */ - private synchronized void waitForStart() { - while (!running) { - try { - wait(); - } catch (InterruptedException e) { /* ignore */ } - } - } - - /** - * Instructs the monitoring to start if it hasn't already. - */ - private synchronized void startMonitoring() { - if (!running) { - running = true; - notifyAll(); - } - } - - private static DeviceMonitor instance = new DeviceMonitor(); - - /** - * Starts monitoring if it hasn't started already. - */ - static void start() { - instance.startMonitoring(); - } -} diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java deleted file mode 100644 index 2e25474..0000000 --- a/services/java/com/android/server/am/FactoryErrorDialog.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.Context; -import android.os.Handler; -import android.os.Message; - -class FactoryErrorDialog extends BaseErrorDialog { - public FactoryErrorDialog(Context context, CharSequence msg) { - super(context); - setCancelable(false); - setTitle(context.getText(com.android.internal.R.string.factorytest_failed)); - setMessage(msg); - setButton(context.getText(com.android.internal.R.string.factorytest_reboot), - mHandler.obtainMessage(0)); - getWindow().setTitle("Factory Error"); - } - - public void onStop() { - } - - private final Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - throw new RuntimeException("Rebooting from failed factory test"); - } - }; -} diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java deleted file mode 100644 index b407208..0000000 --- a/services/java/com/android/server/am/HistoryRecord.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2006 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.server.AttributeCache; -import com.android.server.am.ActivityManagerService.ActivityState; - -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; -import android.os.Message; -import android.os.Process; -import android.os.SystemClock; -import android.util.EventLog; -import android.util.Log; -import android.view.IApplicationToken; - -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashSet; - -/** - * An entry in the history stack, representing an activity. - */ -class HistoryRecord extends IApplicationToken.Stub { - final ActivityManagerService service; // owner - final ActivityInfo info; // all about me - final int launchedFromUid; // always the uid who started the activity. - final Intent intent; // the original intent that generated us - final ComponentName realActivity; // the intent component, or target of an alias. - final String shortComponentName; // the short component name of the intent - final String resolvedType; // as per original caller; - final String packageName; // the package implementing intent's component - final String processName; // process where this component wants to run - final String taskAffinity; // as per ActivityInfo.taskAffinity - final boolean stateNotNeeded; // As per ActivityInfo.flags - final boolean fullscreen; // covers the full screen? - final String baseDir; // where activity source (resources etc) located - final String resDir; // where public activity source (public resources etc) located - final String dataDir; // where activity data should go - CharSequence nonLocalizedLabel; // the label information from the package mgr. - int labelRes; // the label information from the package mgr. - int icon; // resource identifier of activity's icon. - int theme; // resource identifier of activity's theme. - TaskRecord task; // the task this is in. - long startTime; // when we starting launching this activity - Configuration configuration; // configuration activity was last running in - HistoryRecord resultTo; // who started this entry, so will get our reply - final String resultWho; // additional identifier for use by resultTo. - final int requestCode; // code given by requester (resultTo) - ArrayList results; // pending ActivityResult objs we have received - HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act - ArrayList newIntents; // any pending new intents for single-top mode - HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold - HashSet<UriPermission> readUriPermissions; // special access to reading uris. - HashSet<UriPermission> writeUriPermissions; // special access to writing uris. - ProcessRecord app; // if non-null, hosting application - Bitmap thumbnail; // icon representation of paused screen - CharSequence description; // textual description of paused screen - ActivityManagerService.ActivityState state; // current state we are in - Bundle icicle; // last saved activity state - boolean frontOfTask; // is this the root activity of its task? - boolean launchFailed; // set if a launched failed, to abort on 2nd try - boolean haveState; // have we gotten the last activity state? - boolean stopped; // is activity pause finished? - boolean finishing; // activity in pending finish list? - boolean configDestroy; // need to destroy due to config change? - int configChangeFlags; // which config values have changed - boolean keysPaused; // has key dispatching been paused for it? - boolean inHistory; // are we in the history stack? - boolean persistent; // requested to be persistent? - int launchMode; // the launch mode activity attribute. - boolean visible; // does this activity's window need to be shown? - boolean waitingVisible; // true if waiting for a new act to become vis - boolean nowVisible; // is this activity's window visible? - boolean thumbnailNeeded;// has someone requested a thumbnail? - boolean idle; // has the activity gone idle? - boolean hasBeenLaunched;// has this activity ever been launched? - boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "packageName=" + packageName - + " processName=" + processName); - pw.println(prefix + "app=" + app); - pw.println(prefix + "launchedFromUid=" + launchedFromUid); - pw.println(prefix + intent); - pw.println(prefix + "frontOfTask=" + frontOfTask + " task=" + task); - pw.println(prefix + "taskAffinity=" + taskAffinity); - pw.println(prefix + "realActivity=" + realActivity); - pw.println(prefix + "dir=" + baseDir + " res=" + resDir + " data=" + dataDir); - pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) - + " icon=0x" + Integer.toHexString(icon) - + " theme=0x" + Integer.toHexString(theme)); - pw.println(prefix + "configuration=" + configuration); - pw.println(prefix + "resultTo=" + resultTo - + " resultWho=" + resultWho + " resultCode=" + requestCode); - pw.println(prefix + "results=" + results); - pw.println(prefix + "pendingResults=" + pendingResults); - pw.println(prefix + "readUriPermissions=" + readUriPermissions); - pw.println(prefix + "writeUriPermissions=" + writeUriPermissions); - pw.println(prefix + "launchFailed=" + launchFailed - + " haveState=" + haveState + " icicle=" + icicle); - pw.println(prefix + "state=" + state - + " stopped=" + stopped + " finishing=" + finishing); - pw.println(prefix + "keysPaused=" + keysPaused - + " inHistory=" + inHistory + " persistent=" + persistent - + " launchMode=" + launchMode); - pw.println(prefix + "fullscreen=" + fullscreen - + " visible=" + visible - + " frozenBeforeDestroy=" + frozenBeforeDestroy - + " thumbnailNeeded=" + thumbnailNeeded + " idle=" + idle); - pw.println(prefix + "waitingVisible=" + waitingVisible - + " nowVisible=" + nowVisible); - pw.println(prefix + "configDestroy=" + configDestroy - + " configChangeFlags=" + Integer.toHexString(configChangeFlags)); - pw.println(prefix + "connections=" + connections); - } - - HistoryRecord(ActivityManagerService _service, ProcessRecord _caller, - int _launchedFromUid, Intent _intent, String _resolvedType, - ActivityInfo aInfo, Configuration _configuration, - HistoryRecord _resultTo, String _resultWho, int _reqCode) { - service = _service; - info = aInfo; - launchedFromUid = _launchedFromUid; - intent = _intent; - shortComponentName = _intent.getComponent().flattenToShortString(); - resolvedType = _resolvedType; - configuration = _configuration; - resultTo = _resultTo; - resultWho = _resultWho; - requestCode = _reqCode; - state = ActivityManagerService.ActivityState.INITIALIZING; - frontOfTask = false; - launchFailed = false; - haveState = false; - stopped = false; - finishing = false; - configDestroy = false; - keysPaused = false; - inHistory = false; - persistent = false; - visible = true; - waitingVisible = false; - nowVisible = false; - thumbnailNeeded = false; - idle = false; - hasBeenLaunched = false; - - if (aInfo != null) { - if (aInfo.targetActivity == null - || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE - || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { - realActivity = _intent.getComponent(); - } else { - realActivity = new ComponentName(aInfo.packageName, - aInfo.targetActivity); - } - taskAffinity = aInfo.taskAffinity; - stateNotNeeded = (aInfo.flags& - ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0; - baseDir = aInfo.applicationInfo.sourceDir; - resDir = aInfo.applicationInfo.publicSourceDir; - 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 - && _caller != null - && (aInfo.applicationInfo.uid == Process.SYSTEM_UID - || aInfo.applicationInfo.uid == _caller.info.uid)) { - processName = _caller.processName; - } else { - processName = aInfo.processName; - } - - if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) { - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } - - packageName = aInfo.applicationInfo.packageName; - launchMode = aInfo.launchMode; - - AttributeCache.Entry ent = AttributeCache.instance().get(packageName, - theme != 0 ? theme : android.R.style.Theme, - com.android.internal.R.styleable.Window); - fullscreen = ent != null && !ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsFloating, false) - && !ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsTranslucent, false); - - } else { - realActivity = null; - taskAffinity = null; - stateNotNeeded = false; - baseDir = null; - resDir = null; - dataDir = null; - processName = null; - packageName = null; - fullscreen = true; - } - } - - void addResultLocked(HistoryRecord from, String resultWho, - int requestCode, int resultCode, - Intent resultData) { - ActivityResult r = new ActivityResult(from, resultWho, - requestCode, resultCode, resultData); - if (results == null) { - results = new ArrayList(); - } - results.add(r); - } - - void removeResultsLocked(HistoryRecord from, String resultWho, - int requestCode) { - if (results != null) { - for (int i=results.size()-1; i>=0; i--) { - ActivityResult r = (ActivityResult)results.get(i); - if (r.mFrom != from) continue; - if (r.mResultWho == null) { - if (resultWho != null) continue; - } else { - if (!r.mResultWho.equals(resultWho)) continue; - } - if (r.mRequestCode != requestCode) continue; - - results.remove(i); - } - } - } - - void addNewIntentLocked(Intent intent) { - if (newIntents == null) { - newIntents = new ArrayList(); - } - newIntents.add(intent); - } - - void pauseKeyDispatchingLocked() { - if (!keysPaused) { - keysPaused = true; - service.mWindowManager.pauseKeyDispatching(this); - } - } - - void resumeKeyDispatchingLocked() { - if (keysPaused) { - keysPaused = false; - service.mWindowManager.resumeKeyDispatching(this); - } - } - - // IApplicationToken - - public boolean mayFreezeScreenLocked(ProcessRecord app) { - // Only freeze the screen if this activity is currently attached to - // an application, and that application is not blocked or unresponding. - // In any other case, we can't count on getting the screen unfrozen, - // so it is best to leave as-is. - return app == null || (!app.crashing && !app.notResponding); - } - - public void startFreezingScreenLocked(ProcessRecord app, int configChanges) { - if (mayFreezeScreenLocked(app)) { - service.mWindowManager.startAppFreezingScreen(this, configChanges); - } - } - - public void stopFreezingScreenLocked(boolean force) { - if (force || frozenBeforeDestroy) { - frozenBeforeDestroy = false; - service.mWindowManager.stopAppFreezingScreen(this, force); - } - } - - public void windowsVisible() { - synchronized(service) { - if (ActivityManagerService.SHOW_ACTIVITY_START_TIME - && startTime != 0) { - long time = SystemClock.uptimeMillis() - startTime; - EventLog.writeEvent(ActivityManagerService.LOG_ACTIVITY_LAUNCH_TIME, - System.identityHashCode(this), shortComponentName, time); - Log.i(ActivityManagerService.TAG, "Displayed activity " - + shortComponentName - + ": " + time + " ms"); - startTime = 0; - } - if (ActivityManagerService.DEBUG_SWITCH) Log.v( - ActivityManagerService.TAG, "windowsVisible(): " + this); - if (!nowVisible) { - nowVisible = true; - if (!idle) { - // Instead of doing the full stop routine here, let's just - // hide any activities we now can, and let them stop when - // the normal idle happens. - service.processStoppingActivitiesLocked(false); - } else { - // If this activity was already idle, then we now need to - // make sure we perform the full stop of any activities - // that are waiting to do so. This is because we won't - // do that while they are still waiting for this one to - // become visible. - final int N = service.mWaitingVisibleActivities.size(); - if (N > 0) { - for (int i=0; i<N; i++) { - HistoryRecord r = (HistoryRecord) - service.mWaitingVisibleActivities.get(i); - r.waitingVisible = false; - if (ActivityManagerService.DEBUG_SWITCH) Log.v( - ActivityManagerService.TAG, - "Was waiting for visible: " + r); - } - service.mWaitingVisibleActivities.clear(); - Message msg = Message.obtain(); - msg.what = ActivityManagerService.IDLE_NOW_MSG; - service.mHandler.sendMessage(msg); - } - } - service.scheduleAppGcsLocked(); - } - } - } - - public void windowsGone() { - if (ActivityManagerService.DEBUG_SWITCH) Log.v( - ActivityManagerService.TAG, "windowsGone(): " + this); - nowVisible = false; - } - - private HistoryRecord getWaitingHistoryRecordLocked() { - // First find the real culprit... if we are waiting - // for another app to start, then we have paused dispatching - // for this activity. - HistoryRecord r = this; - if (r.waitingVisible) { - // Hmmm, who might we be waiting for? - r = service.mResumedActivity; - if (r == null) { - r = service.mPausingActivity; - } - // Both of those null? Fall back to 'this' again - if (r == null) { - r = this; - } - } - - return r; - } - - public boolean keyDispatchingTimedOut() { - synchronized(service) { - HistoryRecord r = getWaitingHistoryRecordLocked(); - if (r != null && r.app != null) { - if (r.app.debugging) { - return false; - } - - if (r.app.instrumentationClass == null) { - service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut"); - } else { - Bundle info = new Bundle(); - info.putString("shortMsg", "keyDispatchingTimedOut"); - info.putString("longMsg", "Timed out while dispatching key event"); - service.finishInstrumentationLocked( - r.app, Activity.RESULT_CANCELED, info); - } - } - return true; - } - } - - /** Returns the key dispatching timeout for this application token. */ - public long getKeyDispatchingTimeout() { - synchronized(service) { - HistoryRecord r = getWaitingHistoryRecordLocked(); - if (r == null || r.app == null - || r.app.instrumentationClass == null) { - return ActivityManagerService.KEY_DISPATCHING_TIMEOUT; - } - - return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT; - } - } - - /** - * This method will return true if the activity is either visible, is becoming visible, is - * currently pausing, or is resumed. - */ - public boolean isInterestingToUserLocked() { - return visible || nowVisible || state == ActivityState.PAUSING || - state == ActivityState.RESUMED; - } - - - public String toString() { - return "HistoryRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + intent.getComponent().toShortString() + "}"; - } -} diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java deleted file mode 100644 index 24c3943..0000000 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.Intent; -import android.os.IBinder; - -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Iterator; - -/** - * A particular Intent that has been bound to a Service. - */ -class IntentBindRecord { - /** The running service. */ - final ServiceRecord service; - /** The intent that is bound.*/ - final Intent.FilterComparison intent; // - /** All apps that have bound to this Intent. */ - final HashMap<ProcessRecord, AppBindRecord> apps - = new HashMap<ProcessRecord, AppBindRecord>(); - /** Binder published from service. */ - IBinder binder; - /** Set when we have initiated a request for this binder. */ - boolean requested; - /** Set when we have received the requested binder. */ - boolean received; - /** Set when we still need to tell the service all clients are unbound. */ - boolean hasBound; - /** Set when the service's onUnbind() has asked to be told about new clients. */ - boolean doRebind; - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "service=" + service); - pw.println(prefix + "intent=" + intent.getIntent()); - pw.println(prefix + "binder=" + binder - + " requested=" + requested - + " received=" + received - + " hasBound=" + hasBound - + " doRebind=" + doRebind); - if (apps.size() > 0) { - pw.println(prefix + "Application Bindings:"); - Iterator<AppBindRecord> it = apps.values().iterator(); - while (it.hasNext()) { - AppBindRecord a = it.next(); - pw.println(prefix + "Client " + a.client); - a.dump(pw, prefix + " "); - } - } - } - - IntentBindRecord(ServiceRecord _service, Intent.FilterComparison _intent) { - service = _service; - intent = _intent; - } - - public String toString() { - return "IntentBindRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + service.name.toShortString() - + ":" + intent + "}"; - } -} diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java deleted file mode 100644 index b18aaf7..0000000 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IActivityManager; -import android.app.IIntentSender; -import android.app.IIntentReceiver; -import android.app.PendingIntent; -import android.content.Intent; -import android.os.Binder; -import android.os.RemoteException; -import android.util.Log; - -import java.io.PrintWriter; -import java.lang.ref.WeakReference; - -class PendingIntentRecord extends IIntentSender.Stub { - final ActivityManagerService owner; - final Key key; - final int uid; - final WeakReference<PendingIntentRecord> ref; - boolean sent = false; - boolean canceled = false; - - final static class Key { - final int type; - final String packageName; - final HistoryRecord activity; - final String who; - final int requestCode; - final Intent requestIntent; - final String requestResolvedType; - final int flags; - final int hashCode; - - private static final int ODD_PRIME_NUMBER = 37; - - Key(int _t, String _p, HistoryRecord _a, String _w, - int _r, Intent _i, String _it, int _f) { - type = _t; - packageName = _p; - activity = _a; - who = _w; - requestCode = _r; - requestIntent = _i; - requestResolvedType = _it; - flags = _f; - - int hash = 23; - hash = (ODD_PRIME_NUMBER*hash) + _f; - hash = (ODD_PRIME_NUMBER*hash) + _r; - if (_w != null) { - hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); - } - if (_a != null) { - hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); - } - if (_i != null) { - hash = (ODD_PRIME_NUMBER*hash) + _i.filterHashCode(); - } - if (_it != null) { - hash = (ODD_PRIME_NUMBER*hash) + _it.hashCode(); - } - hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode(); - hash = (ODD_PRIME_NUMBER*hash) + _t; - hashCode = hash; - //Log.i(ActivityManagerService.TAG, this + " hashCode=0x" - // + Integer.toHexString(hashCode)); - } - - public boolean equals(Object otherObj) { - if (otherObj == null) { - return false; - } - try { - Key other = (Key)otherObj; - if (type != other.type) { - return false; - } - if (!packageName.equals(other.packageName)) { - return false; - } - if (activity != other.activity) { - return false; - } - if (who != other.who) { - if (who != null) { - if (!who.equals(other.who)) { - return false; - } - } else if (other.who != null) { - return false; - } - } - if (requestCode != other.requestCode) { - return false; - } - if (requestIntent != other.requestIntent) { - if (requestIntent != null) { - if (!requestIntent.filterEquals(other.requestIntent)) { - return false; - } - } else if (other.requestIntent != null) { - return false; - } - } - if (requestResolvedType != other.requestResolvedType) { - if (requestResolvedType != null) { - if (!requestResolvedType.equals(other.requestResolvedType)) { - return false; - } - } else if (other.requestResolvedType != null) { - return false; - } - } - if (flags != other.flags) { - return false; - } - return true; - } catch (ClassCastException e) { - } - return false; - } - - public int hashCode() { - return hashCode; - } - - public String toString() { - return "Key{" + typeName() + " pkg=" + packageName - + " intent=" + requestIntent + " flags=0x" - + Integer.toHexString(flags) + "}"; - } - - String typeName() { - switch (type) { - case IActivityManager.INTENT_SENDER_ACTIVITY: - return "startActivity"; - case IActivityManager.INTENT_SENDER_BROADCAST: - return "broadcastIntent"; - case IActivityManager.INTENT_SENDER_SERVICE: - return "startService"; - case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: - return "activityResult"; - } - return Integer.toString(type); - } - } - - PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { - owner = _owner; - key = _k; - uid = _u; - ref = new WeakReference<PendingIntentRecord>(this); - } - - public int send(int code, Intent intent, String resolvedType, - IIntentReceiver finishedReceiver) { - synchronized(owner) { - if (!canceled) { - sent = true; - if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { - owner.cancelIntentSenderLocked(this, true); - canceled = true; - } - Intent finalIntent = key.requestIntent != null - ? new Intent(key.requestIntent) : new Intent(); - if (intent != null) { - int changes = finalIntent.fillIn(intent, key.flags); - if ((changes&Intent.FILL_IN_DATA) == 0) { - resolvedType = key.requestResolvedType; - } - } else { - resolvedType = key.requestResolvedType; - } - - final long origId = Binder.clearCallingIdentity(); - - boolean sendFinish = finishedReceiver != null; - switch (key.type) { - case IActivityManager.INTENT_SENDER_ACTIVITY: - try { - owner.startActivityInPackage(uid, - finalIntent, resolvedType, - null, null, 0, false); - } catch (RuntimeException e) { - Log.w(ActivityManagerService.TAG, - "Unable to send startActivity intent", e); - } - break; - case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: - owner.sendActivityResultLocked(-1, key.activity, - key.who, key.requestCode, code, finalIntent); - break; - case IActivityManager.INTENT_SENDER_BROADCAST: - try { - // If a completion callback has been requested, require - // that the broadcast be delivered synchronously - owner.broadcastIntentInPackage(key.packageName, uid, - finalIntent, resolvedType, - finishedReceiver, code, null, null, null, - (finishedReceiver != null), false); - sendFinish = false; - } catch (RuntimeException e) { - Log.w(ActivityManagerService.TAG, - "Unable to send startActivity intent", e); - } - break; - case IActivityManager.INTENT_SENDER_SERVICE: - try { - owner.startServiceInPackage(uid, - finalIntent, resolvedType); - } catch (RuntimeException e) { - Log.w(ActivityManagerService.TAG, - "Unable to send startService intent", e); - } - break; - } - - if (sendFinish) { - try { - finishedReceiver.performReceive(new Intent(finalIntent), 0, - null, null, false); - } catch (RemoteException e) { - } - } - - Binder.restoreCallingIdentity(origId); - - return 0; - } - } - return -1; - } - - protected void finalize() throws Throwable { - if (!canceled) { - synchronized(owner) { - WeakReference<PendingIntentRecord> current = - owner.mIntentSenderRecords.get(key); - if (current == ref) { - owner.mIntentSenderRecords.remove(key); - } - } - } - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "packageName=" + key.packageName - + " type=" + key.typeName() - + " flags=0x" + Integer.toHexString(key.flags)); - pw.println(prefix + "activity=" + key.activity + " who=" + key.who); - pw.println(prefix + "requestCode=" + key.requestCode - + " requestResolvedType=" + key.requestResolvedType); - pw.println(prefix + "requestIntent=" + key.requestIntent); - pw.println(prefix + "sent=" + sent + " canceled=" + canceled); - } - - public String toString() { - return "IntentSenderRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + key.packageName + " " + key.typeName() + "}"; - } -} diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/java/com/android/server/am/PendingThumbnailsRecord.java deleted file mode 100644 index ed478c9..0000000 --- a/services/java/com/android/server/am/PendingThumbnailsRecord.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IThumbnailReceiver; - -import java.util.HashSet; - -/** - * This class keeps track of calls to getTasks() that are still - * waiting for thumbnail images. - */ -class PendingThumbnailsRecord -{ - final IThumbnailReceiver receiver; // who is waiting. - HashSet pendingRecords; // HistoryRecord objects we still wait for. - boolean finished; // Is pendingRecords empty? - - PendingThumbnailsRecord(IThumbnailReceiver _receiver) - { - receiver = _receiver; - pendingRecords = new HashSet(); - finished = false; - } -} diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java deleted file mode 100644 index a1320df..0000000 --- a/services/java/com/android/server/am/ProcessRecord.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2006 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.os.BatteryStatsImpl; -import com.android.server.Watchdog; - -import android.app.ActivityManager; -import android.app.Dialog; -import android.app.IApplicationThread; -import android.app.IInstrumentationWatcher; -import android.content.ComponentName; -import android.content.pm.ApplicationInfo; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; - -/** - * Full information about a particular process that - * is currently running. - */ -class ProcessRecord implements Watchdog.PssRequestor { - final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics - final ApplicationInfo info; // all about the first app in the process - final String processName; // name of the process - // List of packages running in the process - final HashSet<String> pkgList = new HashSet(); - IApplicationThread thread; // the actual proc... may be null only if - // 'persistent' is true (in which case we - // are in the process of launching the app) - int pid; // The process of this application; 0 if none - boolean starting; // True if the process is being started - int maxAdj; // Maximum OOM adjustment for this process - int hiddenAdj; // If hidden, this is the adjustment to use - int curRawAdj; // Current OOM unlimited adjustment for this process - int setRawAdj; // Last set OOM unlimited adjustment for this process - int curAdj; // Current OOM adjustment for this process - int setAdj; // Last set OOM adjustment for this process - boolean isForeground; // Is this app running the foreground UI? - boolean setIsForeground; // Running foreground UI when last set? - boolean foregroundServices; // Running any services that are foreground? - boolean bad; // True if disabled in the bad process list - IBinder forcingToForeground;// Token that is forcing this process to be foreground - int adjSeq; // Sequence id for identifying repeated trav - ComponentName instrumentationClass;// class installed to instrument app - String instrumentationProfileFile; // where to save profiling - IInstrumentationWatcher instrumentationWatcher; // who is waiting - Bundle instrumentationArguments;// as given to us - ComponentName instrumentationResultClass;// copy of instrumentationClass - BroadcastRecord curReceiver;// receiver currently running in the app - long lastRequestedGc; // When we last asked the app to do a gc - int lastPss; // Last pss size reported by app. - - // contains HistoryRecord objects - final ArrayList activities = new ArrayList(); - // all ServiceRecord running in this process - final HashSet services = new HashSet(); - // services that are currently executing code (need to remain foreground). - final HashSet<ServiceRecord> executingServices - = new HashSet<ServiceRecord>(); - // All ConnectionRecord this process holds - final HashSet<ConnectionRecord> connections - = new HashSet<ConnectionRecord>(); - // all IIntentReceivers that are registered from this process. - final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>(); - // class (String) -> ContentProviderRecord - final HashMap pubProviders = new HashMap(); - // All ContentProviderRecord process is using - final HashSet conProviders = new HashSet(); - - boolean persistent; // always keep this application running? - boolean crashing; // are we in the process of crashing? - Dialog crashDialog; // dialog being displayed due to crash. - boolean notResponding; // does the app have a not responding dialog? - Dialog anrDialog; // dialog being displayed due to app not resp. - boolean removed; // has app package been removed from device? - boolean debugging; // was app launched for debugging? - int persistentActivities; // number of activities that are persistent - boolean waitedForDebugger; // has process show wait for debugger dialog? - Dialog waitDialog; // current wait for debugger dialog - - // These reports are generated & stored when an app gets into an error condition. - // They will be "null" when all is OK. - ActivityManager.ProcessErrorStateInfo crashingReport; - ActivityManager.ProcessErrorStateInfo notRespondingReport; - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "class=" + info.className); - pw.println(prefix+"manageSpaceActivityName="+info.manageSpaceActivityName); - pw.println(prefix + "dir=" + info.sourceDir + " publicDir=" + info.publicSourceDir - + " data=" + info.dataDir); - pw.println(prefix + "packageList=" + pkgList); - pw.println(prefix + "instrumentationClass=" + instrumentationClass - + " instrumentationProfileFile=" + instrumentationProfileFile); - pw.println(prefix + "instrumentationArguments=" + instrumentationArguments); - pw.println(prefix + "thread=" + thread + " curReceiver=" + curReceiver); - pw.println(prefix + "pid=" + pid + " starting=" + starting - + " lastPss=" + lastPss); - pw.println(prefix + "maxAdj=" + maxAdj + " hiddenAdj=" + hiddenAdj - + " curRawAdj=" + curRawAdj + " setRawAdj=" + setRawAdj - + " curAdj=" + curAdj + " setAdj=" + setAdj); - pw.println(prefix + "isForeground=" + isForeground - + " setIsForeground=" + setIsForeground - + " foregroundServices=" + foregroundServices - + " forcingToForeground=" + forcingToForeground); - pw.println(prefix + "persistent=" + persistent + " removed=" + removed - + " persistentActivities=" + persistentActivities); - pw.println(prefix + "debugging=" + debugging - + " crashing=" + crashing + " " + crashDialog - + " notResponding=" + notResponding + " " + anrDialog - + " bad=" + bad); - pw.println(prefix + "activities=" + activities); - pw.println(prefix + "services=" + services); - pw.println(prefix + "executingServices=" + executingServices); - pw.println(prefix + "connections=" + connections); - pw.println(prefix + "pubProviders=" + pubProviders); - pw.println(prefix + "conProviders=" + conProviders); - pw.println(prefix + "receivers=" + receivers); - } - - ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread, - ApplicationInfo _info, String _processName) { - batteryStats = _batteryStats; - info = _info; - processName = _processName; - pkgList.add(_info.packageName); - thread = _thread; - maxAdj = ActivityManagerService.EMPTY_APP_ADJ; - hiddenAdj = ActivityManagerService.HIDDEN_APP_MIN_ADJ; - curRawAdj = setRawAdj = -100; - curAdj = setAdj = -100; - persistent = false; - removed = false; - persistentActivities = 0; - } - - /** - * This method returns true if any of the activities within the process record are interesting - * to the user. See HistoryRecord.isInterestingToUserLocked() - */ - public boolean isInterestingToUserLocked() { - final int size = activities.size(); - for (int i = 0 ; i < size ; i++) { - HistoryRecord r = (HistoryRecord) activities.get(i); - if (r.isInterestingToUserLocked()) { - return true; - } - } - return false; - } - - public void stopFreezingAllLocked() { - int i = activities.size(); - while (i > 0) { - i--; - ((HistoryRecord)activities.get(i)).stopFreezingScreenLocked(true); - } - } - - public void requestPss() { - IApplicationThread localThread = thread; - if (localThread != null) { - try { - localThread.requestPss(); - } catch (RemoteException e) { - } - } - } - - public String toString() { - return "ProcessRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + pid + ":" + processName + "/" + info.uid + "}"; - } - - /* - * Return true if package has been added false if not - */ - public boolean addPackage(String pkg) { - if (!pkgList.contains(pkg)) { - pkgList.add(pkg); - return true; - } - return false; - } - - /* - * Delete all packages from list except the package indicated in info - */ - public void resetPackageList() { - pkgList.clear(); - pkgList.add(info.packageName); - } - - public String[] getPackageList() { - int size = pkgList.size(); - if (size == 0) { - return null; - } - String list[] = new String[size]; - pkgList.toArray(list); - return list; - } -} diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java deleted file mode 100644 index 6ac527b..0000000 --- a/services/java/com/android/server/am/ReceiverList.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2006 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 android.app.IIntentReceiver; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; - -import java.io.PrintWriter; -import java.util.ArrayList; - -/** - * A receiver object that has registered for one or more broadcasts. - * The ArrayList holds BroadcastFilter objects. - */ -class ReceiverList extends ArrayList<BroadcastFilter> - implements IBinder.DeathRecipient { - final ActivityManagerService owner; - public final IIntentReceiver receiver; - public final ProcessRecord app; - public final int pid; - public final int uid; - BroadcastRecord curBroadcast = null; - boolean linkedToDeath = false; - - ReceiverList(ActivityManagerService _owner, ProcessRecord _app, - int _pid, int _uid, IIntentReceiver _receiver) { - owner = _owner; - receiver = _receiver; - app = _app; - pid = _pid; - uid = _uid; - } - - // Want object identity, not the array identity we are inheriting. - public boolean equals(Object o) { - return this == o; - } - public int hashCode() { - return System.identityHashCode(this); - } - - public void binderDied() { - linkedToDeath = false; - owner.unregisterReceiver(receiver); - } - - void dumpLocal(PrintWriter pw, String prefix) { - pw.println(prefix + "receiver=IBinder " - + Integer.toHexString(System.identityHashCode(receiver.asBinder()))); - pw.println(prefix + "app=" + app + " pid=" + pid + " uid=" + uid); - pw.println(prefix + "curBroadcast=" + curBroadcast - + " linkedToDeath=" + linkedToDeath); - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - dumpLocal(pw, prefix); - String p2 = prefix + " "; - final int N = size(); - for (int i=0; i<N; i++) { - BroadcastFilter bf = get(i); - pw.println(prefix + "Filter #" + i + ": " + bf); - bf.dump(pw, p2); - } - } - - public String toString() { - return "ReceiverList{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + pid + " " + (app != null ? app.processName : "(unknown name)") - + "/" + uid + " client " - + Integer.toHexString(System.identityHashCode(receiver.asBinder())) - + "}"; - } -} diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java deleted file mode 100644 index 4b90600..0000000 --- a/services/java/com/android/server/am/ServiceRecord.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2006 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.os.BatteryStatsImpl; - -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.ServiceInfo; -import android.os.Binder; -import android.os.IBinder; -import android.os.SystemClock; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -/** - * A running application service. - */ -class ServiceRecord extends Binder { - final BatteryStatsImpl.Uid.Pkg.Serv stats; - final ComponentName name; // service component. - final String shortName; // name.flattenToShortString(). - final Intent.FilterComparison intent; - // original intent used to find service. - final ServiceInfo serviceInfo; - // all information about the service. - final ApplicationInfo appInfo; - // information about service's app. - final String packageName; // the package implementing intent's component - final String processName; // process where this component wants to run - final String permission;// permission needed to access service - final String baseDir; // where activity source (resources etc) located - final String resDir; // where public activity source (public resources etc) located - final String dataDir; // where activity data should go - final boolean exported; // from ServiceInfo.exported - final Runnable restarter; // used to schedule retries of starting the service - final long createTime; // when this service was created - final HashMap<Intent.FilterComparison, IntentBindRecord> bindings - = new HashMap<Intent.FilterComparison, IntentBindRecord>(); - // All active bindings to the service. - final HashMap<IBinder, ConnectionRecord> connections - = new HashMap<IBinder, ConnectionRecord>(); - // IBinder -> ConnectionRecord of all bound clients - final List<Intent> startArgs = new ArrayList<Intent>(); - // start() arguments that haven't yet been delivered. - - ProcessRecord app; // where this service is running or null. - boolean isForeground; // asked to run as a foreground service? - long lastActivity; // last time there was some activity on the service. - boolean startRequested; // someone explicitly called start? - int lastStartId; // identifier of most recent start request. - int executeNesting; // number of outstanding operations keeping foreground. - long executingStart; // start time of last execute request. - int crashCount; // number of times proc has crashed with service running - int totalRestartCount; // number of times we have had to restart. - int restartCount; // number of restarts performed in a row. - long restartDelay; // delay until next restart attempt. - long restartTime; // time of last restart. - long nextRestartTime; // time when restartDelay will expire. - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "intent=" + intent.getIntent()); - pw.println(prefix + "packageName=" + packageName); - pw.println(prefix + "processName=" + processName); - pw.println(prefix + "permission=" + permission); - pw.println(prefix + "baseDir=" + baseDir+ " resDir=" + resDir + " dataDir=" + dataDir); - pw.println(prefix + "app=" + app); - pw.println(prefix + "isForeground=" + isForeground - + " lastActivity=" + lastActivity); - pw.println(prefix + "startRequested=" + startRequested - + " startId=" + lastStartId - + " executeNesting=" + executeNesting - + " executingStart=" + executingStart - + " crashCount=" + crashCount); - pw.println(prefix + "totalRestartCount=" + totalRestartCount - + " restartCount=" + restartCount - + " restartDelay=" + restartDelay - + " restartTime=" + restartTime - + " nextRestartTime=" + nextRestartTime); - if (bindings.size() > 0) { - pw.println(prefix + "Bindings:"); - Iterator<IntentBindRecord> it = bindings.values().iterator(); - while (it.hasNext()) { - IntentBindRecord b = it.next(); - pw.println(prefix + "Binding " + b); - b.dump(pw, prefix + " "); - } - } - if (connections.size() > 0) { - pw.println(prefix + "All Connections:"); - Iterator<ConnectionRecord> it = connections.values().iterator(); - while (it.hasNext()) { - ConnectionRecord c = it.next(); - pw.println(prefix + " " + c); - } - } - } - - ServiceRecord(BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, - Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) { - this.stats = servStats; - this.name = name; - shortName = name.flattenToShortString(); - this.intent = intent; - serviceInfo = sInfo; - appInfo = sInfo.applicationInfo; - packageName = sInfo.applicationInfo.packageName; - processName = sInfo.processName; - permission = sInfo.permission; - baseDir = sInfo.applicationInfo.sourceDir; - resDir = sInfo.applicationInfo.publicSourceDir; - dataDir = sInfo.applicationInfo.dataDir; - exported = sInfo.exported; - this.restarter = restarter; - createTime = lastActivity = SystemClock.uptimeMillis(); - } - - public AppBindRecord retrieveAppBindingLocked(Intent intent, - ProcessRecord app) { - Intent.FilterComparison filter = new Intent.FilterComparison(intent); - IntentBindRecord i = bindings.get(filter); - if (i == null) { - i = new IntentBindRecord(this, filter); - bindings.put(filter, i); - } - AppBindRecord a = i.apps.get(app); - if (a != null) { - return a; - } - a = new AppBindRecord(this, i, app); - i.apps.put(app, a); - return a; - } - - public void resetRestartCounter() { - restartCount = 0; - restartDelay = 0; - restartTime = 0; - } - - public String toString() { - return "ServiceRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + shortName + "}"; - } -} diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java deleted file mode 100644 index aab3736..0000000 --- a/services/java/com/android/server/am/TaskRecord.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.os.SystemClock; - -import java.io.PrintWriter; - -class TaskRecord { - final int taskId; // Unique identifier for this task. - final String affinity; // The affinity name for this task, or null. - final boolean clearOnBackground; // As per the original activity. - Intent intent; // The original intent that started the task. - Intent affinityIntent; // Intent of affinity-moved activity that started this task. - ComponentName origActivity; // The non-alias activity component of the intent. - ComponentName realActivity; // The actual activity component that started the task. - int numActivities; // Current number of activities in this task. - long lastActiveTime; // Last time this task was active, including sleep. - boolean rootWasReset; // True if the intent at the root of the task had - // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. - - TaskRecord(int _taskId, ActivityInfo info, Intent _intent, - boolean _clearOnBackground) { - taskId = _taskId; - affinity = info.taskAffinity; - clearOnBackground = _clearOnBackground; - setIntent(_intent, info); - } - - void touchActiveTime() { - lastActiveTime = android.os.SystemClock.elapsedRealtime(); - } - - long getInactiveDuration() { - return android.os.SystemClock.elapsedRealtime() - lastActiveTime; - } - - void setIntent(Intent _intent, ActivityInfo info) { - if (info.targetActivity == null) { - intent = _intent; - realActivity = _intent != null ? _intent.getComponent() : null; - origActivity = null; - } else { - ComponentName targetComponent = new ComponentName( - info.packageName, info.targetActivity); - if (_intent != null) { - Intent targetIntent = new Intent(_intent); - targetIntent.setComponent(targetComponent); - intent = targetIntent; - realActivity = targetComponent; - origActivity = _intent.getComponent(); - } else { - intent = null; - realActivity = targetComponent; - origActivity = new ComponentName(info.packageName, info.name); - } - } - - if (intent != null && - (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { - // Once we are set to an Intent with this flag, we count this - // task as having a true root activity. - rootWasReset = true; - } - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + "clearOnBackground=" + clearOnBackground - + " numActivities=" + numActivities - + " rootWasReset=" + rootWasReset); - pw.println(prefix + "affinity=" + affinity); - pw.println(prefix + "intent=" + intent); - pw.println(prefix + "affinityIntent=" + affinityIntent); - pw.println(prefix + "origActivity=" + origActivity); - pw.println(prefix + "lastActiveTime=" + lastActiveTime - +" (inactive for " + (getInactiveDuration()/1000) + "s)"); - } - - public String toString() { - return "Task{" + taskId + " " - + (affinity != null ? affinity - : (intent != null ? intent.getComponent().flattenToShortString() - : affinityIntent != null ? affinityIntent.getComponent().flattenToShortString() : "??")) - + "}"; - } -} diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java deleted file mode 100644 index fb7a745..0000000 --- a/services/java/com/android/server/am/UriPermission.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2006 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 android.content.Intent; -import android.net.Uri; - -import java.io.PrintWriter; -import java.util.HashSet; - -class UriPermission { - final int uid; - final Uri uri; - int modeFlags = 0; - int globalModeFlags = 0; - final HashSet<HistoryRecord> readActivities = new HashSet<HistoryRecord>(); - final HashSet<HistoryRecord> writeActivities = new HashSet<HistoryRecord>(); - - UriPermission(int _uid, Uri _uri) { - uid = _uid; - uri = _uri; - } - - void clearModes(int modeFlags) { - if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { - globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; - modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; - if (readActivities.size() > 0) { - for (HistoryRecord r : readActivities) { - r.readUriPermissions.remove(this); - if (r.readUriPermissions.size() == 0) { - r.readUriPermissions = null; - } - } - readActivities.clear(); - } - } - if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { - globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; - modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; - if (readActivities.size() > 0) { - for (HistoryRecord r : readActivities) { - r.writeUriPermissions.remove(this); - if (r.writeUriPermissions.size() == 0) { - r.writeUriPermissions = null; - } - } - readActivities.clear(); - } - } - } - - public String toString() { - return "UriPermission{" - + Integer.toHexString(System.identityHashCode(this)) - + " " + uri + "}"; - } - - void dump(PrintWriter pw, String prefix) { - pw.println(prefix + this); - pw.println(prefix + " modeFlags=0x" + Integer.toHexString(modeFlags) - + " uid=" + uid - + " globalModeFlags=0x" - + Integer.toHexString(globalModeFlags)); - pw.println(prefix + " readActivities=" + readActivities); - pw.println(prefix + " writeActivities=" + writeActivities); - } -} diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java deleted file mode 100755 index 3922f39..0000000 --- a/services/java/com/android/server/am/UsageStatsService.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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.Parcel; -import android.os.Process; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.util.Log; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -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; - // structure used to maintain statistics since the last checkin. - final private Map<String, PkgUsageStatsExtended> mStats; - // Lock to update package stats. Methods suffixed by SLOCK should invoked with - // this lock held - final Object mStatsLock; - // Lock to write to file. Methods suffixed by FLOCK should invoked with - // this lock held. - final Object mFileLock; - // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks - private String mResumedPkg; - private File mFile; - //private File mBackupFile; - private long mLastWriteRealTime; - private int _FILE_WRITE_INTERVAL = 30*60*1000; //ms - private static final String _PREFIX_DELIMIT="."; - private String mFilePrefix; - private Calendar mCal; - private static final int _MAX_NUM_FILES = 10; - private long mLastTime; - - private class PkgUsageStatsExtended { - int mLaunchCount; - long mUsageTime; - long mPausedTime; - long mResumedTime; - - PkgUsageStatsExtended() { - mLaunchCount = 0; - mUsageTime = 0; - } - void updateResume() { - mLaunchCount ++; - mResumedTime = SystemClock.elapsedRealtime(); - } - void updatePause() { - mPausedTime = SystemClock.elapsedRealtime(); - mUsageTime += (mPausedTime - mResumedTime); - } - void clear() { - mLaunchCount = 0; - mUsageTime = 0; - } - } - - UsageStatsService(String fileName) { - mStats = new HashMap<String, PkgUsageStatsExtended>(); - mStatsLock = new Object(); - mFileLock = new Object(); - mFilePrefix = fileName; - mCal = Calendar.getInstance(); - // Update current stats which are binned by date - String uFileName = getCurrentDateStr(mFilePrefix); - mFile = new File(uFileName); - readStatsFromFile(); - mLastWriteRealTime = SystemClock.elapsedRealtime(); - mLastTime = new Date().getTime(); - } - - /* - * Utility method to convert date into string. - */ - private String getCurrentDateStr(String prefix) { - mCal.setTime(new Date()); - StringBuilder sb = new StringBuilder(); - if (prefix != null) { - sb.append(prefix); - sb.append("."); - } - int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1; - if (mm < 10) { - sb.append("0"); - } - sb.append(mm); - int dd = mCal.get(Calendar.DAY_OF_MONTH); - if (dd < 10) { - sb.append("0"); - } - sb.append(dd); - sb.append(mCal.get(Calendar.YEAR)); - return sb.toString(); - } - - private Parcel getParcelForFile(File file) throws IOException { - FileInputStream stream = new FileInputStream(file); - byte[] raw = readFully(stream); - Parcel in = Parcel.obtain(); - in.unmarshall(raw, 0, raw.length); - in.setDataPosition(0); - stream.close(); - return in; - } - - private void readStatsFromFile() { - File newFile = mFile; - synchronized (mFileLock) { - try { - if (newFile.exists()) { - readStatsFLOCK(newFile); - } else { - // Check for file limit before creating a new file - checkFileLimitFLOCK(); - newFile.createNewFile(); - } - } catch (IOException e) { - Log.w(TAG,"Error : " + e + " reading data from file:" + newFile); - } - } - } - - private void readStatsFLOCK(File file) throws IOException { - Parcel in = getParcelForFile(file); - while (in.dataAvail() > 0) { - String pkgName = in.readString(); - PkgUsageStatsExtended pus = new PkgUsageStatsExtended(); - pus.mLaunchCount = in.readInt(); - pus.mUsageTime = in.readLong(); - synchronized (mStatsLock) { - mStats.put(pkgName, pus); - } - } - } - - private ArrayList<String> getUsageStatsFileListFLOCK() { - File dir = getUsageFilesDir(); - if (dir == null) { - Log.w(TAG, "Couldnt find writable directory for usage stats file"); - return null; - } - // Check if there are too many files in the system and delete older files - String fList[] = dir.list(); - if (fList == null) { - return null; - } - File pre = new File(mFilePrefix); - String filePrefix = pre.getName(); - // file name followed by dot - int prefixLen = filePrefix.length()+1; - ArrayList<String> fileList = new ArrayList<String>(); - for (String file : fList) { - int index = file.indexOf(filePrefix); - if (index == -1) { - continue; - } - if (file.endsWith(".bak")) { - continue; - } - fileList.add(file); - } - return fileList; - } - - private File getUsageFilesDir() { - if (mFilePrefix == null) { - return null; - } - File pre = new File(mFilePrefix); - return new File(pre.getParent()); - } - - private void checkFileLimitFLOCK() { - File dir = getUsageFilesDir(); - if (dir == null) { - Log.w(TAG, "Couldnt find writable directory for usage stats file"); - return; - } - // Get all usage stats output files - ArrayList<String> fileList = getUsageStatsFileListFLOCK(); - if (fileList == null) { - // Strange but we dont have to delete any thing - return; - } - int count = fileList.size(); - if (count <= _MAX_NUM_FILES) { - return; - } - // Sort files - Collections.sort(fileList); - count -= _MAX_NUM_FILES; - // Delete older files - for (int i = 0; i < count; i++) { - String fileName = fileList.get(i); - File file = new File(dir, fileName); - Log.i(TAG, "Deleting file : "+fileName); - file.delete(); - } - } - - private void writeStatsToFile() { - synchronized (mFileLock) { - long currTime = new Date().getTime(); - boolean dayChanged = ((currTime - mLastTime) >= (24*60*60*1000)); - long currRealTime = SystemClock.elapsedRealtime(); - if (((currRealTime-mLastWriteRealTime) < _FILE_WRITE_INTERVAL) && - (!dayChanged)) { - // wait till the next update - return; - } - // Get the most recent file - String todayStr = getCurrentDateStr(mFilePrefix); - // Copy current file to back up - File backupFile = new File(mFile.getPath() + ".bak"); - mFile.renameTo(backupFile); - try { - checkFileLimitFLOCK(); - mFile.createNewFile(); - // Write mStats to file - writeStatsFLOCK(); - mLastWriteRealTime = currRealTime; - mLastTime = currTime; - if (dayChanged) { - // clear stats - synchronized (mStats) { - mStats.clear(); - } - mFile = new File(todayStr); - } - // Delete the backup file - if (backupFile != null) { - backupFile.delete(); - } - } catch (IOException e) { - Log.w(TAG, "Failed writing stats to file:" + mFile); - if (backupFile != null) { - backupFile.renameTo(mFile); - } - } - } - } - - private void writeStatsFLOCK() throws IOException { - FileOutputStream stream = new FileOutputStream(mFile); - Parcel out = Parcel.obtain(); - writeStatsToParcelFLOCK(out); - stream.write(out.marshall()); - out.recycle(); - stream.flush(); - stream.close(); - } - - private void writeStatsToParcelFLOCK(Parcel out) { - synchronized (mStatsLock) { - Set<String> keys = mStats.keySet(); - for (String key : keys) { - PkgUsageStatsExtended pus = mStats.get(key); - out.writeString(key); - out.writeInt(pus.mLaunchCount); - out.writeLong(pus.mUsageTime); - } - } - } - - 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); - synchronized (mStatsLock) { - 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); - synchronized (mStatsLock) { - PkgUsageStatsExtended pus = mStats.get(pkgName); - if (pus == null) { - // Weird some error here - Log.w(TAG, "No package stats for pkg:"+pkgName); - return; - } - pus.updatePause(); - } - // Persist data to file - writeStatsToFile(); - } - - 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; - } - synchronized (mStatsLock) { - 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 (mStatsLock) { - Set<String> 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; - } - } - - static byte[] readFully(FileInputStream stream) throws java.io.IOException { - int pos = 0; - int avail = stream.available(); - byte[] data = new byte[avail]; - while (true) { - int amt = stream.read(data, pos, data.length-pos); - if (amt <= 0) { - return data; - } - pos += amt; - avail = stream.available(); - if (avail > data.length-pos) { - byte[] newData = new byte[pos+avail]; - System.arraycopy(data, 0, newData, 0, pos); - data = newData; - } - } - } - - private void collectDumpInfoFLOCK(PrintWriter pw, String[] args) { - List<String> fileList = getUsageStatsFileListFLOCK(); - if (fileList == null) { - return; - } - final boolean isCheckinRequest = scanArgs(args, "-c"); - Collections.sort(fileList); - File usageFile = new File(mFilePrefix); - String dirName = usageFile.getParent(); - File dir = new File(dirName); - String filePrefix = usageFile.getName(); - // file name followed by dot - int prefixLen = filePrefix.length()+1; - String todayStr = getCurrentDateStr(null); - for (String file : fileList) { - File dFile = new File(dir, file); - String dateStr = file.substring(prefixLen); - try { - Parcel in = getParcelForFile(dFile); - collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCheckinRequest); - if (isCheckinRequest && !todayStr.equalsIgnoreCase(dateStr)) { - // Delete old file after collecting info only for checkin requests - dFile.delete(); - } - } catch (FileNotFoundException e) { - Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file); - return; - } catch (IOException e) { - Log.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file); - } - } - } - - private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw, - String date, boolean isCheckinRequest) { - StringBuilder sb = new StringBuilder(); - sb.append("Date:"); - sb.append(date); - boolean first = true; - while (in.dataAvail() > 0) { - String pkgName = in.readString(); - int launchCount = in.readInt(); - long usageTime = in.readLong(); - if (isCheckinRequest) { - if (!first) { - sb.append(","); - } - sb.append(pkgName); - sb.append(","); - sb.append(launchCount); - sb.append(","); - sb.append(usageTime); - sb.append("ms"); - } else { - if (first) { - sb.append("\n"); - } - sb.append("pkg="); - sb.append(pkgName); - sb.append(", launchCount="); - sb.append(launchCount); - sb.append(", usageTime="); - sb.append(usageTime); - sb.append(" ms\n"); - } - first = false; - } - pw.write(sb.toString()); - } - - /** - * 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; - } - - @Override - /* - * The data persisted to file is parsed and the stats are computed. - */ - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - synchronized (mFileLock) { - collectDumpInfoFLOCK(pw, args); - } - } - -} diff --git a/services/java/com/android/server/am/package.html b/services/java/com/android/server/am/package.html deleted file mode 100755 index c9f96a6..0000000 --- a/services/java/com/android/server/am/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -{@hide} - -</body> diff --git a/services/java/com/android/server/status/AnimatedImageView.java b/services/java/com/android/server/status/AnimatedImageView.java deleted file mode 100644 index cd581c4..0000000 --- a/services/java/com/android/server/status/AnimatedImageView.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.widget.ImageView; -import android.widget.RemoteViews.RemoteView; - -@RemoteView -public class AnimatedImageView extends ImageView { - AnimationDrawable mAnim; - boolean mAttached; - - public AnimatedImageView(Context context) { - super(context); - } - - public AnimatedImageView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - private void updateAnim() { - Drawable drawable = getDrawable(); - if (mAttached && mAnim != null) { - mAnim.stop(); - } - if (drawable instanceof AnimationDrawable) { - mAnim = (AnimationDrawable)drawable; - if (mAttached) { - mAnim.start(); - } - } else { - mAnim = null; - } - } - - @Override - public void setImageDrawable(Drawable drawable) { - super.setImageDrawable(drawable); - updateAnim(); - } - - @Override - @android.view.RemotableViewMethod - public void setImageResource(int resid) { - super.setImageResource(resid); - updateAnim(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - if (mAnim != null) { - mAnim.start(); - } - mAttached = true; - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (mAnim != null) { - mAnim.stop(); - } - mAttached = false; - } -} - diff --git a/services/java/com/android/server/status/CloseDragHandle.java b/services/java/com/android/server/status/CloseDragHandle.java deleted file mode 100644 index fabf2ba..0000000 --- a/services/java/com/android/server/status/CloseDragHandle.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.widget.LinearLayout; - - -public class CloseDragHandle extends LinearLayout { - StatusBarService mService; - - public CloseDragHandle(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Ensure that, if there is no target under us to receive the touch, - * that we process it ourself. This makes sure that onInterceptTouchEvent() - * is always called for the entire gesture. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() != MotionEvent.ACTION_DOWN) { - mService.interceptTouchEvent(event); - } - return true; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - return mService.interceptTouchEvent(event) - ? true : super.onInterceptTouchEvent(event); - } -} - diff --git a/services/java/com/android/server/status/DateView.java b/services/java/com/android/server/status/DateView.java deleted file mode 100644 index 7c44d67..0000000 --- a/services/java/com/android/server/status/DateView.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.android.server.status; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.text.format.DateFormat; -import android.util.AttributeSet; -import android.util.Log; -import android.widget.TextView; -import android.view.MotionEvent; - -import java.util.Date; - -public final class DateView extends TextView { - private static final String TAG = "DateView"; - - private boolean mUpdating = false; - - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_TIME_TICK) - || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { - updateClock(); - } - } - }; - - public DateView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - setUpdates(false); - } - - @Override - protected int getSuggestedMinimumWidth() { - // makes the large background bitmap not force us to full width - return 0; - } - - private final void updateClock() { - Date now = new Date(); - setText(DateFormat.getLongDateFormat(getContext()).format(now)); - } - - void setUpdates(boolean update) { - if (update != mUpdating) { - mUpdating = update; - if (update) { - // Register for Intent broadcasts for the clock and battery - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - mContext.registerReceiver(mIntentReceiver, filter, null, null); - updateClock(); - } else { - mContext.unregisterReceiver(mIntentReceiver); - } - } - } -} - diff --git a/services/java/com/android/server/status/ExpandedView.java b/services/java/com/android/server/status/ExpandedView.java deleted file mode 100644 index d0f14cb..0000000 --- a/services/java/com/android/server/status/ExpandedView.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.Display; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.WindowManager; -import android.widget.LinearLayout; -import android.util.Log; - - -public class ExpandedView extends LinearLayout { - final Display mDisplay; - StatusBarService mService; - boolean mTracking; - int mStartX, mStartY; - int mMaxHeight = 0; - int mPrevHeight = -1; - - public ExpandedView(Context context, AttributeSet attrs) { - super(context, attrs); - mDisplay = ((WindowManager)context.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay(); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - } - - /** We want to shrink down to 0, and ignore the background. */ - @Override - public int getSuggestedMinimumHeight() { - return 0; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, - MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - int height = bottom - top; - if (height != mPrevHeight) { - //Log.d(StatusBarService.TAG, "height changed old=" + mPrevHeight + " new=" + height); - mPrevHeight = height; - mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE); - } - } - - void setMaxHeight(int h) { - if (h != mMaxHeight) { - mMaxHeight = h; - requestLayout(); - } - } -} diff --git a/services/java/com/android/server/status/FixedSizeDrawable.java b/services/java/com/android/server/status/FixedSizeDrawable.java deleted file mode 100644 index fe5abca..0000000 --- a/services/java/com/android/server/status/FixedSizeDrawable.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.android.server.status; - -import android.graphics.drawable.Drawable; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Rect; -import android.util.Log; - -class FixedSizeDrawable extends Drawable { - Drawable mDrawable; - int mLeft; - int mTop; - int mRight; - int mBottom; - - FixedSizeDrawable(Drawable that) { - mDrawable = that; - } - - public void setFixedBounds(int l, int t, int r, int b) { - mLeft = l; - mTop = t; - mRight = r; - mBottom = b; - } - - public void setBounds(Rect bounds) { - mDrawable.setBounds(mLeft, mTop, mRight, mBottom); - } - - public void setBounds(int l, int t, int r, int b) { - mDrawable.setBounds(mLeft, mTop, mRight, mBottom); - } - - public void draw(Canvas canvas) { - mDrawable.draw(canvas); - } - - public int getOpacity() { - return mDrawable.getOpacity(); - } - - public void setAlpha(int alpha) { - mDrawable.setAlpha(alpha); - } - - public void setColorFilter(ColorFilter cf) { - mDrawable.setColorFilter(cf); - } -} diff --git a/services/java/com/android/server/status/IconData.java b/services/java/com/android/server/status/IconData.java deleted file mode 100644 index 8a61eb5..0000000 --- a/services/java/com/android/server/status/IconData.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.android.server.status; - -import android.util.Log; - -public class IconData { - /** - * Indicates ths item represents a piece of text. - */ - public static final int TEXT = 1; - - /** - * Indicates ths item represents an icon. - */ - public static final int ICON = 2; - - /** - * The type of this item. One of TEXT, ICON, or LEVEL_ICON. - */ - public int type; - - /** - * The slot that this icon will be in if it is not a notification - */ - public String slot; - - /** - * The package containting the icon to draw for this item. Valid if this is - * an ICON type. - */ - public String iconPackage; - - /** - * The icon to draw for this item. Valid if this is an ICON type. - */ - public int iconId; - - /** - * The level associated with the icon. Valid if this is a LEVEL_ICON type. - */ - public int iconLevel; - - /** - * The "count" number. - */ - public int number; - - /** - * The text associated with the icon. Valid if this is a TEXT type. - */ - public CharSequence text; - - private IconData() { - } - - public static IconData makeIcon(String slot, - String iconPackage, int iconId, int iconLevel, int number) { - IconData data = new IconData(); - data.type = ICON; - data.slot = slot; - data.iconPackage = iconPackage; - data.iconId = iconId; - data.iconLevel = iconLevel; - data.number = number; - return data; - } - - public static IconData makeText(String slot, CharSequence text) { - IconData data = new IconData(); - data.type = TEXT; - data.slot = slot; - data.text = text; - return data; - } - - public void copyFrom(IconData that) { - this.type = that.type; - this.slot = that.slot; - this.iconPackage = that.iconPackage; - this.iconId = that.iconId; - this.iconLevel = that.iconLevel; - this.number = that.number; - this.text = that.text; // should we clone this? - } - - public IconData clone() { - IconData that = new IconData(); - that.copyFrom(this); - return that; - } - - public String toString() { - if (this.type == TEXT) { - return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null") - + " text='" + this.text + "')"; - } - else if (this.type == ICON) { - return "IconData(slot=" + (this.slot != null ? "'" + this.slot + "'" : "null") - + " package=" + this.iconPackage - + " iconId=" + Integer.toHexString(this.iconId) - + " iconLevel=" + this.iconLevel + ")"; - } - else { - return "IconData(type=" + type + ")"; - } - } -} diff --git a/services/java/com/android/server/status/IconMerger.java b/services/java/com/android/server/status/IconMerger.java deleted file mode 100644 index 37fdbfb..0000000 --- a/services/java/com/android/server/status/IconMerger.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.View; -import android.widget.LinearLayout; - - -public class IconMerger extends LinearLayout { - private static final boolean SPEW = false; - - StatusBarService service; - StatusBarIcon moreIcon; - - public IconMerger(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - - final int maxWidth = r - l; - final int N = getChildCount(); - int i; - - // get the rightmost one, and see if we even need to do anything - int fitRight = -1; - for (i=N-1; i>=0; i--) { - final View child = getChildAt(i); - if (child != null && child.getVisibility() != GONE) { - fitRight = child.getRight(); - break; - } - } - - // find the first visible one that isn't the more icon - View moreView = null; - int fitLeft = -1; - int startIndex = -1; - for (i=0; i<N; i++) { - final View child = getChildAt(i); - if (com.android.internal.R.drawable.stat_notify_more == child.getId()) { - moreView = child; - startIndex = i+1; - } - else if (child != null && child.getVisibility() != GONE) { - fitLeft = child.getLeft(); - break; - } - } - - if (moreView == null || startIndex < 0) { - throw new RuntimeException("Status Bar / IconMerger moreView == null"); - } - - // if it fits without the more icon, then hide the more icon and update fitLeft - // so everything gets pushed left - int adjust = 0; - if (fitRight - fitLeft <= maxWidth) { - adjust = fitLeft - moreView.getLeft(); - fitLeft -= adjust; - fitRight -= adjust; - moreView.layout(0, moreView.getTop(), 0, moreView.getBottom()); - } - int extra = fitRight - r; - int shift = -1; - - int breakingPoint = fitLeft + extra + adjust; - int number = 0; - for (i=startIndex; i<N; i++) { - final View child = getChildAt(i); - if (child != null && child.getVisibility() != GONE) { - int childLeft = child.getLeft(); - int childRight = child.getRight(); - if (childLeft < breakingPoint) { - // hide this one - child.layout(0, child.getTop(), 0, child.getBottom()); - int n = this.service.getIconNumberForView(child); - if (n == 0) { - number += 1; - } else if (n > 0) { - number += n; - } - } else { - // decide how much to shift by - if (shift < 0) { - shift = childLeft - fitLeft; - } - // shift this left by shift - child.layout(childLeft-shift, child.getTop(), - childRight-shift, child.getBottom()); - } - } - } - - // BUG: Updating the text during the layout here doesn't seem to cause - // the view to be redrawn fully. The text view gets resized correctly, but the - // text contents aren't drawn properly. To work around this, we post a message - // and provide the value later. We're the only one changing this value show it - // should be ordered correctly. - if (false) { - this.moreIcon.update(number); - } else { - mBugWorkaroundNumber = number; - mBugWorkaroundHandler.post(mBugWorkaroundRunnable); - } - } - - private int mBugWorkaroundNumber; - private Handler mBugWorkaroundHandler = new Handler(); - private Runnable mBugWorkaroundRunnable = new Runnable() { - public void run() { - IconMerger.this.moreIcon.update(mBugWorkaroundNumber); - IconMerger.this.moreIcon.view.invalidate(); - } - }; -} diff --git a/services/java/com/android/server/status/LatestItemView.java b/services/java/com/android/server/status/LatestItemView.java deleted file mode 100644 index a47f6ad..0000000 --- a/services/java/com/android/server/status/LatestItemView.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.widget.FrameLayout; - -public class LatestItemView extends FrameLayout { - - public LatestItemView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public boolean dispatchTouchEvent(MotionEvent ev) { - return onTouchEvent(ev); - } -} diff --git a/services/java/com/android/server/status/NotificationData.java b/services/java/com/android/server/status/NotificationData.java deleted file mode 100644 index 63a7d70..0000000 --- a/services/java/com/android/server/status/NotificationData.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.android.server.status; - -import android.app.PendingIntent; -import android.widget.RemoteViews; - -public class NotificationData { - public String pkg; - public int id; - public CharSequence tickerText; - - public long when; - public boolean ongoingEvent; - public boolean clearable; - - public RemoteViews contentView; - public PendingIntent contentIntent; - - public PendingIntent deleteIntent; - - public NotificationData() { - } - - public String toString() { - return "NotificationData(package=" + pkg + " tickerText=" + tickerText - + " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent - + " deleteIntent=" + deleteIntent - + " clearable=" + clearable - + " contentView=" + contentView + " when=" + when + ")"; - } -} diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/services/java/com/android/server/status/NotificationLinearLayout.java deleted file mode 100644 index ac2e44d..0000000 --- a/services/java/com/android/server/status/NotificationLinearLayout.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.LinearLayout; - - -public class NotificationLinearLayout extends LinearLayout { - public NotificationLinearLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } -} - diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java deleted file mode 100644 index 6229292..0000000 --- a/services/java/com/android/server/status/NotificationViewList.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.android.server.status; - -import android.os.IBinder; -import android.util.Log; -import android.view.View; -import java.util.ArrayList; - -class NotificationViewList { - private ArrayList<StatusBarNotification> mOngoing = new ArrayList(); - private ArrayList<StatusBarNotification> mLatest = new ArrayList(); - - NotificationViewList() { - } - - private static final int indexInList(ArrayList<StatusBarNotification> list, NotificationData n){ - final int N = list.size(); - for (int i=0; i<N; i++) { - StatusBarNotification that = list.get(i); - if (that.data == n) { - return i; - } - } - return -1; - } - - int getIconIndex(NotificationData n) { - final int ongoingSize = mOngoing.size(); - final int latestSize = mLatest.size(); - if (n.ongoingEvent) { - int index = indexInList(mOngoing, n); - if (index >= 0) { - return latestSize + index + 1; - } else { - return -1; - } - } else { - return indexInList(mLatest, n) + 1; - } - } - - void remove(StatusBarNotification notification) { - NotificationData n = notification.data; - int index; - index = indexInList(mOngoing, n); - if (index >= 0) { - mOngoing.remove(index); - return; - } - index = indexInList(mLatest, n); - if (index >= 0) { - mLatest.remove(index); - return; - } - } - - ArrayList<StatusBarNotification> notificationsForPackage(String packageName) { - ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>(); - int N = mOngoing.size(); - for (int i=0; i<N; i++) { - if (matchPackage(mOngoing.get(i), packageName)) { - list.add(mOngoing.get(i)); - } - } - N = mLatest.size(); - for (int i=0; i<N; i++) { - if (matchPackage(mLatest.get(i), packageName)) { - list.add(mLatest.get(i)); - } - } - return list; - } - - private final boolean matchPackage(StatusBarNotification snb, String packageName) { - if (snb.data.contentIntent != null) { - if (snb.data.contentIntent.getTargetPackage().equals(packageName)) { - return true; - } - } else if (snb.data.pkg != null && snb.data.pkg.equals(packageName)) { - return true; - } - return false; - } - - private static final int indexForKey(ArrayList<StatusBarNotification> list, IBinder key) { - final int N = list.size(); - for (int i=0; i<N; i++) { - if (list.get(i).key == key) { - return i; - } - } - return -1; - } - - StatusBarNotification get(IBinder key) { - int index; - index = indexForKey(mOngoing, key); - if (index >= 0) { - return mOngoing.get(index); - } - index = indexForKey(mLatest, key); - if (index >= 0) { - return mLatest.get(index); - } - return null; - } - - // gets the index of the notification in its expanded parent view - int getExpandedIndex(StatusBarNotification notification) { - ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest; - return list.size() - indexForKey(list, notification.key) - 1; - } - - void clearViews() { - int N = mOngoing.size(); - for (int i=0; i<N; i++) { - mOngoing.get(i).view = null; - } - N = mLatest.size(); - for (int i=0; i<N; i++) { - mLatest.get(i).view = null; - } - } - - int ongoingCount() { - return mOngoing.size(); - } - - int latestCount() { - return mLatest.size(); - } - - StatusBarNotification getOngoing(int index) { - return mOngoing.get(index); - } - - StatusBarNotification getLatest(int index) { - return mLatest.get(index); - } - - int size() { - return mOngoing.size() + mLatest.size(); - } - - void add(StatusBarNotification notification) { - ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest; - long when = notification.data.when; - final int N = list.size(); - int index = N; - for (int i=0; i<N; i++) { - StatusBarNotification that = list.get(i); - if (that.data.when > when) { - index = i; - break; - } - } - list.add(index, notification); - - if (StatusBarService.SPEW) { - String s = ""; - for (int i=0; i<mOngoing.size(); i++) { - StatusBarNotification that = mOngoing.get(i); - if (that.key == notification.key) { - s += "["; - } - s += that.data.when; - if (that.key == notification.key) { - s += "]"; - } - s += " "; - } - Log.d(StatusBarService.TAG, "NotificationViewList ongoing index=" + index + ": " + s); - - s = ""; - for (int i=0; i<mLatest.size(); i++) { - StatusBarNotification that = mLatest.get(i); - if (that.key == notification.key) { - s += "["; - } - s += that.data.when; - if (that.key == notification.key) { - s += "]"; - } - s += " "; - } - Log.d(StatusBarService.TAG, "NotificationViewList latest index=" + index + ": " + s); - } - } - - StatusBarNotification get(View view) { - int N = mOngoing.size(); - for (int i=0; i<N; i++) { - StatusBarNotification notification = mOngoing.get(i); - View v = notification.view; - if (v == view) { - return notification; - } - } - N = mLatest.size(); - for (int i=0; i<N; i++) { - StatusBarNotification notification = mLatest.get(i); - View v = notification.view; - if (v == view) { - return notification; - } - } - return null; - } - - void update(StatusBarNotification notification) { - remove(notification); - add(notification); - } - - boolean hasClearableItems() { - int N = mLatest.size(); - for (int i=0; i<N; i++) { - if (mLatest.get(i).data.clearable) { - return true; - } - } - return false; - } -} diff --git a/services/java/com/android/server/status/StatusBarException.java b/services/java/com/android/server/status/StatusBarException.java deleted file mode 100644 index 8e93ca7..0000000 --- a/services/java/com/android/server/status/StatusBarException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.android.server.status; - -public class StatusBarException extends RuntimeException { - StatusBarException(String msg) { - super(msg); - } -} diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java deleted file mode 100644 index 6d09919..0000000 --- a/services/java/com/android/server/status/StatusBarIcon.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.Typeface; -import android.graphics.drawable.AnimationDrawable; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -class StatusBarIcon { - // TODO: get this from a resource - private static final int ICON_GAP = 8; - private static final int ICON_WIDTH = 25; - private static final int ICON_HEIGHT = 25; - - public View view; - - IconData mData; - - private TextView mTextView; - private AnimatedImageView mImageView; - private TextView mNumberView; - - public StatusBarIcon(Context context, IconData data, ViewGroup parent) { - mData = data.clone(); - - switch (data.type) { - case IconData.TEXT: { - TextView t; - t = new TextView(context); - mTextView = t; - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.FILL_PARENT); - t.setTextSize(16); - t.setTextColor(0xff000000); - t.setTypeface(Typeface.DEFAULT_BOLD); - t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); - t.setPadding(6, 0, 0, 0); - t.setLayoutParams(layoutParams); - t.setText(data.text); - this.view = t; - break; - } - - case IconData.ICON: { - // container - LayoutInflater inflater = (LayoutInflater)context.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - View v = inflater.inflate(com.android.internal.R.layout.status_bar_icon, parent, false); - this.view = v; - - // icon - AnimatedImageView im = (AnimatedImageView)v.findViewById(com.android.internal.R.id.image); - im.setImageDrawable(getIcon(context, data)); - im.setImageLevel(data.iconLevel); - mImageView = im; - - // number - TextView nv = (TextView)v.findViewById(com.android.internal.R.id.number); - mNumberView = nv; - if (data.number > 0) { - nv.setText("" + data.number); - nv.setVisibility(View.VISIBLE); - } else { - nv.setVisibility(View.GONE); - } - break; - } - } - } - - public void update(Context context, IconData data) throws StatusBarException { - if (mData.type != data.type) { - throw new StatusBarException("status bar entry type can't change"); - } - switch (data.type) { - case IconData.TEXT: - if (!TextUtils.equals(mData.text, data.text)) { - TextView tv = mTextView; - tv.setText(data.text); - } - break; - case IconData.ICON: - if (((mData.iconPackage != null && data.iconPackage != null) - && !mData.iconPackage.equals(data.iconPackage)) - || mData.iconId != data.iconId - || mData.iconLevel != data.iconLevel) { - ImageView im = mImageView; - im.setImageDrawable(getIcon(context, data)); - im.setImageLevel(data.iconLevel); - } - if (mData.number != data.number) { - TextView nv = mNumberView; - if (data.number > 0) { - nv.setText("" + data.number); - } else { - nv.setText(""); - } - } - break; - } - mData.copyFrom(data); - } - - public void update(int number) { - if (mData.number != number) { - TextView nv = mNumberView; - if (number > 0) { - nv.setText("" + number); - } else { - nv.setText(""); - } - } - mData.number = number; - } - - - /** - * Returns the right icon to use for this item, respecting the iconId and - * iconPackage (if set) - * - * @param context Context to use to get resources if iconPackage is not set - * @return Drawable for this item, or null if the package or item could not - * be found - */ - static Drawable getIcon(Context context, IconData data) { - - Resources r = null; - - if (data.iconPackage != null) { - try { - r = context.getPackageManager().getResourcesForApplication(data.iconPackage); - } catch (PackageManager.NameNotFoundException ex) { - Log.e(StatusBarService.TAG, "Icon package not found: " + data.iconPackage, ex); - return null; - } - } else { - r = context.getResources(); - } - - try { - return r.getDrawable(data.iconId); - } catch (RuntimeException e) { - Log.w(StatusBarService.TAG, "Icon not found in " - + (data.iconPackage != null ? data.iconId : "<system>") - + ": " + Integer.toHexString(data.iconId)); - } - - return null; - } - - int getNumber() { - return mData.number; - } -} - diff --git a/services/java/com/android/server/status/StatusBarNotification.java b/services/java/com/android/server/status/StatusBarNotification.java deleted file mode 100644 index 4636cba..0000000 --- a/services/java/com/android/server/status/StatusBarNotification.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.server.status; - -import android.os.IBinder; -import android.view.View; - -class StatusBarNotification { - IBinder key; - NotificationData data; - View view; - View contentView; -} diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java deleted file mode 100644 index 3a5b13c..0000000 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ /dev/null @@ -1,900 +0,0 @@ -/* - * 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.status; - -import com.android.internal.R; -import com.android.internal.location.GpsLocationProvider; -import com.android.internal.telephony.SimCard; -import com.android.internal.telephony.TelephonyIntents; - -import android.app.AlertDialog; -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothHeadset; -import android.bluetooth.BluetoothIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.TypedArray; -import android.graphics.PixelFormat; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.net.NetworkInfo; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.provider.Settings; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.text.format.DateFormat; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.WindowManagerImpl; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.util.Calendar; -import java.util.TimeZone; - -/** - * This class contains all of the policy about which icons are installed in the status - * bar at boot time. In reality, it should go into the android.policy package, but - * putting it here is the first step from extracting it. - */ -public class StatusBarPolicy { - private static final String TAG = "StatusBarPolicy"; - - private static StatusBarPolicy sInstance; - - // message codes for the handler - private static final int EVENT_DATA_CONN_STATE_CHANGED = 2; - private static final int EVENT_DATA_ACTIVITY = 3; - private static final int EVENT_BATTERY_CLOSE = 4; - - private Context mContext; - private StatusBarService mService; - private Handler mHandler = new StatusBarHandler(); - - // clock - private Calendar mCalendar; - private IBinder mClockIcon; - private IconData mClockData; - - // battery - private IBinder mBatteryIcon; - private IconData mBatteryData; - private boolean mBatteryFirst = true; - private boolean mBatteryPlugged; - private int mBatteryLevel; - private int mBatteryThreshold = 0; // index into mBatteryThresholds - private int[] mBatteryThresholds = new int[] { 15, -1 }; - private AlertDialog mLowBatteryDialog; - private TextView mBatteryLevelTextView; - private View mBatteryView; - private int mBatteryViewSequence; - private boolean mBatteryShowLowOnEndCall = false; - private static final boolean SHOW_LOW_BATTERY_WARNING = true; - - // phone - private TelephonyManager mPhone; - private IBinder mPhoneIcon; - private IconData mPhoneData; - private static final int[] sSignalImages = new int[] { - com.android.internal.R.drawable.stat_sys_signal_0, - com.android.internal.R.drawable.stat_sys_signal_1, - com.android.internal.R.drawable.stat_sys_signal_2, - com.android.internal.R.drawable.stat_sys_signal_3, - com.android.internal.R.drawable.stat_sys_signal_4 - }; - private static final int[] sSignalImages_r = new int[] { - com.android.internal.R.drawable.stat_sys_r_signal_0, - com.android.internal.R.drawable.stat_sys_r_signal_1, - com.android.internal.R.drawable.stat_sys_r_signal_2, - com.android.internal.R.drawable.stat_sys_r_signal_3, - com.android.internal.R.drawable.stat_sys_r_signal_4 - }; - private int[] mDataIconList = sDataNetType_g; - private static final int[] sDataNetType_g = new int[] { - com.android.internal.R.drawable.stat_sys_data_connected_g, - com.android.internal.R.drawable.stat_sys_data_in_g, - com.android.internal.R.drawable.stat_sys_data_out_g, - com.android.internal.R.drawable.stat_sys_data_inandout_g, - }; - private static final int[] sDataNetType_3g = new int[] { - com.android.internal.R.drawable.stat_sys_data_connected_3g, - com.android.internal.R.drawable.stat_sys_data_in_3g, - com.android.internal.R.drawable.stat_sys_data_out_3g, - com.android.internal.R.drawable.stat_sys_data_inandout_3g, - }; - private static final int[] sDataNetType_e = new int[] { - com.android.internal.R.drawable.stat_sys_data_connected_e, - com.android.internal.R.drawable.stat_sys_data_in_e, - com.android.internal.R.drawable.stat_sys_data_out_e, - com.android.internal.R.drawable.stat_sys_data_inandout_e, - }; - // Assume it's all good unless we hear otherwise. We don't always seem - // to get broadcasts that it *is* there. - SimCard.State mSimState = SimCard.State.READY; - int mPhoneState = TelephonyManager.CALL_STATE_IDLE; - int mDataState = TelephonyManager.DATA_DISCONNECTED; - int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; - ServiceState mServiceState; - int mSignalAsu = -1; - - // data connection - private IBinder mDataIcon; - private IconData mDataData; - private boolean mDataIconVisible; - - // ringer volume - private IBinder mVolumeIcon; - private IconData mVolumeData; - private boolean mVolumeVisible; - - // bluetooth device status - private IBinder mBluetoothIcon; - private IconData mBluetoothData; - private int mBluetoothHeadsetState; - private int mBluetoothA2dpState; - private boolean mBluetoothEnabled; - - // wifi - private static final int[] sWifiSignalImages = new int[] { - com.android.internal.R.drawable.stat_sys_wifi_signal_1, - com.android.internal.R.drawable.stat_sys_wifi_signal_2, - com.android.internal.R.drawable.stat_sys_wifi_signal_3, - com.android.internal.R.drawable.stat_sys_wifi_signal_4, - }; - private static final int sWifiTemporarilyNotConnectedImage = - com.android.internal.R.drawable.stat_sys_wifi_signal_0; - - private int mLastWifiSignalLevel = -1; - private boolean mIsWifiConnected = false; - private IBinder mWifiIcon; - private IconData mWifiData; - - // gps - private IBinder mGpsIcon; - private IconData mGpsEnabledIconData; - private IconData mGpsFixIconData; - - // alarm clock - // Icon lit when clock is set - private IBinder mAlarmClockIcon; - private IconData mAlarmClockIconData; - - // sync state - // If sync is active the SyncActive icon is displayed. If sync is not active but - // sync is failing the SyncFailing icon is displayed. Otherwise neither are displayed. - private IBinder mSyncActiveIcon; - private IBinder mSyncFailingIcon; - - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_TIME_TICK)) { - updateClock(); - } - else if (action.equals(Intent.ACTION_TIME_CHANGED)) { - updateClock(); - } - else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { - updateClock(); - } - else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { - String tz = intent.getStringExtra("time-zone"); - mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); - updateClock(); - } - else if (action.equals(Intent.ACTION_ALARM_CHANGED)) { - updateAlarm(intent); - } - else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) { - updateSyncState(intent); - } - else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - updateBattery(intent); - } - else if (action.equals(BluetoothIntent.ENABLED_ACTION) || - action.equals(BluetoothIntent.DISABLED_ACTION) || - action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) || - action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { - updateBluetooth(intent); - } - else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) || - action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) || - action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - updateWifi(intent); - } - else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) || - action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION)) { - updateGps(intent); - } - else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || - action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) { - updateVolume(intent); - } - else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { - updateSimState(intent); - } - } - }; - - private StatusBarPolicy(Context context, StatusBarService service) { - mContext = context; - mService = service; - - // clock - mCalendar = Calendar.getInstance(TimeZone.getDefault()); - mClockData = IconData.makeText("clock", ""); - mClockIcon = service.addIcon(mClockData, null); - updateClock(); - - // battery - mBatteryData = IconData.makeIcon("battery", - null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0); - mBatteryIcon = service.addIcon(mBatteryData, null); - - // phone_signal - mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - mPhoneData = IconData.makeIcon("phone_signal", - null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); - mPhoneIcon = service.addIcon(mPhoneData, null); - // register for phone state notifications. - ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)) - .listen(mPhoneStateListener, - PhoneStateListener.LISTEN_SERVICE_STATE - | PhoneStateListener.LISTEN_SIGNAL_STRENGTH - | PhoneStateListener.LISTEN_CALL_STATE - | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_DATA_ACTIVITY); - - // data_connection - mDataData = IconData.makeIcon("data_connection", - null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0); - mDataIcon = service.addIcon(mDataData, null); - service.setIconVisibility(mDataIcon, false); - - // wifi - mWifiData = IconData.makeIcon("wifi", null, sWifiSignalImages[0], 0, 0); - mWifiIcon = service.addIcon(mWifiData, null); - service.setIconVisibility(mWifiIcon, false); - // wifi will get updated by the sticky intents - - // bluetooth status - mBluetoothData = IconData.makeIcon("bluetooth", - null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); - mBluetoothIcon = service.addIcon(mBluetoothData, 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", - null, com.android.internal.R.drawable.stat_sys_gps_acquiring_anim, 0, 0); - mGpsFixIconData = IconData.makeIcon("gps", - null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0); - mGpsIcon = service.addIcon(mGpsEnabledIconData, null); - service.setIconVisibility(mGpsIcon, false); - - // Alarm clock - mAlarmClockIconData = IconData.makeIcon( - "alarm_clock", - null, com.android.internal.R.drawable.stat_notify_alarm, 0, 0); - mAlarmClockIcon = service.addIcon(mAlarmClockIconData, null); - service.setIconVisibility(mAlarmClockIcon, false); - - // Sync state - mSyncActiveIcon = service.addIcon(IconData.makeIcon("sync_active", - null, R.drawable.stat_notify_sync_anim0, 0, 0), null); - mSyncFailingIcon = service.addIcon(IconData.makeIcon("sync_failing", - null, R.drawable.stat_notify_sync_error, 0, 0), null); - service.setIconVisibility(mSyncActiveIcon, false); - service.setIconVisibility(mSyncFailingIcon, false); - - // volume - mVolumeData = IconData.makeIcon("volume", - null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0); - mVolumeIcon = service.addIcon(mVolumeData, null); - service.setIconVisibility(mVolumeIcon, false); - - IntentFilter filter = new IntentFilter(); - - // Register for Intent broadcasts for... - filter.addAction(Intent.ACTION_TIME_TICK); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - filter.addAction(Intent.ACTION_ALARM_CHANGED); - filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); - filter.addAction(BluetoothIntent.ENABLED_ACTION); - filter.addAction(BluetoothIntent.DISABLED_ACTION); - filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); - filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.RSSI_CHANGED_ACTION); - filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); - filter.addAction(GpsLocationProvider.GPS_FIX_CHANGE_ACTION); - filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); - } - - public static void installIcons(Context context, StatusBarService service) { - sInstance = new StatusBarPolicy(context, service); - } - - private final void updateClock() { - mCalendar.setTimeInMillis(System.currentTimeMillis()); - mClockData.text = DateFormat.getTimeFormat(mContext) - .format(mCalendar.getTime()); - mService.updateIcon(mClockIcon, mClockData, null); - } - - private final void updateAlarm(Intent intent) { - boolean alarmSet = intent.getBooleanExtra("alarmSet", false); - mService.setIconVisibility(mAlarmClockIcon, alarmSet); - } - - private final void updateSyncState(Intent intent) { - boolean isActive = intent.getBooleanExtra("active", false); - boolean isFailing = intent.getBooleanExtra("failing", false); - mService.setIconVisibility(mSyncActiveIcon, isActive); - // Don't display sync failing icon: BUG 1297963 Set sync error timeout to "never" - //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive); - } - - private void pickNextBatteryLevel(int level) { - final int N = mBatteryThresholds.length; - for (int i=0; i<N; i++) { - if (level >= mBatteryThresholds[i]) { - mBatteryThreshold = i; - break; - } - } - if (mBatteryThreshold >= N) { - mBatteryThreshold = N-1; - } - } - - private final void updateBattery(Intent intent) { - mBatteryData.iconId = intent.getIntExtra("icon-small", 0); - mBatteryData.iconLevel = intent.getIntExtra("level", 0); - mService.updateIcon(mBatteryIcon, mBatteryData, null); - - boolean plugged = intent.getIntExtra("plugged", 0) != 0; - int level = intent.getIntExtra("level", -1); - if (false) { - Log.d(TAG, "updateBattery level=" + level - + " plugged=" + plugged - + " mBatteryPlugged=" + mBatteryPlugged - + " mBatteryLevel=" + mBatteryLevel - + " mBatteryThreshold=" + mBatteryThreshold - + " mBatteryFirst=" + mBatteryFirst); - } - - boolean oldPlugged = mBatteryPlugged; - int oldThreshold = mBatteryThreshold; - pickNextBatteryLevel(level); - - mBatteryPlugged = plugged; - mBatteryLevel = level; - - if (mBatteryFirst) { - mBatteryFirst = false; - } - /* - * No longer showing the battery view because it draws attention away - * from the USB storage notification. We could still show it when - * connected to a brick, but that could lead to the user into thinking - * the device does not charge when plugged into USB (since he/she would - * not see the same battery screen on USB as he sees on brick). - */ - /* else { - if (plugged && !oldPlugged) { - showBatteryView(); - } - } - */ - if (!plugged - && ((oldPlugged && level <= mBatteryThresholds[0]) - || (mBatteryThreshold > oldThreshold))) { - // Broadcast the low battery warning - mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); - - if (SHOW_LOW_BATTERY_WARNING) { - if (false) { - Log.d(TAG, "mPhoneState=" + mPhoneState - + " mLowBatteryDialog=" + mLowBatteryDialog - + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); - } - - if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { - showLowBatteryWarning(); - } else { - mBatteryShowLowOnEndCall = true; - } - } - } - } - - private void showBatteryView() { - closeLastBatteryView(); - if (mLowBatteryDialog != null) { - mLowBatteryDialog.dismiss(); - } - - int level = mBatteryLevel; - - View v = View.inflate(mContext, com.android.internal.R.layout.battery_status, null); - mBatteryView = v; - int pixelFormat = PixelFormat.TRANSLUCENT; - Drawable bg = v.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); - } - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_TOAST, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_BLUR_BEHIND - | WindowManager.LayoutParams.FLAG_DIM_BEHIND, - pixelFormat); - - // Get the dim amount from the theme - TypedArray a = mContext.obtainStyledAttributes( - com.android.internal.R.styleable.Theme); - lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); - a.recycle(); - - lp.setTitle("Battery"); - - TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent); - levelTextView.setText(mContext.getString( - com.android.internal.R.string.battery_status_text_percent_format, level)); - - setBatteryLevel(v, com.android.internal.R.id.spacer, 100-level, 0, 0); - setBatteryLevel(v, com.android.internal.R.id.level, level, - com.android.internal.R.drawable.battery_charge_fill, level); - - WindowManagerImpl.getDefault().addView(v, lp); - - scheduleCloseBatteryView(); - } - - private void setBatteryLevel(View parent, int id, int height, int background, int level) { - ImageView v = (ImageView)parent.findViewById(id); - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)v.getLayoutParams(); - lp.weight = height; - if (background != 0) { - v.setBackgroundResource(background); - Drawable bkg = v.getBackground(); - bkg.setLevel(level); - } - } - - private void showLowBatteryWarning() { - closeLastBatteryView(); - - int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0]; - CharSequence levelText = mContext.getString( - com.android.internal.R.string.battery_low_percent_format, level); - - if (mBatteryLevelTextView != null) { - mBatteryLevelTextView.setText(levelText); - } else { - View v = View.inflate(mContext, com.android.internal.R.layout.battery_low, null); - mBatteryLevelTextView=(TextView)v.findViewById(com.android.internal.R.id.level_percent); - - mBatteryLevelTextView.setText(levelText); - - AlertDialog.Builder b = new AlertDialog.Builder(mContext); - b.setCancelable(true); - b.setTitle(com.android.internal.R.string.battery_low_title); - b.setView(v); - b.setIcon(android.R.drawable.ic_dialog_alert); - b.setPositiveButton(android.R.string.ok, null); - - AlertDialog d = b.create(); - d.setOnDismissListener(mLowBatteryListener); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - d.show(); - mLowBatteryDialog = d; - } - } - - private final void updateCallState(int state) { - mPhoneState = state; - if (false) { - Log.d(TAG, "mPhoneState=" + mPhoneState - + " mLowBatteryDialog=" + mLowBatteryDialog - + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); - } - if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { - if (mBatteryShowLowOnEndCall) { - if (!mBatteryPlugged) { - showLowBatteryWarning(); - } - mBatteryShowLowOnEndCall = false; - } - } else { - if (mLowBatteryDialog != null) { - mLowBatteryDialog.dismiss(); - mBatteryShowLowOnEndCall = true; - } - } - } - - private DialogInterface.OnDismissListener mLowBatteryListener - = new DialogInterface.OnDismissListener() { - public void onDismiss(DialogInterface dialog) { - mLowBatteryDialog = null; - mBatteryLevelTextView = null; - } - }; - - private void scheduleCloseBatteryView() { - Message m = mHandler.obtainMessage(EVENT_BATTERY_CLOSE); - m.arg1 = (++mBatteryViewSequence); - mHandler.sendMessageDelayed(m, 3000); - } - - private void closeLastBatteryView() { - if (mBatteryView != null) { - //mBatteryView.debug(); - WindowManagerImpl.getDefault().removeView(mBatteryView); - mBatteryView = null; - } - } - - private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onSignalStrengthChanged(int asu) { - mSignalAsu = asu; - updateSignalStrength(); - } - - @Override - public void onServiceStateChanged(ServiceState state) { - mServiceState = state; - updateSignalStrength(); - updateDataIcon(); - } - - @Override - public void onCallStateChanged(int state, String incomingNumber) { - updateCallState(state); - } - - @Override - public void onDataConnectionStateChanged(int state) { - mDataState = state; - updateDataNetType(); - updateDataIcon(); - } - - @Override - public void onDataActivity(int direction) { - mDataActivity = direction; - updateDataIcon(); - } - }; - - - private final void updateSimState(Intent intent) { - String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE); - if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) { - mSimState = SimCard.State.ABSENT; - } - else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) { - mSimState = SimCard.State.READY; - } - else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) { - final String lockedReason = intent.getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON); - if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { - mSimState = SimCard.State.PIN_REQUIRED; - } - else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { - mSimState = SimCard.State.PUK_REQUIRED; - } - else { - mSimState = SimCard.State.NETWORK_LOCKED; - } - } else { - mSimState = SimCard.State.UNKNOWN; - } - updateDataIcon(); - } - - private final void updateSignalStrength() { - int asu = mSignalAsu; - ServiceState ss = mServiceState; - - boolean hasService = true; - - if (ss != null) { - int state = ss.getState(); - switch (state) { - case ServiceState.STATE_OUT_OF_SERVICE: - case ServiceState.STATE_POWER_OFF: - hasService = false; - break; - } - } else { - hasService = false; - } - - if (!hasService) { - //Log.d(TAG, "updateSignalStrength: no service"); - if (Settings.System.getInt(mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, 0) == 1) { - mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_flightmode; - } else { - mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null; - } - mService.updateIcon(mPhoneIcon, mPhoneData, null); - return; - } - - // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5 - // asu = 0 (-113dB or less) is very weak - // signal, its better to show 0 bars to the user in such cases. - // asu = 99 is a special case, where the signal strength is unknown. - if (asu <= 0 || asu == 99) asu = 0; - else if (asu >= 16) asu = 4; - else if (asu >= 8) asu = 3; - else if (asu >= 4) asu = 2; - else asu = 1; - - int[] iconList; - if (mPhone.isNetworkRoaming()) { - iconList = sSignalImages_r; - } else { - iconList = sSignalImages; - } - - mPhoneData.iconId = iconList[asu]; - mService.updateIcon(mPhoneIcon, mPhoneData, null); - } - - private final void updateDataNetType() { - int net = mPhone.getNetworkType(); - switch (net) { - case TelephonyManager.NETWORK_TYPE_EDGE: - mDataIconList = sDataNetType_e; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - mDataIconList = sDataNetType_3g; - break; - default: - mDataIconList = sDataNetType_g; - break; - } - } - - private final void updateDataIcon() { - int iconId; - boolean visible = true; - - if (mSimState == SimCard.State.READY || mSimState == SimCard.State.UNKNOWN) { - int data = mDataState; - - int[] list = mDataIconList; - - ServiceState ss = mServiceState; - - boolean hasService = false; - - if (ss != null) { - hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE); - } - - if (hasService && data == TelephonyManager.DATA_CONNECTED) { - switch (mDataActivity) { - case TelephonyManager.DATA_ACTIVITY_IN: - iconId = list[1]; - break; - case TelephonyManager.DATA_ACTIVITY_OUT: - iconId = list[2]; - break; - case TelephonyManager.DATA_ACTIVITY_INOUT: - iconId = list[3]; - break; - default: - iconId = list[0]; - break; - } - mDataData.iconId = iconId; - mService.updateIcon(mDataIcon, mDataData, null); - } else { - visible = false; - } - } else { - mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim; - mService.updateIcon(mDataIcon, mDataData, null); - } - if (mDataIconVisible != visible) { - mService.setIconVisibility(mDataIcon, visible); - mDataIconVisible = visible; - } - } - - private final void updateVolume(Intent intent) { - // This can be called from two different received intents, so don't use extras. - - AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - final int ringerMode = audioManager.getRingerMode(); - final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || - ringerMode == AudioManager.RINGER_MODE_VIBRATE; - final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER) - ? com.android.internal.R.drawable.stat_sys_ringer_vibrate - : com.android.internal.R.drawable.stat_sys_ringer_silent; - - if (visible) { - mVolumeData.iconId = iconId; - mService.updateIcon(mVolumeIcon, mVolumeData, null); - } - if (visible != mVolumeVisible) { - mService.setIconVisibility(mVolumeIcon, visible); - mVolumeVisible = visible; - } - } - - private final void updateBluetooth(Intent intent) { - int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth; - - String action = intent.getAction(); - if (action.equals(BluetoothIntent.DISABLED_ACTION)) { - mBluetoothEnabled = false; - } else if (action.equals(BluetoothIntent.ENABLED_ACTION)) { - mBluetoothEnabled = true; - } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { - mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, - BluetoothHeadset.STATE_ERROR); - } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { - mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, - BluetoothA2dp.STATE_DISCONNECTED); - } else { - return; - } - - if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED || - mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED || - mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) { - iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected; - } - - mBluetoothData.iconId = iconId; - mService.updateIcon(mBluetoothIcon, mBluetoothData, null); - mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled); - } - - private final void updateWifi(Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - - final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - if (!enabled) { - // If disabled, hide the icon. (We show icon when connected.) - mService.setIconVisibility(mWifiIcon, false); - } - - } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { - final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, - false); - if (!enabled) { - mService.setIconVisibility(mWifiIcon, false); - } - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - - final NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - - int iconId; - if (networkInfo != null && networkInfo.isConnected()) { - mIsWifiConnected = true; - if (mLastWifiSignalLevel == -1) { - iconId = sWifiSignalImages[0]; - } else { - iconId = sWifiSignalImages[mLastWifiSignalLevel]; - } - - // Show the icon since wi-fi is connected - mService.setIconVisibility(mWifiIcon, true); - - } else { - mLastWifiSignalLevel = -1; - mIsWifiConnected = false; - iconId = sWifiSignalImages[0]; - - // Hide the icon since we're not connected - mService.setIconVisibility(mWifiIcon, false); - } - - mWifiData.iconId = iconId; - mService.updateIcon(mWifiIcon, mWifiData, null); - } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200); - int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, - sWifiSignalImages.length); - if (newSignalLevel != mLastWifiSignalLevel) { - mLastWifiSignalLevel = newSignalLevel; - if (mIsWifiConnected) { - mWifiData.iconId = sWifiSignalImages[newSignalLevel]; - } else { - mWifiData.iconId = sWifiTemporarilyNotConnectedImage; - } - mService.updateIcon(mWifiIcon, mWifiData, null); - } - } - } - - private final void updateGps(Intent intent) { - final String action = intent.getAction(); - final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false); - - if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) { - // GPS is getting fixes - mService.updateIcon(mGpsIcon, mGpsFixIconData, null); - mService.setIconVisibility(mGpsIcon, true); - } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) { - // GPS is off - mService.setIconVisibility(mGpsIcon, false); - } else { - // GPS is on, but not receiving fixes - mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null); - mService.setIconVisibility(mGpsIcon, true); - } - } - - private class StatusBarHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_BATTERY_CLOSE: - if (msg.arg1 == mBatteryViewSequence) { - closeLastBatteryView(); - } - break; - } - } - } -} diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java deleted file mode 100644 index 4748389..0000000 --- a/services/java/com/android/server/status/StatusBarService.java +++ /dev/null @@ -1,1771 +0,0 @@ -/* - * Copyright (C) 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.status; - -import com.android.internal.R; -import com.android.internal.util.CharSequences; - -import android.app.Dialog; -import android.app.IStatusBar; -import android.app.PendingIntent; -import android.app.StatusBarManager; -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.graphics.PixelFormat; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.Binder; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.provider.Telephony; -import android.util.Log; -import android.view.Display; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.WindowManagerImpl; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.LinearLayout; -import android.widget.RemoteViews; -import android.widget.ScrollView; -import android.widget.TextView; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Set; - - -/** - * The public (ok, semi-public) service for the status bar. - * <p> - * This interesting thing to note about this class is that most of the methods that - * are called from other classes just post a message, and everything else is batched - * and coalesced into a series of calls to methods that all start with "perform." - * There are two reasons for this. The first is that some of the methods (activate/deactivate) - * are on IStatusBar, so they're called from the thread pool and they need to make their - * way onto the UI thread. The second is that the message queue is stopped while animations - * are happening in order to make for smoother transitions. - * <p> - * Each icon is either an icon or an icon and a notification. They're treated mostly - * separately throughout the code, although they both use the same key, which is assigned - * when they are created. - */ -public class StatusBarService extends IStatusBar.Stub -{ - static final String TAG = "StatusBar"; - static final boolean DEBUG = false; - static final boolean SPEW = false; - static final boolean DBG = false; - - static final int EXPANDED_LEAVE_ALONE = -10000; - static final int EXPANDED_FULL_OPEN = -10001; - - private static final int MSG_ANIMATE = 1000; - private static final int MSG_ANIMATE_REVEAL = 1001; - - private static final int OP_ADD_ICON = 1; - private static final int OP_UPDATE_ICON = 2; - private static final int OP_REMOVE_ICON = 3; - private static final int OP_SET_VISIBLE = 4; - private static final int OP_EXPAND = 5; - private static final int OP_TOGGLE = 6; - private static final int OP_DISABLE = 7; - private class PendingOp { - IBinder key; - int code; - IconData iconData; - NotificationData notificationData; - boolean visible; - int integer; - } - - private class DisableRecord implements IBinder.DeathRecipient { - String pkg; - int what; - IBinder token; - - public void binderDied() { - Log.i(TAG, "binder died for pkg=" + pkg); - disable(0, token, pkg); - } - } - - public interface NotificationCallbacks { - void onSetDisabled(int status); - void onClearAll(); - void onNotificationClick(String pkg, int id); - void onPanelRevealed(); - } - - private class ExpandedDialog extends Dialog { - ExpandedDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Light_NoTitleBar); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - boolean down = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_BACK: - if (down) { - StatusBarService.this.deactivate(); - } - return true; - } - return super.dispatchKeyEvent(event); - } - } - - final Context mContext; - final Display mDisplay; - StatusBarView mStatusBarView; - int mPixelFormat; - H mHandler = new H(); - ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>(); - NotificationCallbacks mNotificationCallbacks; - - // All accesses to mIconMap and mNotificationData are syncronized on those objects, - // but this is only so dump() can work correctly. Modifying these outside of the UI - // thread will not work, there are places in the code that unlock and reaquire between - // reads and require them to not be modified. - - // icons - HashMap<IBinder,StatusBarIcon> mIconMap = new HashMap<IBinder,StatusBarIcon>(); - ArrayList<StatusBarIcon> mIconList = new ArrayList<StatusBarIcon>(); - String[] mRightIconSlots; - StatusBarIcon[] mRightIcons; - LinearLayout mIcons; - IconMerger mNotificationIcons; - LinearLayout mStatusIcons; - StatusBarIcon mMoreIcon; - private UninstallReceiver mUninstallReceiver; - - // expanded notifications - NotificationViewList mNotificationData = new NotificationViewList(); - Dialog mExpandedDialog; - ExpandedView mExpandedView; - WindowManager.LayoutParams mExpandedParams; - ScrollView mScrollView; - View mNotificationLinearLayout; - View mOngoingTitle; - LinearLayout mOngoingItems; - View mLatestTitle; - LinearLayout mLatestItems; - View mNoNotificationsTitle; - TextView mSpnLabel; - TextView mPlmnLabel; - TextView mClearButton; - CloseDragHandle mCloseView; - int[] mCloseLocation = new int[2]; - boolean mExpanded; - boolean mExpandedVisible; - - // the date view - DateView mDateView; - - // the tracker view - TrackingView mTrackingView; - WindowManager.LayoutParams mTrackingParams; - int mTrackingPosition; - - // ticker - private Ticker mTicker; - private View mTickerView; - private boolean mTicking; - - // Tracking finger for opening/closing. - boolean mTracking; - VelocityTracker mVelocityTracker; - - static final int ANIM_FRAME_DURATION = (1000/60); - - boolean mAnimating; - long mCurAnimationTime; - float mDisplayHeight; - float mAnimY; - float mAnimVel; - float mAnimAccel; - long mAnimLastTime; - boolean mAnimatingReveal = false; - int mViewDelta; - int[] mAbsPos = new int[2]; - - // for disabling the status bar - ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); - int mDisabled = 0; - - /** - * Construct the service, add the status bar view to the window manager - */ - public StatusBarService(Context context) { - mContext = context; - mDisplay = ((WindowManager)context.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay(); - makeStatusBarView(context); - mUninstallReceiver = new UninstallReceiver(); - } - - public void setNotificationCallbacks(NotificationCallbacks listener) { - mNotificationCallbacks = listener; - } - - // ================================================================================ - // Constructing the view - // ================================================================================ - private void makeStatusBarView(Context context) { - Resources res = context.getResources(); - mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order); - mRightIcons = new StatusBarIcon[mRightIconSlots.length]; - - ExpandedView expanded = (ExpandedView)View.inflate(context, - com.android.internal.R.layout.status_bar_expanded, null); - expanded.mService = this; - StatusBarView sb = (StatusBarView)View.inflate(context, - com.android.internal.R.layout.status_bar, null); - sb.mService = this; - - // figure out which pixel-format to use for the status bar. - mPixelFormat = PixelFormat.TRANSLUCENT; - Drawable bg = sb.getBackground(); - if (bg != null) { - mPixelFormat = bg.getOpacity(); - } - - mStatusBarView = sb; - mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons); - mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons); - mNotificationIcons.service = this; - mIcons = (LinearLayout)sb.findViewById(R.id.icons); - mTickerView = sb.findViewById(R.id.ticker); - mDateView = (DateView)sb.findViewById(R.id.date); - - mExpandedDialog = new ExpandedDialog(context); - mExpandedView = expanded; - mOngoingTitle = expanded.findViewById(R.id.ongoingTitle); - mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems); - mLatestTitle = expanded.findViewById(R.id.latestTitle); - mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems); - mNoNotificationsTitle = expanded.findViewById(R.id.noNotificationsTitle); - mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button); - mClearButton.setOnClickListener(mClearButtonListener); - mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel); - mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel); - mScrollView = (ScrollView)expanded.findViewById(R.id.scroll); - mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout); - - mOngoingTitle.setVisibility(View.GONE); - mLatestTitle.setVisibility(View.GONE); - - mTicker = new MyTicker(context, sb); - - TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText); - tickerView.mTicker = mTicker; - - mTrackingView = (TrackingView)View.inflate(context, - com.android.internal.R.layout.status_bar_tracking, null); - mTrackingView.mService = this; - mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close); - mCloseView.mService = this; - - // add the more icon for the notifications - IconData moreData = IconData.makeIcon(null, context.getPackageName(), - R.drawable.stat_notify_more, 0, 42); - mMoreIcon = new StatusBarIcon(context, moreData, mNotificationIcons); - mMoreIcon.view.setId(R.drawable.stat_notify_more); - mNotificationIcons.moreIcon = mMoreIcon; - mNotificationIcons.addView(mMoreIcon.view); - - // set the inital view visibility - setAreThereNotifications(); - mDateView.setVisibility(View.INVISIBLE); - - // before we register for broadcasts - mPlmnLabel.setText(R.string.lockscreen_carrier_default); - mPlmnLabel.setVisibility(View.VISIBLE); - mSpnLabel.setText(""); - mSpnLabel.setVisibility(View.GONE); - - // receive broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION); - context.registerReceiver(mBroadcastReceiver, filter); - } - - public void systemReady() { - final StatusBarView view = mStatusBarView; - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - 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, - mPixelFormat); - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("StatusBar"); - lp.windowAnimations = R.style.Animation_StatusBar; - - WindowManagerImpl.getDefault().addView(view, lp); - } - - // ================================================================================ - // From IStatusBar - // ================================================================================ - public void activate() { - enforceExpandStatusBar(); - addPendingOp(OP_EXPAND, null, true); - } - - public void deactivate() { - enforceExpandStatusBar(); - addPendingOp(OP_EXPAND, null, false); - } - - public void toggle() { - enforceExpandStatusBar(); - addPendingOp(OP_TOGGLE, null, false); - } - - public void disable(int what, IBinder token, String pkg) { - enforceStatusBar(); - synchronized (mNotificationCallbacks) { - // This is a little gross, but I think it's safe as long as nobody else - // synchronizes on mNotificationCallbacks. It's important that the the callback - // and the pending op get done in the correct order and not interleaved with - // other calls, otherwise they'll get out of sync. - int net; - synchronized (mDisableRecords) { - manageDisableListLocked(what, token, pkg); - net = gatherDisableActionsLocked(); - mNotificationCallbacks.onSetDisabled(net); - } - addPendingOp(OP_DISABLE, net); - } - } - - public IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel) { - enforceStatusBar(); - return addIcon(IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); - } - - public void updateIcon(IBinder key, - String slot, String iconPackage, int iconId, int iconLevel) { - enforceStatusBar(); - updateIcon(key, IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); - } - - public void removeIcon(IBinder key) { - enforceStatusBar(); - addPendingOp(OP_REMOVE_ICON, key, null, null, -1); - } - - private void enforceStatusBar() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.STATUS_BAR, - "StatusBarService"); - } - - private void enforceExpandStatusBar() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.EXPAND_STATUS_BAR, - "StatusBarService"); - } - - // ================================================================================ - // Can be called from any thread - // ================================================================================ - public IBinder addIcon(IconData data, NotificationData n) { - int slot; - // assert early-on if they using a slot that doesn't exist. - if (data != null && n == null) { - slot = getRightIconIndex(data.slot); - if (slot < 0) { - throw new SecurityException("invalid status bar icon slot: " - + (data.slot != null ? "'" + data.slot + "'" : "null")); - } - } else { - slot = -1; - } - IBinder key = new Binder(); - addPendingOp(OP_ADD_ICON, key, data, n, -1); - return key; - } - - public void updateIcon(IBinder key, IconData data, NotificationData n) { - addPendingOp(OP_UPDATE_ICON, key, data, n, -1); - } - - public void setIconVisibility(IBinder key, boolean visible) { - addPendingOp(OP_SET_VISIBLE, key, visible); - } - - private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) { - synchronized (mQueue) { - PendingOp op = new PendingOp(); - op.key = key; - op.code = code; - op.iconData = data == null ? null : data.clone(); - op.notificationData = n; - op.integer = i; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(2); - } - } - } - - private void addPendingOp(int code, IBinder key, boolean visible) { - synchronized (mQueue) { - PendingOp op = new PendingOp(); - op.key = key; - op.code = code; - op.visible = visible; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(1); - } - } - } - - private void addPendingOp(int code, int integer) { - synchronized (mQueue) { - PendingOp op = new PendingOp(); - op.code = code; - op.integer = integer; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(1); - } - } - } - - // lock on mDisableRecords - void manageDisableListLocked(int what, IBinder token, String pkg) { - if (SPEW) { - Log.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) - + " pkg=" + pkg); - } - // update the list - synchronized (mDisableRecords) { - final int N = mDisableRecords.size(); - DisableRecord tok = null; - int i; - for (i=0; i<N; i++) { - DisableRecord t = mDisableRecords.get(i); - if (t.token == token) { - tok = t; - break; - } - } - if (what == 0 || !token.isBinderAlive()) { - if (tok != null) { - mDisableRecords.remove(i); - } - } else { - if (tok == null) { - tok = new DisableRecord(); - try { - token.linkToDeath(tok, 0); - } - catch (RemoteException ex) { - return; // give up - } - mDisableRecords.add(tok); - } - tok.what = what; - tok.token = token; - tok.pkg = pkg; - } - } - } - - // lock on mDisableRecords - int gatherDisableActionsLocked() { - final int N = mDisableRecords.size(); - // gather the new net flags - int net = 0; - for (int i=0; i<N; i++) { - net |= mDisableRecords.get(i).what; - } - return net; - } - - private int getRightIconIndex(String slot) { - final int N = mRightIconSlots.length; - for (int i=0; i<N; i++) { - if (mRightIconSlots[i].equals(slot)) { - return i; - } - } - return -1; - } - - // ================================================================================ - // Always called from UI thread - // ================================================================================ - /** - * All changes to the status bar and notifications funnel through here and are batched. - */ - private class H extends Handler { - public void handleMessage(Message m) { - if (m.what == MSG_ANIMATE) { - doAnimation(); - return; - } - if (m.what == MSG_ANIMATE_REVEAL) { - doRevealAnimation(); - return; - } - synchronized (mQueue) { - boolean wasExpanded = mExpanded; - - // for each one in the queue, find all of the ones with the same key - // and collapse that down into a final op and/or call to setVisibility, etc - boolean expand = wasExpanded; - boolean doExpand = false; - boolean doDisable = false; - int disableWhat = 0; - int N = mQueue.size(); - while (N > 0) { - PendingOp op = mQueue.get(0); - boolean doOp = false; - boolean visible = false; - boolean doVisibility = false; - if (op.code == OP_SET_VISIBLE) { - doVisibility = true; - visible = op.visible; - } - else if (op.code == OP_EXPAND) { - doExpand = true; - expand = op.visible; - } - else if (op.code == OP_TOGGLE) { - doExpand = true; - expand = !expand; - } - else { - doOp = true; - } - - if (alwaysHandle(op.code)) { - // coalesce these - for (int i=1; i<N; i++) { - PendingOp o = mQueue.get(i); - if (!alwaysHandle(o.code) && o.key == op.key) { - if (o.code == OP_SET_VISIBLE) { - visible = o.visible; - doVisibility = true; - } - else if (o.code == OP_EXPAND) { - expand = o.visible; - doExpand = true; - } - else { - op.code = o.code; - op.iconData = o.iconData; - op.notificationData = o.notificationData; - } - mQueue.remove(i); - i--; - N--; - } - } - } - - mQueue.remove(0); - N--; - - if (doOp) { - switch (op.code) { - case OP_ADD_ICON: - case OP_UPDATE_ICON: - performAddUpdateIcon(op.key, op.iconData, op.notificationData); - break; - case OP_REMOVE_ICON: - performRemoveIcon(op.key); - break; - case OP_DISABLE: - doDisable = true; - disableWhat = op.integer; - break; - } - } - if (doVisibility && op.code != OP_REMOVE_ICON) { - performSetIconVisibility(op.key, visible); - } - } - - if (mQueue.size() != 0) { - throw new RuntimeException("Assertion failed: mQueue.size=" + mQueue.size()); - } - if (doExpand) { - // this is last so that we capture all of the pending changes before doing it - if (expand) { - animateExpand(); - } else { - animateCollapse(); - } - } - if (doDisable) { - performDisableActions(disableWhat); - } - } - } - } - - private boolean alwaysHandle(int code) { - return code == OP_DISABLE; - } - - /* private */ void performAddUpdateIcon(IBinder key, IconData data, NotificationData n) - throws StatusBarException { - if (DBG) { - Log.d(TAG, "performAddUpdateIcon icon=" + data + " notification=" + n + " key=" + key); - } - // notification - if (n != null) { - StatusBarNotification notification = getNotification(key); - NotificationData oldData = null; - if (notification == null) { - // add - notification = new StatusBarNotification(); - notification.key = key; - notification.data = n; - synchronized (mNotificationData) { - mNotificationData.add(notification); - } - addNotificationView(notification); - setAreThereNotifications(); - } else { - // update - oldData = notification.data; - notification.data = n; - updateNotificationView(notification, oldData); - } - // Show the ticker if one is requested, and the text is different - // than the currently displayed ticker. Also don't do this - // until status bar window is attached to the window manager, - // because... well, what's the point otherwise? And trying to - // run a ticker without being attached will crash! - if (n.tickerText != null && mStatusBarView.getWindowToken() != null - && (oldData == null - || oldData.tickerText == null - || !CharSequences.equals(oldData.tickerText, n.tickerText))) { - if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { - mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText); - } - } - } - - // icon - synchronized (mIconMap) { - StatusBarIcon icon = mIconMap.get(key); - if (icon == null) { - // add - LinearLayout v = n == null ? mStatusIcons : mNotificationIcons; - - icon = new StatusBarIcon(mContext, data, v); - mIconMap.put(key, icon); - mIconList.add(icon); - - if (n == null) { - int slotIndex = getRightIconIndex(data.slot); - StatusBarIcon[] rightIcons = mRightIcons; - if (rightIcons[slotIndex] == null) { - int pos = 0; - for (int i=mRightIcons.length-1; i>slotIndex; i--) { - StatusBarIcon ic = rightIcons[i]; - if (ic != null) { - pos++; - } - } - rightIcons[slotIndex] = icon; - mStatusIcons.addView(icon.view, pos); - } else { - Log.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot); - mIconMap.remove(key); - mIconList.remove(icon); - return ; - } - } else { - int iconIndex = mNotificationData.getIconIndex(n); - mNotificationIcons.addView(icon.view, iconIndex); - } - } else { - if (n == null) { - // right hand side icons -- these don't reorder - icon.update(mContext, data); - } else { - // remove old - ViewGroup parent = (ViewGroup)icon.view.getParent(); - parent.removeView(icon.view); - // add new - icon.update(mContext, data); - int iconIndex = mNotificationData.getIconIndex(n); - mNotificationIcons.addView(icon.view, iconIndex); - } - } - } - } - - /* private */ void performSetIconVisibility(IBinder key, boolean visible) { - synchronized (mIconMap) { - if (DBG) { - Log.d(TAG, "performSetIconVisibility key=" + key + " visible=" + visible); - } - StatusBarIcon icon = mIconMap.get(key); - icon.view.setVisibility(visible ? View.VISIBLE : View.GONE); - } - } - - /* private */ void performRemoveIcon(IBinder key) { - synchronized (this) { - if (DBG) { - Log.d(TAG, "performRemoveIcon key=" + key); - } - StatusBarIcon icon = mIconMap.remove(key); - mIconList.remove(icon); - if (icon != null) { - ViewGroup parent = (ViewGroup)icon.view.getParent(); - parent.removeView(icon.view); - int slotIndex = getRightIconIndex(icon.mData.slot); - if (slotIndex >= 0) { - mRightIcons[slotIndex] = null; - } - } - StatusBarNotification notification = getNotification(key); - if (notification != null) { - removeNotificationView(notification); - synchronized (mNotificationData) { - mNotificationData.remove(notification); - } - setAreThereNotifications(); - } - } - } - - int getIconNumberForView(View v) { - synchronized (mIconMap) { - StatusBarIcon icon = null; - final int N = mIconList.size(); - for (int i=0; i<N; i++) { - StatusBarIcon ic = mIconList.get(i); - if (ic.view == v) { - icon = ic; - break; - } - } - if (icon != null) { - return icon.getNumber(); - } else { - return -1; - } - } - } - - - StatusBarNotification getNotification(IBinder key) { - synchronized (mNotificationData) { - return mNotificationData.get(key); - } - } - - View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { - public void onFocusChange(View v, boolean hasFocus) { - // Because 'v' is a ViewGroup, all its children will be (un)selected - // too, which allows marqueeing to work. - v.setSelected(hasFocus); - } - }; - - View makeNotificationView(StatusBarNotification notification, ViewGroup parent) { - NotificationData n = notification.data; - RemoteViews remoteViews = n.contentView; - if (remoteViews == null) { - return null; - } - - // create the row view - LayoutInflater inflater = (LayoutInflater)mContext.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - View row = inflater.inflate(com.android.internal.R.layout.status_bar_latest_event, parent, false); - - // bind the click event to the content area - ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content); - content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - content.setOnFocusChangeListener(mFocusChangeListener); - PendingIntent contentIntent = n.contentIntent; - if (contentIntent != null) { - content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.id)); - } - - View child = null; - Exception exception = null; - try { - child = remoteViews.apply(mContext, content); - } - catch (RuntimeException e) { - exception = e; - } - if (child == null) { - Log.e(TAG, "couldn't inflate view for package " + n.pkg, exception); - return null; - } - content.addView(child); - - row.setDrawingCacheEnabled(true); - - notification.view = row; - notification.contentView = child; - - return row; - } - - void addNotificationView(StatusBarNotification notification) { - if (notification.view != null) { - throw new RuntimeException("Assertion failed: notification.view=" - + notification.view); - } - - LinearLayout parent = notification.data.ongoingEvent ? mOngoingItems : mLatestItems; - - View child = makeNotificationView(notification, parent); - if (child == null) { - return ; - } - - int index = mNotificationData.getExpandedIndex(notification); - parent.addView(child, index); - } - - /** - * Remove the old one and put the new one in its place. - * @param notification the notification - */ - void updateNotificationView(StatusBarNotification notification, NotificationData oldData) { - NotificationData n = notification.data; - if (oldData != null && n != null - && n.contentView != null && oldData.contentView != null - && n.contentView.getPackage() != null - && oldData.contentView.getPackage() != null - && oldData.contentView.getPackage().equals(n.contentView.getPackage()) - && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()) { - mNotificationData.update(notification); - try { - n.contentView.reapply(mContext, notification.contentView); - - // update the contentIntent - ViewGroup content = (ViewGroup)notification.view.findViewById( - com.android.internal.R.id.content); - PendingIntent contentIntent = n.contentIntent; - if (contentIntent != null) { - content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.id)); - } - } - catch (RuntimeException e) { - // It failed to add cleanly. Log, and remove the view from the panel. - Log.w(TAG, "couldn't reapply views for package " + n.contentView.getPackage(), e); - removeNotificationView(notification); - } - } else { - mNotificationData.update(notification); - removeNotificationView(notification); - addNotificationView(notification); - } - setAreThereNotifications(); - } - - void removeNotificationView(StatusBarNotification notification) { - View v = notification.view; - if (v != null) { - ViewGroup parent = (ViewGroup)v.getParent(); - parent.removeView(v); - notification.view = null; - } - } - - private void setAreThereNotifications() { - boolean ongoing = mOngoingItems.getChildCount() != 0; - boolean latest = mLatestItems.getChildCount() != 0; - - if (mNotificationData.hasClearableItems()) { - mClearButton.setVisibility(View.VISIBLE); - } else { - mClearButton.setVisibility(View.INVISIBLE); - } - - mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE); - mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE); - - if (ongoing || latest) { - mNoNotificationsTitle.setVisibility(View.GONE); - } else { - mNoNotificationsTitle.setVisibility(View.VISIBLE); - } - } - - private void makeExpandedVisible() { - if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); - if (mExpandedVisible) { - return; - } - mExpandedVisible = true; - panelSlightlyVisible(true); - - updateExpandedViewPos(EXPANDED_LEAVE_ALONE); - mExpandedDialog.show(); - mExpandedView.requestFocus(View.FOCUS_FORWARD); - mTrackingView.setVisibility(View.VISIBLE); - - if (!mTicking) { - setDateViewVisibility(true, com.android.internal.R.anim.fade_in); - } - } - - void animateExpand() { - if (SPEW) Log.d(TAG, "Animate expand: expanded=" + mExpanded); - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return ; - } - if (mExpanded) { - return; - } - - prepareTracking(0); - performFling(0, 2000.0f, true); - } - - void animateCollapse() { - if (SPEW) Log.d(TAG, "Animate collapse: expanded=" + mExpanded - + " expanded visible=" + mExpandedVisible); - - if (!mExpandedVisible) { - return; - } - - prepareTracking(mDisplay.getHeight()-1); - performFling(mDisplay.getHeight()-1, -2000.0f, true); - } - - void performExpand() { - if (SPEW) Log.d(TAG, "Perform expand: expanded=" + mExpanded); - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return ; - } - if (mExpanded) { - return; - } - - // It seems strange to sometimes not expand... - if (false) { - synchronized (mNotificationData) { - if (mNotificationData.size() == 0) { - return; - } - } - } - - mExpanded = true; - makeExpandedVisible(); - updateExpandedViewPos(EXPANDED_FULL_OPEN); - - if (false) postStartTracing(); - } - - void performCollapse() { - if (SPEW) Log.d(TAG, "Perform collapse: expanded=" + mExpanded - + " expanded visible=" + mExpandedVisible); - - if (!mExpandedVisible) { - return; - } - mExpandedVisible = false; - panelSlightlyVisible(false); - mExpandedDialog.hide(); - mTrackingView.setVisibility(View.GONE); - - if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { - setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); - } - setDateViewVisibility(false, com.android.internal.R.anim.fade_out); - - if (!mExpanded) { - return; - } - mExpanded = false; - } - - void doAnimation() { - if (mAnimating) { - if (SPEW) Log.d(TAG, "doAnimation"); - if (SPEW) Log.d(TAG, "doAnimation before mAnimY=" + mAnimY); - incrementAnim(); - if (SPEW) Log.d(TAG, "doAnimation after mAnimY=" + mAnimY); - if (mAnimY >= mDisplay.getHeight()-1) { - if (SPEW) Log.d(TAG, "Animation completed to expanded state."); - mAnimating = false; - updateExpandedViewPos(EXPANDED_FULL_OPEN); - performExpand(); - } - else if (mAnimY < mStatusBarView.getHeight()) { - if (SPEW) Log.d(TAG, "Animation completed to collapsed state."); - mAnimating = false; - performCollapse(); - } - else { - updateExpandedViewPos((int)mAnimY); - mCurAnimationTime += ANIM_FRAME_DURATION; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); - } - } - } - - void stopTracking() { - mTracking = false; - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - void incrementAnim() { - long now = SystemClock.uptimeMillis(); - float t = ((float)(now - mAnimLastTime)) / 1000; // ms -> s - final float y = mAnimY; - final float v = mAnimVel; // px/s - final float a = mAnimAccel; // px/s/s - mAnimY = y + (v*t) + (0.5f*a*t*t); // px - mAnimVel = v + (a*t); // px/s - mAnimLastTime = now; // ms - //Log.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY - // + " mAnimAccel=" + mAnimAccel); - } - - void doRevealAnimation() { - final int h = mCloseView.getHeight() + mStatusBarView.getHeight(); - if (mAnimatingReveal && mAnimating && mAnimY < h) { - incrementAnim(); - if (mAnimY >= h) { - mAnimY = h; - updateExpandedViewPos((int)mAnimY); - } else { - updateExpandedViewPos((int)mAnimY); - mCurAnimationTime += ANIM_FRAME_DURATION; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - } - } - } - - void prepareTracking(int y) { - mTracking = true; - mVelocityTracker = VelocityTracker.obtain(); - boolean opening = !mExpanded; - if (!mExpanded) { - mAnimAccel = 2000.0f; - mAnimVel = 200; - mAnimY = mStatusBarView.getHeight(); - updateExpandedViewPos((int)mAnimY); - mAnimating = true; - mAnimatingReveal = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - } else { - // it's open, close it? - if (mAnimating) { - mAnimating = false; - mHandler.removeMessages(MSG_ANIMATE); - } - } - if (opening) { - makeExpandedVisible(); - } else { - updateExpandedViewPos(y + mViewDelta); - } - } - - void performFling(int y, float vel, boolean always) { - mAnimatingReveal = false; - mDisplayHeight = mDisplay.getHeight(); - - mAnimY = y; - mAnimVel = vel; - - //Log.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel); - - if (mExpanded) { - if (!always && ( - vel > 200.0f - || (y > (mDisplayHeight-25) && vel > -200.0f))) { - // We are expanded, but they didn't move sufficiently to cause - // us to retract. Animate back to the expanded position. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are expanded and are now going to animate away. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } else { - if (always || ( - vel > 200.0f - || (y > (mDisplayHeight/2) && vel > -200.0f))) { - // We are collapsed, and they moved enough to allow us to - // expand. Animate in the notifications. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are collapsed, but they didn't move sufficiently to cause - // us to retract. Animate back to the collapsed position. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } - //Log.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel - // + " mAnimAccel=" + mAnimAccel); - - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); - stopTracking(); - } - - boolean interceptTouchEvent(MotionEvent event) { - if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event); - - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return true; - } - - final int statusBarSize = mStatusBarView.getHeight(); - final int hitSize = statusBarSize*2; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - int y = (int)event.getRawY(); - - if (!mExpanded) { - mViewDelta = statusBarSize - y; - } else { - mTrackingView.getLocationOnScreen(mAbsPos); - mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; - } - if ((!mExpanded && y < hitSize) || - (mExpanded && y > (mDisplay.getHeight()-hitSize))) { - prepareTracking(y); - mVelocityTracker.addMovement(event); - } - } else if (mTracking) { - mVelocityTracker.addMovement(event); - final int minY = statusBarSize + mCloseView.getHeight(); - if (event.getAction() == MotionEvent.ACTION_MOVE) { - int y = (int)event.getRawY(); - if (mAnimatingReveal && y < minY) { - // nothing - } else { - mAnimatingReveal = false; - updateExpandedViewPos(y + mViewDelta); - } - } else if (event.getAction() == MotionEvent.ACTION_UP) { - mVelocityTracker.computeCurrentVelocity(1000); - - float yVel = mVelocityTracker.getYVelocity(); - boolean negative = yVel < 0; - - float xVel = mVelocityTracker.getXVelocity(); - if (xVel < 0) { - xVel = -xVel; - } - if (xVel > 150.0f) { - xVel = 150.0f; // limit how much we care about the x axis - } - - float vel = (float)Math.hypot(yVel, xVel); - if (negative) { - vel = -vel; - } - - performFling((int)event.getRawY(), vel, false); - } - - } - return false; - } - - private class Launcher implements View.OnClickListener { - private PendingIntent mIntent; - private String mPkg; - private int mId; - - Launcher(PendingIntent intent, String pkg, int id) { - mIntent = intent; - mPkg = pkg; - mId = id; - } - - public void onClick(View v) { - try { - mIntent.send(); - mNotificationCallbacks.onNotificationClick(mPkg, mId); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. Just log the exception message. - Log.w(TAG, "Sending contentIntent failed: " + e); - } - deactivate(); - } - } - - private class MyTicker extends Ticker { - MyTicker(Context context, StatusBarView sb) { - super(context, sb); - } - - @Override - void tickerStarting() { - mTicking = true; - mIcons.setVisibility(View.GONE); - mTickerView.setVisibility(View.VISIBLE); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); - if (mExpandedVisible) { - setDateViewVisibility(false, com.android.internal.R.anim.push_up_out); - } - } - - @Override - void tickerDone() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.push_down_in); - } - } - - void tickerHalting() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } - - Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; - public void onAnimationEnd(Animation animation) { - mTicking = false; - } - public void onAnimationRepeat(Animation animation) { - } - public void onAnimationStart(Animation animation) { - } - }; - - private Animation loadAnim(int id, Animation.AnimationListener listener) { - Animation anim = AnimationUtils.loadAnimation(mContext, id); - if (listener != null) { - anim.setAnimationListener(listener); - } - return anim; - } - - public String viewInfo(View v) { - return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() - + " " + v.getWidth() + "x" + v.getHeight() + ")"; - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump StatusBar from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mQueue) { - pw.println("Current Status Bar state:"); - pw.println(" mExpanded=" + mExpanded - + ", mExpandedVisible=" + mExpandedVisible); - pw.println(" mTicking=" + mTicking); - pw.println(" mTracking=" + mTracking); - pw.println(" mAnimating=" + mAnimating - + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel - + ", mAnimAccel=" + mAnimAccel); - pw.println(" mCurAnimationTime=" + mCurAnimationTime - + " mAnimLastTime=" + mAnimLastTime); - pw.println(" mDisplayHeight=" + mDisplayHeight - + " mAnimatingReveal=" + mAnimatingReveal - + " mViewDelta=" + mViewDelta); - pw.println(" mDisplayHeight=" + mDisplayHeight); - final int N = mQueue.size(); - pw.println(" mQueue.size=" + N); - for (int i=0; i<N; i++) { - PendingOp op = mQueue.get(i); - pw.println(" [" + i + "] key=" + op.key + " code=" + op.code + " visible=" - + op.visible); - pw.println(" iconData=" + op.iconData); - pw.println(" notificationData=" + op.notificationData); - } - pw.println(" mExpandedParams: " + mExpandedParams); - pw.println(" mExpandedView: " + viewInfo(mExpandedView)); - pw.println(" mExpandedDialog: " + mExpandedDialog); - pw.println(" mTrackingParams: " + mTrackingParams); - pw.println(" mTrackingView: " + viewInfo(mTrackingView)); - pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle)); - pw.println(" mOngoingItems: " + viewInfo(mOngoingItems)); - pw.println(" mLatestTitle: " + viewInfo(mLatestTitle)); - pw.println(" mLatestItems: " + viewInfo(mLatestItems)); - pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle)); - pw.println(" mCloseView: " + viewInfo(mCloseView)); - pw.println(" mTickerView: " + viewInfo(mTickerView)); - pw.println(" mScrollView: " + viewInfo(mScrollView) - + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); - pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout)); - } - synchronized (mIconMap) { - final int N = mIconMap.size(); - pw.println(" mIconMap.size=" + N); - Set<IBinder> keys = mIconMap.keySet(); - int i=0; - for (IBinder key: keys) { - StatusBarIcon icon = mIconMap.get(key); - pw.println(" [" + i + "] key=" + key); - pw.println(" data=" + icon.mData); - i++; - } - } - synchronized (mNotificationData) { - int N = mNotificationData.ongoingCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getOngoing(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - N = mNotificationData.latestCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getLatest(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - } - synchronized (mDisableRecords) { - final int N = mDisableRecords.size(); - pw.println(" mDisableRecords.size=" + N - + " mDisabled=0x" + Integer.toHexString(mDisabled)); - for (int i=0; i<N; i++) { - DisableRecord tok = mDisableRecords.get(i); - pw.println(" [" + i + "] what=0x" + Integer.toHexString(tok.what) - + " pkg=" + tok.pkg + " token=" + tok.token); - } - } - - if (false) { - pw.println("see the logcat for a dump of the views we have created."); - // must happen on ui thread - mHandler.post(new Runnable() { - public void run() { - mStatusBarView.getLocationOnScreen(mAbsPos); - Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mStatusBarView.getWidth() + "x" - + mStatusBarView.getHeight()); - mStatusBarView.debug(); - - mExpandedView.getLocationOnScreen(mAbsPos); - Log.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mExpandedView.getWidth() + "x" - + mExpandedView.getHeight()); - mExpandedView.debug(); - - mTrackingView.getLocationOnScreen(mAbsPos); - Log.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mTrackingView.getWidth() + "x" - + mTrackingView.getHeight()); - mTrackingView.debug(); - } - }); - } - } - - void onBarViewAttached() { - WindowManager.LayoutParams lp; - int pixelFormat; - Drawable bg; - - /// ---------- Tracking View -------------- - pixelFormat = PixelFormat.TRANSLUCENT; - bg = mTrackingView.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); - } - - lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT, - WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - pixelFormat); -// lp.token = mStatusBarView.getWindowToken(); - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("TrackingView"); - mTrackingParams = lp; - - WindowManagerImpl.getDefault().addView(mTrackingView, lp); - } - - void onTrackingViewAttached() { - WindowManager.LayoutParams lp; - int pixelFormat; - Drawable bg; - - /// ---------- Expanded View -------------- - pixelFormat = PixelFormat.TRANSLUCENT; - bg = mExpandedView.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); - } - - lp = mExpandedDialog.getWindow().getAttributes(); - lp.width = ViewGroup.LayoutParams.FILL_PARENT; - lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; - lp.x = 0; - lp.y = 0; - lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; - lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - lp.format = pixelFormat; - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("StatusBarExpanded"); - mExpandedDialog.getWindow().setAttributes(lp); - mExpandedParams = lp; - - mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mExpandedDialog.setContentView(mExpandedView, - new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - mExpandedDialog.show(); - mExpandedDialog.hide(); - View hack = (View)mExpandedView.getParent(); - } - - void setDateViewVisibility(boolean visible, int anim) { - mDateView.setUpdates(visible); - mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - mDateView.startAnimation(loadAnim(anim, null)); - } - - void setNotificationIconVisibility(boolean visible, int anim) { - int old = mNotificationIcons.getVisibility(); - int v = visible ? View.VISIBLE : View.INVISIBLE; - if (old != v) { - mNotificationIcons.setVisibility(v); - mNotificationIcons.startAnimation(loadAnim(anim, null)); - } - } - - void updateExpandedViewPos(int expandedPosition) { - if (SPEW) { - Log.d(TAG, "updateExpandedViewPos before pos=" + expandedPosition - + " mTrackingParams.y=" + mTrackingParams.y - + " mTrackingPosition=" + mTrackingPosition); - } - - // If the expanded view is not visible, there is no reason to do - // any work. - if (!mExpandedVisible) { - return; - } - - // tracking view... - int h = mStatusBarView.getHeight(); - int disph = mDisplay.getHeight(); - int pos; - if (expandedPosition == EXPANDED_FULL_OPEN) { - pos = h; - } - else if (expandedPosition == EXPANDED_LEAVE_ALONE) { - pos = mTrackingPosition; - } - else { - if (expandedPosition <= disph) { - pos = expandedPosition; - } else { - pos = disph; - } - pos -= disph-h; - } - mTrackingPosition = mTrackingParams.y = pos; - mTrackingParams.height = disph-h; - WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams); - - mCloseView.getLocationInWindow(mCloseLocation); - - if (mExpandedParams != null) { - mExpandedParams.y = pos + mTrackingView.getHeight() - - (mTrackingParams.height-mCloseLocation[1]) - mExpandedView.getHeight(); - int max = h; - if (mExpandedParams.y > max) { - mExpandedParams.y = max; - } - int min = mTrackingPosition; - if (mExpandedParams.y < min) { - mExpandedParams.y = min; - } - - /* - Log.d(TAG, "mTrackingPosition=" + mTrackingPosition - + " mTrackingView.height=" + mTrackingView.getHeight() - + " diff=" + (mTrackingPosition + mTrackingView.getHeight()) - + " h=" + h); - */ - panelSlightlyVisible((mTrackingPosition + mTrackingView.getHeight()) > h); - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - } - - if (SPEW) { - Log.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition - + " mTrackingParams.y=" + mTrackingParams.y - + " mTrackingPosition=" + mTrackingPosition - + " mExpandedParams.y=" + mExpandedParams.y); - } - } - - void updateAvailableHeight() { - if (mExpandedView != null) { - int disph = mDisplay.getHeight(); - int h = mStatusBarView.getHeight(); - int max = disph - (mCloseView.getHeight() + h); - mExpandedView.setMaxHeight(max); - } - } - - /** - * The LEDs are turned o)ff when the notification panel is shown, even just a little bit. - * This was added last-minute and is inconsistent with the way the rest of the notifications - * are handled, because the notification isn't really cancelled. The lights are just - * turned off. If any other notifications happen, the lights will turn back on. Steve says - * this is what he wants. (see bug 1131461) - */ - private boolean mPanelSlightlyVisible; - void panelSlightlyVisible(boolean visible) { - if (mPanelSlightlyVisible != visible) { - mPanelSlightlyVisible = visible; - if (visible) { - // tell the notification manager to turn off the lights. - mNotificationCallbacks.onPanelRevealed(); - } - } - } - - void performDisableActions(int net) { - int old = mDisabled; - int diff = net ^ old; - mDisabled = net; - - // act accordingly - if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { - if ((net & StatusBarManager.DISABLE_EXPAND) != 0) { - performCollapse(); - } - } - if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - Log.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); - if (mTicking) { - mNotificationIcons.setVisibility(View.INVISIBLE); - mTicker.halt(); - } else { - setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); - } - } else { - Log.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); - if (!mExpandedVisible) { - setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } - } - - private View.OnClickListener mClearButtonListener = new View.OnClickListener() { - public void onClick(View v) { - mNotificationCallbacks.onClearAll(); - performCollapse(); - } - }; - - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - deactivate(); - } - else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) { - updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false), - intent.getStringExtra(Telephony.Intents.EXTRA_SPN), - intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false), - intent.getStringExtra(Telephony.Intents.EXTRA_PLMN)); - } - else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - updateResources(); - } - } - }; - - void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { - if (false) { - Log.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn - + " showPlmn=" + showPlmn + " plmn=" + plmn); - } - boolean something = false; - if (showPlmn) { - mPlmnLabel.setVisibility(View.VISIBLE); - if (plmn != null) { - mPlmnLabel.setText(plmn); - } else { - mPlmnLabel.setText(R.string.lockscreen_carrier_default); - } - } else { - mPlmnLabel.setText(""); - mPlmnLabel.setVisibility(View.GONE); - } - if (showSpn && spn != null) { - mSpnLabel.setText(spn); - mSpnLabel.setVisibility(View.VISIBLE); - something = true; - } else { - mSpnLabel.setText(""); - mSpnLabel.setVisibility(View.GONE); - } - } - - /** - * Reload some of our resources when the configuration changes. - * - * We don't reload everything when the configuration changes -- we probably - * should, but getting that smooth is tough. Someday we'll fix that. In the - * meantime, just update the things that we know change. - */ - void updateResources() { - mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button)); - Log.d(TAG, "updateResources"); - } - - // - // tracing - // - - void postStartTracing() { - mHandler.postDelayed(mStartTracing, 3000); - } - - void vibrate() { - android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService( - Context.VIBRATOR_SERVICE); - vib.vibrate(250); - } - - Runnable mStartTracing = new Runnable() { - public void run() { - vibrate(); - SystemClock.sleep(250); - Log.d(TAG, "startTracing"); - android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); - mHandler.postDelayed(mStopTracing, 10000); - } - }; - - Runnable mStopTracing = new Runnable() { - public void run() { - android.os.Debug.stopMethodTracing(); - Log.d(TAG, "stopTracing"); - vibrate(); - } - }; - - class UninstallReceiver extends BroadcastReceiver { - public UninstallReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); - filter.addDataScheme("package"); - mContext.registerReceiver(this, filter); - } - - @Override - public void onReceive(Context context, Intent intent) { - ArrayList<StatusBarNotification> list = null; - synchronized (StatusBarService.this) { - Uri data = intent.getData(); - if (data != null) { - String pkg = data.getSchemeSpecificPart(); - list = mNotificationData.notificationsForPackage(pkg); - } - } - - if (list != null) { - final int N = list.size(); - for (int i=0; i<N; i++) { - removeIcon(list.get(i).key); - } - } - } - } -} diff --git a/services/java/com/android/server/status/StatusBarView.java b/services/java/com/android/server/status/StatusBarView.java deleted file mode 100644 index 35dfb81..0000000 --- a/services/java/com/android/server/status/StatusBarView.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.widget.FrameLayout; - -import com.android.internal.R; - -public class StatusBarView extends FrameLayout { - private static final String TAG = "StatusBarView"; - - StatusBarService mService; - boolean mTracking; - int mStartX, mStartY; - ViewGroup mNotificationIcons; - ViewGroup mStatusIcons; - View mDate; - FixedSizeDrawable mBackground; - - public StatusBarView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mNotificationIcons = (ViewGroup)findViewById(R.id.notificationIcons); - mStatusIcons = (ViewGroup)findViewById(R.id.statusIcons); - mDate = findViewById(R.id.date); - - mBackground = new FixedSizeDrawable(mDate.getBackground()); - mBackground.setFixedBounds(0, 0, 0, 0); - mDate.setBackgroundDrawable(mBackground); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mService.onBarViewAttached(); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - - // put the date date view quantized to the icons - int oldDateRight = mDate.getRight(); - int newDateRight; - - newDateRight = getDateSize(mNotificationIcons, oldDateRight, - getViewOffset(mNotificationIcons)); - if (newDateRight < 0) { - int offset = getViewOffset(mStatusIcons); - if (oldDateRight < offset) { - newDateRight = oldDateRight; - } else { - newDateRight = getDateSize(mStatusIcons, oldDateRight, offset); - if (newDateRight < 0) { - newDateRight = r; - } - } - } - int max = r - getPaddingRight(); - if (newDateRight > max) { - newDateRight = max; - } - - mDate.layout(mDate.getLeft(), mDate.getTop(), newDateRight, mDate.getBottom()); - mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t)); - } - - /** - * Gets the left position of v in this view. Throws if v is not - * a child of this. - */ - private int getViewOffset(View v) { - int offset = 0; - while (v != this) { - offset += v.getLeft(); - ViewParent p = v.getParent(); - if (v instanceof View) { - v = (View)p; - } else { - throw new RuntimeException(v + " is not a child of " + this); - } - } - return offset; - } - - private int getDateSize(ViewGroup g, int w, int offset) { - final int N = g.getChildCount(); - for (int i=0; i<N; i++) { - View v = g.getChildAt(i); - int l = v.getLeft() + offset; - int r = v.getRight() + offset; - if (w >= l && w <= r) { - return r; - } - } - return -1; - } - - /** - * Ensure that, if there is no target under us to receive the touch, - * that we process it ourself. This makes sure that onInterceptTouchEvent() - * is always called for the entire gesture. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() != MotionEvent.ACTION_DOWN) { - mService.interceptTouchEvent(event); - } - return true; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - return mService.interceptTouchEvent(event) - ? true : super.onInterceptTouchEvent(event); - } -} - diff --git a/services/java/com/android/server/status/Ticker.java b/services/java/com/android/server/status/Ticker.java deleted file mode 100644 index c93ee0d..0000000 --- a/services/java/com/android/server/status/Ticker.java +++ /dev/null @@ -1,230 +0,0 @@ -package com.android.server.status; - -import com.android.internal.R; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.text.StaticLayout; -import android.text.Layout.Alignment; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.TextSwitcher; -import android.widget.TextView; -import android.widget.ImageSwitcher; - -import java.util.ArrayList; - - -abstract class Ticker { - private static final int TICKER_SEGMENT_DELAY = 3000; - - private final class Segment { - NotificationData notificationData; - Drawable icon; - CharSequence text; - int current; - int next; - boolean first; - - StaticLayout getLayout(CharSequence substr) { - int w = mTextSwitcher.getWidth() - mTextSwitcher.getPaddingLeft() - - mTextSwitcher.getPaddingRight(); - return new StaticLayout(substr, mPaint, w, Alignment.ALIGN_NORMAL, 1, 0, true); - } - - CharSequence rtrim(CharSequence substr, int start, int end) { - while (end > start && !TextUtils.isGraphic(substr.charAt(end-1))) { - end--; - } - if (end > start) { - return substr.subSequence(start, end); - } - return null; - } - - /** returns null if there is no more text */ - CharSequence getText() { - if (this.current > this.text.length()) { - return null; - } - CharSequence substr = this.text.subSequence(this.current, this.text.length()); - StaticLayout l = getLayout(substr); - int lineCount = l.getLineCount(); - if (lineCount > 0) { - int start = l.getLineStart(0); - int end = l.getLineEnd(0); - this.next = this.current + end; - return rtrim(substr, start, end); - } else { - throw new RuntimeException("lineCount=" + lineCount + " current=" + current + - " text=" + text); - } - } - - /** returns null if there is no more text */ - CharSequence advance() { - this.first = false; - int index = this.next; - final int len = this.text.length(); - while (index < len && !TextUtils.isGraphic(this.text.charAt(index))) { - index++; - } - if (index >= len) { - return null; - } - - CharSequence substr = this.text.subSequence(index, this.text.length()); - StaticLayout l = getLayout(substr); - final int lineCount = l.getLineCount(); - int i; - for (i=0; i<lineCount; i++) { - int start = l.getLineStart(i); - int end = l.getLineEnd(i); - if (i == lineCount-1) { - this.next = len; - } else { - this.next = index + l.getLineStart(i+1); - } - CharSequence result = rtrim(substr, start, end); - if (result != null) { - this.current = index + start; - return result; - } - } - this.current = len; - return null; - } - - Segment(NotificationData n, Drawable icon, CharSequence text) { - this.notificationData = n; - this.icon = icon; - this.text = text; - int index = 0; - final int len = text.length(); - while (index < len && !TextUtils.isGraphic(text.charAt(index))) { - index++; - } - this.current = index; - this.next = index; - this.first = true; - } - }; - - private Handler mHandler = new Handler(); - private ArrayList<Segment> mSegments = new ArrayList(); - private TextPaint mPaint; - private View mTickerView; - private ImageSwitcher mIconSwitcher; - private TextSwitcher mTextSwitcher; - - Ticker(Context context, StatusBarView sb) { - mTickerView = sb.findViewById(R.id.ticker); - - mIconSwitcher = (ImageSwitcher)sb.findViewById(R.id.tickerIcon); - mIconSwitcher.setInAnimation( - AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_in)); - mIconSwitcher.setOutAnimation( - AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_out)); - - mTextSwitcher = (TextSwitcher)sb.findViewById(R.id.tickerText); - mTextSwitcher.setInAnimation( - AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_in)); - mTextSwitcher.setOutAnimation( - AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_out)); - - // Copy the paint style of one of the TextSwitchers children to use later for measuring - TextView text = (TextView)mTextSwitcher.getChildAt(0); - mPaint = text.getPaint(); - } - - void addEntry(NotificationData n, Drawable icon, CharSequence text) { - int initialCount = mSegments.size(); - - Segment newSegment = new Segment(n, icon, text); - - // prune out any preexisting ones for this notification, but not the current one. - // let that finish, even if it's the same id - for (int i=1; i<initialCount; i++) { - Segment seg = mSegments.get(i); - if (n.id == seg.notificationData.id && n.pkg.equals(seg.notificationData.pkg)) { - // just update that one to use this new data instead - mSegments.set(i, newSegment); - // and since we know initialCount != 0, just return - return ; - } - } - - mSegments.add(newSegment); - - if (initialCount == 0 && mSegments.size() > 0) { - Segment seg = mSegments.get(0); - seg.first = false; - - mIconSwitcher.setAnimateFirstView(false); - mIconSwitcher.reset(); - mIconSwitcher.setImageDrawable(seg.icon); - - mTextSwitcher.setAnimateFirstView(false); - mTextSwitcher.reset(); - mTextSwitcher.setText(seg.getText()); - - tickerStarting(); - scheduleAdvance(); - } - } - - void halt() { - mHandler.removeCallbacks(mAdvanceTicker); - mSegments.clear(); - tickerHalting(); - } - - void reflowText() { - if (mSegments.size() > 0) { - Segment seg = mSegments.get(0); - CharSequence text = seg.getText(); - mTextSwitcher.setCurrentText(text); - } - } - - private Runnable mAdvanceTicker = new Runnable() { - public void run() { - while (mSegments.size() > 0) { - Segment seg = mSegments.get(0); - - if (seg.first) { - // this makes the icon slide in for the first one for a given - // notification even if there are two notifications with the - // same icon in a row - mIconSwitcher.setImageDrawable(seg.icon); - } - CharSequence text = seg.advance(); - if (text == null) { - mSegments.remove(0); - continue; - } - mTextSwitcher.setText(text); - - scheduleAdvance(); - break; - } - if (mSegments.size() == 0) { - tickerDone(); - } - } - }; - - private void scheduleAdvance() { - mHandler.postDelayed(mAdvanceTicker, TICKER_SEGMENT_DELAY); - } - - abstract void tickerStarting(); - abstract void tickerDone(); - abstract void tickerHalting(); -} - diff --git a/services/java/com/android/server/status/TickerView.java b/services/java/com/android/server/status/TickerView.java deleted file mode 100644 index 349c7f4..0000000 --- a/services/java/com/android/server/status/TickerView.java +++ /dev/null @@ -1,23 +0,0 @@ - -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.TextSwitcher; - - -public class TickerView extends TextSwitcher -{ - Ticker mTicker; - - public TickerView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mTicker.reflowText(); - } -} - diff --git a/services/java/com/android/server/status/TrackingView.java b/services/java/com/android/server/status/TrackingView.java deleted file mode 100644 index 722d10c..0000000 --- a/services/java/com/android/server/status/TrackingView.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.android.server.status; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.Display; -import android.view.KeyEvent; -import android.view.WindowManager; -import android.widget.LinearLayout; - - -public class TrackingView extends LinearLayout { - final Display mDisplay; - StatusBarService mService; - boolean mTracking; - int mStartX, mStartY; - - public TrackingView(Context context, AttributeSet attrs) { - super(context, attrs); - mDisplay = ((WindowManager)context.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - mService.updateAvailableHeight(); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - boolean down = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_BACK: - if (down) { - mService.deactivate(); - } - return true; - } - return super.dispatchKeyEvent(event); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mService.onTrackingViewAttached(); - } -} diff --git a/services/java/com/android/server/status/package.html b/services/java/com/android/server/status/package.html deleted file mode 100755 index c9f96a6..0000000 --- a/services/java/com/android/server/status/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -{@hide} - -</body> |