summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/java/Android.mk4
-rw-r--r--services/java/com/android/server/AccessibilityManagerService.java120
-rw-r--r--services/java/com/android/server/AlarmManagerService.java126
-rw-r--r--services/java/com/android/server/AppWidgetService.java113
-rw-r--r--services/java/com/android/server/BackupManagerService.java1215
-rw-r--r--services/java/com/android/server/BatteryService.java167
-rw-r--r--services/java/com/android/server/BootReceiver.java188
-rw-r--r--services/java/com/android/server/BrickReceiver.java4
-rw-r--r--services/java/com/android/server/ConnectivityService.java491
-rw-r--r--services/java/com/android/server/DemoDataSet.java12
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java1004
-rw-r--r--services/java/com/android/server/DeviceStorageMonitorService.java87
-rw-r--r--services/java/com/android/server/DiskStatsService.java111
-rw-r--r--services/java/com/android/server/DockObserver.java168
-rw-r--r--services/java/com/android/server/DropBoxManagerService.java727
-rw-r--r--services/java/com/android/server/EntropyService.java31
-rw-r--r--services/java/com/android/server/EventLogTags.logtags139
-rw-r--r--services/java/com/android/server/FallbackCheckinService.java75
-rw-r--r--services/java/com/android/server/HeadsetObserver.java12
-rw-r--r--services/java/com/android/server/INativeDaemonConnectorCallbacks.java24
-rw-r--r--services/java/com/android/server/InputDevice.java294
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java794
-rw-r--r--services/java/com/android/server/Installer.java49
-rw-r--r--services/java/com/android/server/IntentResolver.java133
-rw-r--r--services/java/com/android/server/JournaledFile.java107
-rw-r--r--services/java/com/android/server/KeyInputQueue.java189
-rw-r--r--services/java/com/android/server/LightsService.java163
-rw-r--r--services/java/com/android/server/LocationManagerService.java423
-rw-r--r--services/java/com/android/server/MasterClearReceiver.java33
-rw-r--r--services/java/com/android/server/MountListener.java325
-rw-r--r--services/java/com/android/server/MountService.java1585
-rw-r--r--services/java/com/android/server/NativeDaemonConnector.java291
-rw-r--r--services/java/com/android/server/NativeDaemonConnectorException.java48
-rw-r--r--services/java/com/android/server/NetStatService.java56
-rw-r--r--services/java/com/android/server/NetworkManagementService.java608
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java230
-rw-r--r--services/java/com/android/server/NotificationPlayer.java338
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java231
-rw-r--r--services/java/com/android/server/PackageManagerService.java5030
-rw-r--r--services/java/com/android/server/PowerManagerService.java801
-rw-r--r--services/java/com/android/server/ProcessStats.java22
-rw-r--r--services/java/com/android/server/RandomBlock.java8
-rw-r--r--services/java/com/android/server/RecognitionManagerService.java130
-rw-r--r--services/java/com/android/server/SensorService.java200
-rw-r--r--services/java/com/android/server/ShutdownActivity.java4
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java18
-rw-r--r--services/java/com/android/server/SystemServer.java262
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java11
-rw-r--r--services/java/com/android/server/ThrottleService.java1040
-rw-r--r--services/java/com/android/server/TwilightCalculator.java123
-rw-r--r--services/java/com/android/server/UiModeManagerService.java772
-rwxr-xr-xservices/java/com/android/server/VibratorService.java (renamed from services/java/com/android/server/HardwareService.java)149
-rw-r--r--services/java/com/android/server/ViewServer.java10
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java223
-rw-r--r--services/java/com/android/server/Watchdog.java183
-rw-r--r--services/java/com/android/server/WifiService.java916
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java80
-rw-r--r--services/java/com/android/server/WindowManagerService.java2441
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java3811
-rw-r--r--services/java/com/android/server/am/AppErrorDialog.java17
-rw-r--r--services/java/com/android/server/am/AppNotRespondingDialog.java10
-rw-r--r--services/java/com/android/server/am/AppWaitingForDebuggerDialog.java3
-rw-r--r--services/java/com/android/server/am/BackupRecord.java2
-rw-r--r--services/java/com/android/server/am/BaseErrorDialog.java8
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java12
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java4
-rw-r--r--services/java/com/android/server/am/DeviceMonitor.java8
-rw-r--r--services/java/com/android/server/am/EventLogTags.logtags85
-rw-r--r--services/java/com/android/server/am/HistoryRecord.java19
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java44
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java37
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java14
-rw-r--r--services/java/com/android/server/am/UsageStatsService.java48
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java1453
-rw-r--r--services/java/com/android/server/status/AnimatedImageView.java16
-rw-r--r--services/java/com/android/server/status/CloseDragHandle.java16
-rw-r--r--services/java/com/android/server/status/DateView.java18
-rw-r--r--services/java/com/android/server/status/ExpandedView.java39
-rw-r--r--services/java/com/android/server/status/FixedSizeDrawable.java18
-rw-r--r--services/java/com/android/server/status/IconData.java18
-rw-r--r--services/java/com/android/server/status/IconMerger.java16
-rw-r--r--services/java/com/android/server/status/LatestItemView.java18
-rw-r--r--services/java/com/android/server/status/NotificationData.java18
-rw-r--r--services/java/com/android/server/status/NotificationLinearLayout.java16
-rw-r--r--services/java/com/android/server/status/NotificationViewList.java67
-rw-r--r--services/java/com/android/server/status/StatusBarException.java16
-rw-r--r--services/java/com/android/server/status/StatusBarIcon.java28
-rw-r--r--services/java/com/android/server/status/StatusBarNotification.java16
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java154
-rw-r--r--services/java/com/android/server/status/StatusBarService.java416
-rw-r--r--services/java/com/android/server/status/StatusBarView.java62
-rw-r--r--services/java/com/android/server/status/StorageNotification.java395
-rw-r--r--services/java/com/android/server/status/Ticker.java18
-rw-r--r--services/java/com/android/server/status/TickerView.java15
-rw-r--r--services/java/com/android/server/status/TrackingPatternView.java2
-rw-r--r--services/java/com/android/server/status/TrackingView.java18
-rw-r--r--services/java/com/android/server/status/UsbStorageActivity.java272
-rw-r--r--services/jni/Android.mk3
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp14
-rw-r--r--services/jni/com_android_server_LightsService.cpp (renamed from services/jni/com_android_server_HardwareService.cpp)63
-rw-r--r--services/jni/com_android_server_SensorService.cpp1
-rw-r--r--services/jni/com_android_server_VibratorService.cpp55
-rw-r--r--services/jni/onload.cpp6
-rw-r--r--services/tests/servicestests/Android.mk17
-rw-r--r--services/tests/servicestests/AndroidManifest.xml32
-rw-r--r--services/tests/servicestests/src/com/android/server/DropBoxTest.java567
-rw-r--r--services/tests/servicestests/src/com/android/server/EntropyServiceTest.java41
107 files changed, 23008 insertions, 8176 deletions
diff --git a/services/java/Android.mk b/services/java/Android.mk
index 5e912d6..934712c 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -5,7 +5,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files)
+ $(call all-subdir-java-files) \
+ com/android/server/EventLogTags.logtags \
+ com/android/server/am/EventLogTags.logtags
LOCAL_MODULE:= services
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index f67a7ae..87de79a 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -16,8 +16,7 @@
package com.android.server;
-import static android.util.Config.LOGV;
-
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.HandlerCaller.SomeArgs;
@@ -47,7 +46,8 @@ import android.os.RemoteException;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
-import android.util.Log;
+import android.util.Config;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
@@ -57,6 +57,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -137,10 +138,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
registerPackageChangeAndBootCompletedBroadcastReceiver();
registerSettingsContentObservers();
-
- synchronized (mLock) {
- populateAccessibilityServiceListLocked();
- }
}
/**
@@ -150,34 +147,83 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void registerPackageChangeAndBootCompletedBroadcastReceiver() {
Context context = mContext;
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ PackageMonitor monitor = new PackageMonitor() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onSomePackagesChanged() {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
manageServicesLocked();
+ }
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages,
+ int uid, boolean doit) {
+ synchronized (mLock) {
+ boolean changed = false;
+ Iterator<ComponentName> it = mEnabledServices.iterator();
+ while (it.hasNext()) {
+ ComponentName comp = it.next();
+ String compPkg = comp.getPackageName();
+ for (String pkg : packages) {
+ if (compPkg.equals(pkg)) {
+ if (!doit) {
+ return true;
+ }
+ it.remove();
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ it = mEnabledServices.iterator();
+ StringBuilder str = new StringBuilder();
+ while (it.hasNext()) {
+ if (str.length() > 0) {
+ str.append(':');
+ }
+ str.append(it.next().flattenToShortString());
+ }
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ str.toString());
+ manageServicesLocked();
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+ synchronized (mLock) {
+ populateAccessibilityServiceListLocked();
- if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+ // get the accessibility enabled setting on boot
mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
- updateClientsLocked();
+
+ // if accessibility is enabled inform our clients we are on
+ if (mIsEnabled) {
+ updateClientsLocked();
+ }
+
+ manageServicesLocked();
}
+
+ return;
}
+
+ super.onReceive(context, intent);
}
};
// package changes
- IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- packageFilter.addDataScheme("package");
- context.registerReceiver(broadcastReceiver, packageFilter);
+ monitor.register(context, true);
// boot completed
IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
- mContext.registerReceiver(broadcastReceiver, bootFiler);
+ mContext.registerReceiver(monitor, bootFiler);
}
/**
@@ -229,7 +275,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
client.setEnabled(mIsEnabled);
mClients.add(client);
} catch (RemoteException re) {
- Log.w(LOG_TAG, "Dead AccessibilityManagerClient: " + client, re);
+ Slog.w(LOG_TAG, "Dead AccessibilityManagerClient: " + client, re);
}
}
}
@@ -263,13 +309,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
service.mServiceInterface.onInterrupt();
} catch (RemoteException re) {
if (re instanceof DeadObjectException) {
- Log.w(LOG_TAG, "Dead " + service.mService + ". Cleaning up.");
+ Slog.w(LOG_TAG, "Dead " + service.mService + ". Cleaning up.");
if (removeDeadServiceLocked(service)) {
count--;
i--;
}
} else {
- Log.e(LOG_TAG, "Error during sending interrupt request to "
+ Slog.e(LOG_TAG, "Error during sending interrupt request to "
+ service.mService, re);
}
}
@@ -297,7 +343,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
return;
default:
- Log.w(LOG_TAG, "Unknown message type: " + message.what);
+ Slog.w(LOG_TAG, "Unknown message type: " + message.what);
}
}
@@ -404,17 +450,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
try {
listener.onAccessibilityEvent(event);
- if (LOGV) {
- Log.i(LOG_TAG, "Event " + event + " sent to " + listener);
+ if (Config.DEBUG) {
+ Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
}
} catch (RemoteException re) {
if (re instanceof DeadObjectException) {
- Log.w(LOG_TAG, "Dead " + service.mService + ". Cleaning up.");
+ Slog.w(LOG_TAG, "Dead " + service.mService + ". Cleaning up.");
synchronized (mLock) {
removeDeadServiceLocked(service);
}
} else {
- Log.e(LOG_TAG, "Error during sending " + event + " to " + service.mService, re);
+ Slog.e(LOG_TAG, "Error during sending " + event + " to " + service.mService, re);
}
}
}
@@ -429,8 +475,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mServices.remove(service);
mHandler.removeMessages(service.mId);
- if (LOGV) {
- Log.i(LOG_TAG, "Dead service " + service.mService + " removed");
+ if (Config.DEBUG) {
+ Slog.i(LOG_TAG, "Dead service " + service.mService + " removed");
}
if (mServices.isEmpty()) {
@@ -524,8 +570,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(servicesValue);
while (splitter.hasNext()) {
- ComponentName enabledService = ComponentName.unflattenFromString(splitter.next());
- enabledServices.add(enabledService);
+ String str = splitter.next();
+ if (str == null || str.length() <= 0) {
+ continue;
+ }
+ ComponentName enabledService = ComponentName.unflattenFromString(str);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
}
}
}
@@ -542,6 +594,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
List<Service> services = mServices;
+ boolean isEnabled = mIsEnabled;
for (int i = 0, count = installedServices.size(); i < count; i++) {
ServiceInfo intalledService = installedServices.get(i);
@@ -549,7 +602,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
intalledService.name);
Service service = componentNameToServiceMap.get(componentName);
- if (enabledServices.contains(componentName)) {
+ if (isEnabled && enabledServices.contains(componentName)) {
if (service == null) {
new Service(componentName).bind();
}
@@ -573,6 +626,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
} catch (RemoteException re) {
mClients.remove(i);
count--;
+ i--;
}
}
}
@@ -668,7 +722,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
} catch (RemoteException re) {
- Log.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
+ Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
}
}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 8d86219..e088417 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.IAlarmManager;
@@ -36,7 +37,7 @@ import android.os.SystemProperties;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -127,8 +128,9 @@ class AlarmManagerService extends IAlarmManager.Stub {
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);
+ Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);
// now that we have initied the driver schedule the alarm
mClockReceiver= new ClockReceiver();
@@ -139,7 +141,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (mDescriptor != -1) {
mWaitThread.start();
} else {
- Log.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
+ Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
}
@@ -158,7 +160,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
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");
+ Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
}
synchronized (mLock) {
@@ -171,7 +173,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
// Remove this alarm if already scheduled.
removeLocked(operation);
- if (localLOGV) Log.v(TAG, "set: " + alarm);
+ if (localLOGV) Slog.v(TAG, "set: " + alarm);
int index = addAlarmLocked(alarm);
if (index == 0) {
@@ -183,7 +185,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
public void setInexactRepeating(int type, long triggerAtTime, long interval,
PendingIntent operation) {
if (operation == null) {
- Log.w(TAG, "setInexactRepeating ignored because there is no intent");
+ Slog.w(TAG, "setInexactRepeating ignored because there is no intent");
return;
}
@@ -235,12 +237,20 @@ class AlarmManagerService extends IAlarmManager.Stub {
// 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
+ if (localLOGV) Slog.v(TAG, "setInexactRepeating: interval=" + interval
+ " bucketTime=" + bucketTime);
mInexactDeliveryTimes[intervalSlot] = bucketTime;
setRepeating(type, bucketTime, interval, operation);
}
+ public void setTime(long millis) {
+ mContext.enforceCallingOrSelfPermission(
+ "android.permission.SET_TIME",
+ "setTime");
+
+ SystemClock.setCurrentTimeMillis(millis);
+ }
+
public void setTimeZone(String tz) {
mContext.enforceCallingOrSelfPermission(
"android.permission.SET_TIME_ZONE",
@@ -254,7 +264,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
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());
+ if (localLOGV) Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
timeZoneWasChanged = true;
SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
}
@@ -272,6 +282,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (timeZoneWasChanged) {
Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra("time-zone", zone.getID());
mContext.sendBroadcast(intent);
}
@@ -334,6 +345,22 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
+ public boolean lookForPackageLocked(String packageName) {
+ return lookForPackageLocked(mRtcWakeupAlarms, packageName)
+ || lookForPackageLocked(mRtcAlarms, packageName)
+ || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
+ || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
+ }
+
+ private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
+ for (int i=alarmList.size()-1; i>=0; i--) {
+ if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private ArrayList<Alarm> getAlarmList(int type) {
switch (type) {
case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms;
@@ -352,18 +379,18 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (index < 0) {
index = 0 - index - 1;
}
- if (localLOGV) Log.v(TAG, "Adding alarm " + alarm + " at " + index);
+ if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
alarmList.add(index, alarm);
if (localLOGV) {
// Display the list of alarms for this alarm type
- Log.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
+ Slog.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
int position = 0;
for (Alarm a : alarmList) {
Time time = new Time();
time.set(a.when);
String timeStr = time.format("%b %d %I:%M:%S %p");
- Log.v(TAG, position + ": " + timeStr
+ Slog.v(TAG, position + ": " + timeStr
+ " " + a.operation.getTargetPackage());
position += 1;
}
@@ -373,7 +400,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
public long timeToNextAlarm() {
- long nextAlarm = 0xfffffffffffffffl;
+ long nextAlarm = Long.MAX_VALUE;
synchronized (mLock) {
for (int i=AlarmManager.RTC_WAKEUP;
i<=AlarmManager.ELAPSED_REALTIME; i++) {
@@ -393,7 +420,18 @@ class AlarmManagerService extends IAlarmManager.Stub {
{
if (mDescriptor != -1)
{
- set(mDescriptor, alarm.type, (alarm.when * 1000 * 1000));
+ // The kernel never triggers alarms with negative wakeup times
+ // so we ensure they are positive.
+ long alarmSeconds, alarmNanoseconds;
+ if (alarm.when < 0) {
+ alarmSeconds = 0;
+ alarmNanoseconds = 0;
+ } else {
+ alarmSeconds = alarm.when / 1000;
+ alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
+ }
+
+ set(mDescriptor, alarm.type, alarmSeconds, alarmNanoseconds);
}
else
{
@@ -472,7 +510,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
private native int init();
private native void close(int fd);
- private native void set(int fd, int type, long nanoseconds);
+ private native void set(int fd, int type, long seconds, long nanoseconds);
private native int waitForAlarm(int fd);
private native int setKernelTimezone(int fd, int minuteswest);
@@ -487,7 +525,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
{
Alarm alarm = it.next();
- if (localLOGV) Log.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
+ if (localLOGV) Slog.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
if (alarm.when > now) {
// don't fire alarms in the future
@@ -499,14 +537,14 @@ class AlarmManagerService extends IAlarmManager.Stub {
// the Calendar app with a reminder that is in the past. In that
// case, the reminder alarm will fire immediately.
if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
- Log.v(TAG, "alarm is late! alarm time: " + alarm.when
+ Slog.v(TAG, "alarm is late! alarm time: " + alarm.when
+ " now: " + now + " delay (in seconds): "
+ (now - alarm.when) / 1000);
}
// 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);
+ if (localLOGV) Slog.v(TAG, "Alarm triggering: " + alarm);
alarm.count = 1;
if (alarm.repeatInterval > 0) {
// this adjustment will be zero if we're late by
@@ -609,13 +647,15 @@ class AlarmManagerService extends IAlarmManager.Stub {
if ((result & TIME_CHANGED_MASK) != 0) {
remove(mTimeTickSender);
mClockReceiver.scheduleTimeTickEvent();
- mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
+ Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ mContext.sendBroadcast(intent);
}
synchronized (mLock) {
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Checking for alarms... rtc=" + nowRTC
+ ", elapsed=" + nowELAPSED);
@@ -636,7 +676,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
while (it.hasNext()) {
Alarm alarm = it.next();
try {
- if (localLOGV) Log.v(TAG, "sending alarm " + alarm);
+ if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
alarm.operation.send(mContext, 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
@@ -667,7 +707,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
remove(alarm.operation);
}
} catch (RuntimeException e) {
- Log.w(TAG, "Failure sending alarm.", e);
+ Slog.w(TAG, "Failure sending alarm.", e);
}
}
}
@@ -766,18 +806,50 @@ class AlarmManagerService extends IAlarmManager.Stub {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
+ // Register for events related to sdcard installation.
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(this, sdFilter);
}
@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);
+ String action = intent.getAction();
+ String pkgList[] = null;
+ if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ for (String packageName : pkgList) {
+ if (lookForPackageLocked(packageName)) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ }
+ return;
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else {
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ // This package is being updated; don't kill its alarms.
+ return;
+ }
+ Uri data = intent.getData();
+ if (data != null) {
+ String pkg = data.getSchemeSpecificPart();
+ if (pkg != null) {
+ pkgList = new String[]{pkg};
+ }
+ }
+ }
+ if (pkgList != null && (pkgList.length > 0)) {
+ for (String pkg : pkgList) {
+ removeLocked(pkg);
+ mBroadcastStats.remove(pkg);
+ }
}
}
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 6bf7102..24526af 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.net.Uri;
@@ -38,7 +39,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -145,6 +146,11 @@ class AppWidgetService extends IAppWidgetService.Stub
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
+ // Register for events related to sdcard installation.
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mBroadcastReceiver, sdFilter);
}
@Override
@@ -423,7 +429,7 @@ class AppWidgetService extends IAppWidgetService.Stub
synchronized (mAppWidgetIds) {
Provider p = lookupProviderLocked(provider);
if (p == null) {
- Log.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
+ Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
return;
}
ArrayList<AppWidgetId> instances = p.instances;
@@ -518,10 +524,11 @@ class AppWidgetService extends IAppWidgetService.Stub
}
Provider lookupProviderLocked(ComponentName provider) {
+ final String className = provider.getClassName();
final int N = mInstalledProviders.size();
for (int i=0; i<N; i++) {
Provider p = mInstalledProviders.get(i);
- if (p.info.provider.equals(provider)) {
+ if (p.info.provider.equals(provider) || className.equals(p.info.oldName)) {
return p;
}
}
@@ -568,7 +575,7 @@ class AppWidgetService extends IAppWidgetService.Stub
List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
- final int N = broadcastReceivers.size();
+ final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
for (int i=0; i<N; i++) {
ResolveInfo ri = broadcastReceivers.get(i);
addProviderLocked(ri);
@@ -678,7 +685,7 @@ class AppWidgetService extends IAppWidgetService.Stub
parser = activityInfo.loadXmlMetaData(mPackageManager,
AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
if (parser == null) {
- Log.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
+ Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
+ "AppWidget provider '" + component + '\'');
return null;
}
@@ -693,18 +700,25 @@ class AppWidgetService extends IAppWidgetService.Stub
String nodeName = parser.getName();
if (!"appwidget-provider".equals(nodeName)) {
- Log.w(TAG, "Meta-data does not start with appwidget-provider tag for"
+ Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
+ " AppWidget provider '" + component + '\'');
return null;
}
p = new Provider();
AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
+ // If metaData was null, we would have returned earlier when getting
+ // the parser No need to do the check here
+ info.oldName = activityInfo.metaData.getString(
+ AppWidgetManager.META_DATA_APPWIDGET_OLD_NAME);
info.provider = component;
p.uid = activityInfo.applicationInfo.uid;
- TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ Resources res = mPackageManager.getResourcesForApplication(
+ activityInfo.applicationInfo);
+
+ TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AppWidgetProviderInfo);
// These dimensions has to be resolved in the application's context.
@@ -732,7 +746,7 @@ class AppWidgetService extends IAppWidgetService.Stub
// 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 AppWidget provider '" + component + '\'', e);
+ Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
return null;
} finally {
if (parser != null) parser.close();
@@ -824,7 +838,7 @@ class AppWidgetService extends IAppWidgetService.Stub
}
if (!writeStateToFileLocked(temp)) {
- Log.w(TAG, "Failed to persist new settings");
+ Slog.w(TAG, "Failed to persist new settings");
return;
}
@@ -926,6 +940,16 @@ class AppWidgetService extends IAppWidgetService.Stub
// as before?
String pkg = parser.getAttributeValue(null, "pkg");
String cl = parser.getAttributeValue(null, "cl");
+
+ final PackageManager packageManager = mContext.getPackageManager();
+ try {
+ packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ String[] pkgs = packageManager.currentToCanonicalPackageNames(
+ new String[] { pkg });
+ pkg = pkgs[0];
+ }
+
Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
if (p == null && mSafeMode) {
// if we're in safe mode, make a temporary one
@@ -975,7 +999,7 @@ class AppWidgetService extends IAppWidgetService.Stub
int pIndex = Integer.parseInt(providerString, 16);
id.provider = loadedProviders.get(pIndex);
if (false) {
- Log.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
+ Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
+ pIndex + " which is " + id.provider);
}
if (id.provider == null) {
@@ -1002,15 +1026,15 @@ class AppWidgetService extends IAppWidgetService.Stub
} while (type != XmlPullParser.END_DOCUMENT);
success = true;
} catch (NullPointerException e) {
- Log.w(TAG, "failed parsing " + file, e);
+ Slog.w(TAG, "failed parsing " + file, e);
} catch (NumberFormatException e) {
- Log.w(TAG, "failed parsing " + file, e);
+ Slog.w(TAG, "failed parsing " + file, e);
} catch (XmlPullParserException e) {
- Log.w(TAG, "failed parsing " + file, e);
+ Slog.w(TAG, "failed parsing " + file, e);
} catch (IOException e) {
- Log.w(TAG, "failed parsing " + file, e);
+ Slog.w(TAG, "failed parsing " + file, e);
} catch (IndexOutOfBoundsException e) {
- Log.w(TAG, "failed parsing " + file, e);
+ Slog.w(TAG, "failed parsing " + file, e);
}
try {
if (stream != null) {
@@ -1050,7 +1074,7 @@ class AppWidgetService extends IAppWidgetService.Stub
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- //Log.d(TAG, "received " + action);
+ //Slog.d(TAG, "received " + action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
sendInitialBroadcasts();
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -1070,36 +1094,55 @@ class AppWidgetService extends IAppWidgetService.Stub
}
}
} else {
- Uri uri = intent.getData();
- if (uri == null) {
- return;
+ boolean added = false;
+ String pkgList[] = null;
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ added = true;
+ } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ added = false;
+ } else {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ if (pkgName == null) {
+ return;
+ }
+ pkgList = new String[] { pkgName };
+ added = Intent.ACTION_PACKAGE_ADDED.equals(action);
}
- String pkgName = uri.getSchemeSpecificPart();
- if (pkgName == null) {
+ if (pkgList == null || pkgList.length == 0) {
return;
}
-
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (added) {
synchronized (mAppWidgetIds) {
Bundle extras = intent.getExtras();
if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
- // The package was just upgraded
- updateProvidersForPackageLocked(pkgName);
+ for (String pkgName : pkgList) {
+ // The package was just upgraded
+ updateProvidersForPackageLocked(pkgName);
+ }
} else {
// The package was just added
- addProvidersForPackageLocked(pkgName);
+ for (String pkgName : pkgList) {
+ addProvidersForPackageLocked(pkgName);
+ }
}
saveStateLocked();
}
- }
- else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ } else {
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 (mAppWidgetIds) {
- removeProvidersForPackageLocked(pkgName);
- saveStateLocked();
+ for (String pkgName : pkgList) {
+ removeProvidersForPackageLocked(pkgName);
+ saveStateLocked();
+ }
}
}
}
@@ -1107,14 +1150,13 @@ class AppWidgetService extends IAppWidgetService.Stub
}
};
- // 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(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.setPackage(pkgName);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
- final int N = broadcastReceivers.size();
+ final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
for (int i=0; i<N; i++) {
ResolveInfo ri = broadcastReceivers.get(i);
ActivityInfo ai = ri.activityInfo;
@@ -1125,16 +1167,15 @@ class AppWidgetService extends IAppWidgetService.Stub
}
}
- // 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<String>();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.setPackage(pkgName);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
// add the missing ones and collect which ones to keep
- int N = broadcastReceivers.size();
+ int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
for (int i=0; i<N; i++) {
ResolveInfo ri = broadcastReceivers.get(i);
ActivityInfo ai = ri.activityInfo;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c3b591e..d67dde0 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -17,11 +17,16 @@
package com.android.server;
import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
import android.app.PendingIntent;
+import android.app.backup.RestoreSet;
+import android.app.backup.IBackupManager;
+import android.app.backup.IRestoreObserver;
+import android.app.backup.IRestoreSession;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -30,53 +35,51 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
-import android.provider.Settings;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
-
-import android.backup.IBackupManager;
-import android.backup.IRestoreObserver;
-import android.backup.IRestoreSession;
-import android.backup.RestoreSet;
+import android.util.SparseIntArray;
import com.android.internal.backup.BackupConstants;
-import com.android.internal.backup.LocalTransport;
import com.android.internal.backup.IBackupTransport;
-
-import com.android.server.PackageManagerBackupAgent;
+import com.android.internal.backup.LocalTransport;
import com.android.server.PackageManagerBackupAgent.Metadata;
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
-import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -93,44 +96,38 @@ class BackupManagerService extends IBackupManager.Stub {
// the first backup pass.
private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
- private static final String RUN_BACKUP_ACTION = "android.backup.intent.RUN";
- private static final String RUN_INITIALIZE_ACTION = "android.backup.intent.INIT";
- private static final String RUN_CLEAR_ACTION = "android.backup.intent.CLEAR";
+ private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
+ private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
+ private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
private static final int MSG_RUN_INITIALIZE = 5;
-
- // Event tags -- see system/core/logcat/event-log-tags
- private static final int BACKUP_DATA_CHANGED_EVENT = 2820;
- private static final int BACKUP_START_EVENT = 2821;
- private static final int BACKUP_TRANSPORT_FAILURE_EVENT = 2822;
- private static final int BACKUP_AGENT_FAILURE_EVENT = 2823;
- private static final int BACKUP_PACKAGE_EVENT = 2824;
- private static final int BACKUP_SUCCESS_EVENT = 2825;
- private static final int BACKUP_RESET_EVENT = 2826;
- private static final int BACKUP_INITIALIZE_EVENT = 2827;
-
- private static final int RESTORE_START_EVENT = 2830;
- private static final int RESTORE_TRANSPORT_FAILURE_EVENT = 2831;
- private static final int RESTORE_AGENT_FAILURE_EVENT = 2832;
- private static final int RESTORE_PACKAGE_EVENT = 2833;
- private static final int RESTORE_SUCCESS_EVENT = 2834;
+ private static final int MSG_RUN_GET_RESTORE_SETS = 6;
+ private static final int MSG_TIMEOUT = 7;
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
+ // Timeout intervals for agent backup & restore operations
+ static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
+ static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
+
private Context mContext;
private PackageManager mPackageManager;
+ IPackageManager mPackageManagerBinder;
private IActivityManager mActivityManager;
private PowerManager mPowerManager;
private AlarmManager mAlarmManager;
+ IBackupManager mBackupManagerBinder;
boolean mEnabled; // access to this is synchronized on 'this'
boolean mProvisioned;
+ boolean mAutoRestore;
PowerManager.WakeLock mWakelock;
- final BackupHandler mBackupHandler = new BackupHandler();
+ HandlerThread mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
+ BackupHandler mBackupHandler;
PendingIntent mRunBackupIntent, mRunInitIntent;
BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
// map UIDs to the set of backup client services within that UID's app set
@@ -167,7 +164,6 @@ class BackupManagerService extends IBackupManager.Stub {
final Object mAgentConnectLock = new Object();
IBackupAgent mConnectedAgent;
volatile boolean mConnecting;
- volatile boolean mBackupOrRestoreInProgress = false;
volatile long mLastBackupPass;
volatile long mNextBackupPass;
@@ -180,17 +176,43 @@ class BackupManagerService extends IBackupManager.Stub {
= new HashMap<String,IBackupTransport>();
String mCurrentTransport;
IBackupTransport mLocalTransport, mGoogleTransport;
- RestoreSession mActiveRestoreSession;
+ ActiveRestoreSession mActiveRestoreSession;
+
+ class RestoreGetSetsParams {
+ public IBackupTransport transport;
+ public ActiveRestoreSession session;
+ public IRestoreObserver observer;
+
+ RestoreGetSetsParams(IBackupTransport _transport, ActiveRestoreSession _session,
+ IRestoreObserver _observer) {
+ transport = _transport;
+ session = _session;
+ observer = _observer;
+ }
+ }
class RestoreParams {
public IBackupTransport transport;
public IRestoreObserver observer;
public long token;
+ public PackageInfo pkgInfo;
+ public int pmToken; // in post-install restore, the PM's token for this transaction
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
+ long _token, PackageInfo _pkg, int _pmToken) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ pkgInfo = _pkg;
+ pmToken = _pmToken;
+ }
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
transport = _transport;
observer = _obs;
token = _token;
+ pkgInfo = null;
+ pmToken = 0;
}
}
@@ -204,35 +226,203 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Bookkeeping of in-flight operations for timeout etc. purposes. The operation
+ // token is the index of the entry in the pending-operations list.
+ static final int OP_PENDING = 0;
+ static final int OP_ACKNOWLEDGED = 1;
+ static final int OP_TIMEOUT = -1;
+
+ final SparseIntArray mCurrentOperations = new SparseIntArray();
+ final Object mCurrentOpLock = new Object();
+ final Random mTokenGenerator = new Random();
+
// Where we keep our journal files and other bookkeeping
File mBaseStateDir;
File mDataDir;
File mJournalDir;
File mJournal;
- // Keep a log of all the apps we've ever backed up
+ // Keep a log of all the apps we've ever backed up, and what the
+ // dataset tokens are for both the current backup dataset and
+ // the ancestral dataset.
private File mEverStored;
HashSet<String> mEverStoredApps = new HashSet<String>();
+ static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1; // increment when the schema changes
+ File mTokenFile;
+ Set<String> mAncestralPackages = null;
+ long mAncestralToken = 0;
+ long mCurrentToken = 0;
+
// Persistently track the need to do a full init
static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
HashSet<String> mPendingInits = new HashSet<String>(); // transport names
- volatile boolean mInitInProgress = false;
+
+ // ----- Asynchronous backup/restore handler thread -----
+
+ private class BackupHandler extends Handler {
+ public BackupHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+
+ switch (msg.what) {
+ case MSG_RUN_BACKUP:
+ {
+ mLastBackupPass = System.currentTimeMillis();
+ mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
+
+ IBackupTransport transport = getTransport(mCurrentTransport);
+ if (transport == null) {
+ Slog.v(TAG, "Backup requested but no transport available");
+ mWakelock.release();
+ break;
+ }
+
+ // snapshot the pending-backup set and work on that
+ ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
+ File oldJournal = mJournal;
+ synchronized (mQueueLock) {
+ // Do we have any work to do? Construct the work queue
+ // then release the synchronization lock to actually run
+ // the backup.
+ if (mPendingBackups.size() > 0) {
+ for (BackupRequest b: mPendingBackups.values()) {
+ queue.add(b);
+ }
+ if (DEBUG) Slog.v(TAG, "clearing pending backups");
+ mPendingBackups.clear();
+
+ // Start a new backup-queue journal file too
+ mJournal = null;
+
+ }
+ }
+
+ if (queue.size() > 0) {
+ // At this point, we have started a new journal file, and the old
+ // file identity is being passed to the backup processing thread.
+ // When it completes successfully, that old journal file will be
+ // deleted. If we crash prior to that, the old journal is parsed
+ // at next boot and the journaled requests fulfilled.
+ (new PerformBackupTask(transport, queue, oldJournal)).run();
+ } else {
+ Slog.v(TAG, "Backup requested but nothing pending");
+ mWakelock.release();
+ }
+ break;
+ }
+
+ case MSG_RUN_FULL_BACKUP:
+ break;
+
+ case MSG_RUN_RESTORE:
+ {
+ RestoreParams params = (RestoreParams)msg.obj;
+ Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
+ (new PerformRestoreTask(params.transport, params.observer,
+ params.token, params.pkgInfo, params.pmToken)).run();
+ break;
+ }
+
+ case MSG_RUN_CLEAR:
+ {
+ ClearParams params = (ClearParams)msg.obj;
+ (new PerformClearTask(params.transport, params.packageInfo)).run();
+ break;
+ }
+
+ case MSG_RUN_INITIALIZE:
+ {
+ HashSet<String> queue;
+
+ // Snapshot the pending-init queue and work on that
+ synchronized (mQueueLock) {
+ queue = new HashSet<String>(mPendingInits);
+ mPendingInits.clear();
+ }
+
+ (new PerformInitializeTask(queue)).run();
+ break;
+ }
+
+ case MSG_RUN_GET_RESTORE_SETS:
+ {
+ // Like other async operations, this is entered with the wakelock held
+ RestoreSet[] sets = null;
+ RestoreGetSetsParams params = (RestoreGetSetsParams)msg.obj;
+ try {
+ sets = params.transport.getAvailableRestoreSets();
+ // cache the result in the active session
+ synchronized (params.session) {
+ params.session.mRestoreSets = sets;
+ }
+ if (sets == null) EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
+ } catch (Exception e) {
+ Slog.e(TAG, "Error from transport getting set list");
+ } finally {
+ if (params.observer != null) {
+ try {
+ params.observer.restoreSetsAvailable(sets);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to report listing to observer");
+ } catch (Exception e) {
+ Slog.e(TAG, "Restore observer threw", e);
+ }
+ }
+
+ mWakelock.release();
+ }
+ break;
+ }
+
+ case MSG_TIMEOUT:
+ {
+ synchronized (mCurrentOpLock) {
+ final int token = msg.arg1;
+ int state = mCurrentOperations.get(token, OP_TIMEOUT);
+ if (state == OP_PENDING) {
+ if (DEBUG) Slog.v(TAG, "TIMEOUT: token=" + token);
+ mCurrentOperations.put(token, OP_TIMEOUT);
+ }
+ mCurrentOpLock.notifyAll();
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // ----- Main service implementation -----
public BackupManagerService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
+ mPackageManagerBinder = ActivityThread.getPackageManager();
mActivityManager = ActivityManagerNative.getDefault();
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mBackupManagerBinder = asInterface(asBinder());
+
+ // spin up the backup/restore handler thread
+ mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
+ mHandlerThread.start();
+ mBackupHandler = new BackupHandler(mHandlerThread.getLooper());
+
// Set up our bookkeeping
boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.BACKUP_ENABLED, 0) != 0;
mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
+ mAutoRestore = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
+ // If Encrypted file systems is enabled or disabled, this call will return the
+ // correct directory.
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
+ mBaseStateDir.mkdirs();
mDataDir = Environment.getDownloadCacheDirectory();
// Alarm receivers for scheduled backups & initialization operations
@@ -284,15 +474,30 @@ class BackupManagerService extends IBackupManager.Stub {
if ("".equals(mCurrentTransport)) {
mCurrentTransport = null;
}
- if (DEBUG) Log.v(TAG, "Starting with transport " + mCurrentTransport);
+ if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
// Attach to the Google backup transport. When this comes up, it will set
// itself as the current transport because we explicitly reset mCurrentTransport
// to null.
- Intent intent = new Intent().setComponent(new ComponentName(
- "com.google.android.backup",
- "com.google.android.backup.BackupTransportService"));
- context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
+ ComponentName transportComponent = new ComponentName("com.google.android.backup",
+ "com.google.android.backup.BackupTransportService");
+ try {
+ // If there's something out there that is supposed to be the Google
+ // backup transport, make sure it's legitimately part of the OS build
+ // and not an app lying about its package name.
+ ApplicationInfo info = mPackageManager.getApplicationInfo(
+ transportComponent.getPackageName(), 0);
+ if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (DEBUG) Slog.v(TAG, "Binding to Google transport");
+ Intent intent = new Intent().setComponent(transportComponent);
+ context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
+ } else {
+ Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
+ }
+ } catch (PackageManager.NameNotFoundException nnf) {
+ // No such package? No binding.
+ if (DEBUG) Slog.v(TAG, "Google transport not present");
+ }
// Now that we know about valid backup participants, parse any
// leftover journal files into the pending backup set
@@ -312,22 +517,19 @@ class BackupManagerService extends IBackupManager.Stub {
if (mPendingInits.size() > 0) {
// If there are pending init operations, we process those
// and then settle into the usual periodic backup schedule.
- if (DEBUG) Log.v(TAG, "Init pending at scheduled backup");
+ if (DEBUG) Slog.v(TAG, "Init pending at scheduled backup");
try {
mAlarmManager.cancel(mRunInitIntent);
mRunInitIntent.send();
} catch (PendingIntent.CanceledException ce) {
- Log.e(TAG, "Run init intent cancelled");
+ Slog.e(TAG, "Run init intent cancelled");
// can't really do more than bail here
}
} else {
- // Don't run backups now if we're disabled, not yet
- // fully set up, in the middle of a backup already,
- // or racing with an initialize pass.
- if (mEnabled && mProvisioned
- && !mBackupOrRestoreInProgress && !mInitInProgress) {
- if (DEBUG) Log.v(TAG, "Running a backup pass");
- mBackupOrRestoreInProgress = true;
+ // Don't run backups now if we're disabled or not yet
+ // fully set up.
+ if (mEnabled && mProvisioned) {
+ if (DEBUG) Slog.v(TAG, "Running a backup pass");
// Acquire the wakelock and pass it to the backup thread. it will
// be released once backup concludes.
@@ -336,8 +538,7 @@ class BackupManagerService extends IBackupManager.Stub {
Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
mBackupHandler.sendMessage(msg);
} else {
- Log.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned
- + " b=" + mBackupOrRestoreInProgress + " i=" + mInitInProgress);
+ Slog.w(TAG, "Backup pass but e=" + mEnabled + " p=" + mProvisioned);
}
}
}
@@ -349,8 +550,7 @@ class BackupManagerService extends IBackupManager.Stub {
public void onReceive(Context context, Intent intent) {
if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
synchronized (mQueueLock) {
- if (DEBUG) Log.v(TAG, "Running a device init");
- mInitInProgress = true;
+ if (DEBUG) Slog.v(TAG, "Running a device init");
// Acquire the wakelock and pass it to the init thread. it will
// be released once init concludes.
@@ -364,7 +564,32 @@ class BackupManagerService extends IBackupManager.Stub {
}
private void initPackageTracking() {
- if (DEBUG) Log.v(TAG, "Initializing package tracking");
+ if (DEBUG) Slog.v(TAG, "Initializing package tracking");
+
+ // Remember our ancestral dataset
+ mTokenFile = new File(mBaseStateDir, "ancestral");
+ try {
+ RandomAccessFile tf = new RandomAccessFile(mTokenFile, "r");
+ int version = tf.readInt();
+ if (version == CURRENT_ANCESTRAL_RECORD_VERSION) {
+ mAncestralToken = tf.readLong();
+ mCurrentToken = tf.readLong();
+
+ int numPackages = tf.readInt();
+ if (numPackages >= 0) {
+ mAncestralPackages = new HashSet<String>();
+ for (int i = 0; i < numPackages; i++) {
+ String pkgName = tf.readUTF();
+ mAncestralPackages.add(pkgName);
+ }
+ }
+ }
+ } catch (FileNotFoundException fnf) {
+ // Probably innocuous
+ Slog.v(TAG, "No ancestral data");
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to read token file", e);
+ }
// Keep a log of what apps we've ever backed up. Because we might have
// rebooted in the middle of an operation that was removing something from
@@ -396,20 +621,20 @@ class BackupManagerService extends IBackupManager.Stub {
info = mPackageManager.getPackageInfo(pkg, 0);
mEverStoredApps.add(pkg);
temp.writeUTF(pkg);
- if (DEBUG) Log.v(TAG, " + " + pkg);
+ if (DEBUG) Slog.v(TAG, " + " + pkg);
} catch (NameNotFoundException e) {
// nope, this package was uninstalled; don't include it
- if (DEBUG) Log.v(TAG, " - " + pkg);
+ if (DEBUG) Slog.v(TAG, " - " + pkg);
}
}
} catch (EOFException e) {
// Once we've rewritten the backup history log, atomically replace the
// old one with the new one then reopen the file for continuing use.
if (!tempProcessedFile.renameTo(mEverStored)) {
- Log.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
+ Slog.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
}
} catch (IOException e) {
- Log.e(TAG, "Error in processed file", e);
+ Slog.e(TAG, "Error in processed file", e);
} finally {
try { if (temp != null) temp.close(); } catch (IOException e) {}
try { if (in != null) in.close(); } catch (IOException e) {}
@@ -423,6 +648,11 @@ class BackupManagerService extends IBackupManager.Stub {
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
+ // Register for events related to sdcard installation.
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mBroadcastReceiver, sdFilter);
}
private void parseLeftoverJournals() {
@@ -433,17 +663,17 @@ class BackupManagerService extends IBackupManager.Stub {
// backup.
RandomAccessFile in = null;
try {
- Log.i(TAG, "Found stale backup journal, scheduling:");
+ Slog.i(TAG, "Found stale backup journal, scheduling:");
in = new RandomAccessFile(f, "r");
while (true) {
String packageName = in.readUTF();
- Log.i(TAG, " + " + packageName);
+ Slog.i(TAG, " + " + packageName);
dataChanged(packageName);
}
} catch (EOFException e) {
// no more data; we're done
} catch (Exception e) {
- Log.e(TAG, "Can't read " + f, e);
+ Slog.e(TAG, "Can't read " + f, e);
} finally {
// close/delete the file
try { if (in != null) in.close(); } catch (IOException e) {}
@@ -456,7 +686,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Maintain persistent state around whether need to do an initialize operation.
// Must be called with the queue lock held.
void recordInitPendingLocked(boolean isPending, String transportName) {
- if (DEBUG) Log.i(TAG, "recordInitPendingLocked: " + isPending
+ if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
+ " on transport " + transportName);
try {
IBackupTransport transport = getTransport(transportName);
@@ -493,6 +723,9 @@ class BackupManagerService extends IBackupManager.Stub {
mEverStoredApps.clear();
mEverStored.delete();
+ mCurrentToken = 0;
+ writeRestoreTokens();
+
// Remove all the state files
for (File sf : stateFileDir.listFiles()) {
// ... but don't touch the needs-init sentinel
@@ -513,11 +746,21 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- // Add a transport to our set of available backends
+ // Add a transport to our set of available backends. If 'transport' is null, this
+ // is an unregistration, and the transport's entry is removed from our bookkeeping.
private void registerTransport(String name, IBackupTransport transport) {
synchronized (mTransports) {
- if (DEBUG) Log.v(TAG, "Registering transport " + name + " = " + transport);
- mTransports.put(name, transport);
+ if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport);
+ if (transport != null) {
+ mTransports.put(name, transport);
+ } else {
+ mTransports.remove(name);
+ if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
+ mCurrentTransport = null;
+ }
+ // Nothing further to do in the unregistration case
+ return;
+ }
}
// If the init sentinel file exists, we need to be sure to perform the init
@@ -547,37 +790,55 @@ class BackupManagerService extends IBackupManager.Stub {
// ----- Track installation/removal of packages -----
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "Received broadcast " + intent);
+ if (DEBUG) Slog.d(TAG, "Received broadcast " + intent);
- Uri uri = intent.getData();
- if (uri == null) {
- return;
+ String action = intent.getAction();
+ boolean replacing = false;
+ boolean added = false;
+ Bundle extras = intent.getExtras();
+ String pkgList[] = null;
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ if (pkgName != null) {
+ pkgList = new String[] { pkgName };
+ }
+ added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+ replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ added = true;
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ added = false;
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
- String pkgName = uri.getSchemeSpecificPart();
- if (pkgName == null) {
+ if (pkgList == null || pkgList.length == 0) {
return;
}
-
- String action = intent.getAction();
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (added) {
synchronized (mBackupParticipants) {
- Bundle extras = intent.getExtras();
- if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
- // The package was just upgraded
- updatePackageParticipantsLocked(pkgName);
- } else {
- // The package was just added
- addPackageParticipantsLocked(pkgName);
+ for (String pkgName : pkgList) {
+ if (replacing) {
+ // The package was just upgraded
+ updatePackageParticipantsLocked(pkgName);
+ } else {
+ // The package was just added
+ addPackageParticipantsLocked(pkgName);
+ }
}
}
- }
- else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- Bundle extras = intent.getExtras();
- if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ } else {
+ if (replacing) {
// The package is being updated. We'll receive a PACKAGE_ADDED shortly.
} else {
synchronized (mBackupParticipants) {
- removePackageParticipantsLocked(pkgName);
+ for (String pkgName : pkgList) {
+ removePackageParticipantsLocked(pkgName);
+ }
}
}
}
@@ -587,112 +848,23 @@ class BackupManagerService extends IBackupManager.Stub {
// ----- Track connection to GoogleBackupTransport service -----
ServiceConnection mGoogleConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Log.v(TAG, "Connected to Google transport");
+ if (DEBUG) Slog.v(TAG, "Connected to Google transport");
mGoogleTransport = IBackupTransport.Stub.asInterface(service);
registerTransport(name.flattenToShortString(), mGoogleTransport);
}
public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.v(TAG, "Disconnected from Google transport");
+ if (DEBUG) Slog.v(TAG, "Disconnected from Google transport");
mGoogleTransport = null;
registerTransport(name.flattenToShortString(), null);
}
};
- // ----- Run the actual backup process asynchronously -----
-
- private class BackupHandler extends Handler {
- public void handleMessage(Message msg) {
-
- switch (msg.what) {
- case MSG_RUN_BACKUP:
- {
- mLastBackupPass = System.currentTimeMillis();
- mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
-
- IBackupTransport transport = getTransport(mCurrentTransport);
- if (transport == null) {
- Log.v(TAG, "Backup requested but no transport available");
- synchronized (mQueueLock) {
- mBackupOrRestoreInProgress = false;
- }
- mWakelock.release();
- break;
- }
-
- // snapshot the pending-backup set and work on that
- ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
- synchronized (mQueueLock) {
- // Do we have any work to do?
- if (mPendingBackups.size() > 0) {
- for (BackupRequest b: mPendingBackups.values()) {
- queue.add(b);
- }
- Log.v(TAG, "clearing pending backups");
- mPendingBackups.clear();
-
- // Start a new backup-queue journal file too
- File oldJournal = mJournal;
- mJournal = null;
-
- // At this point, we have started a new journal file, and the old
- // file identity is being passed to the backup processing thread.
- // When it completes successfully, that old journal file will be
- // deleted. If we crash prior to that, the old journal is parsed
- // at next boot and the journaled requests fulfilled.
- (new PerformBackupThread(transport, queue, oldJournal)).start();
- } else {
- Log.v(TAG, "Backup requested but nothing pending");
- synchronized (mQueueLock) {
- mBackupOrRestoreInProgress = false;
- }
- mWakelock.release();
- }
- }
- break;
- }
-
- case MSG_RUN_FULL_BACKUP:
- break;
-
- case MSG_RUN_RESTORE:
- {
- RestoreParams params = (RestoreParams)msg.obj;
- Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
- (new PerformRestoreThread(params.transport, params.observer,
- params.token)).start();
- break;
- }
-
- case MSG_RUN_CLEAR:
- {
- ClearParams params = (ClearParams)msg.obj;
- (new PerformClearThread(params.transport, params.packageInfo)).start();
- break;
- }
-
- case MSG_RUN_INITIALIZE:
- {
- HashSet<String> queue;
-
- // Snapshot the pending-init queue and work on that
- synchronized (mQueueLock) {
- queue = new HashSet<String>(mPendingInits);
- mPendingInits.clear();
- }
-
- (new PerformInitializeThread(queue)).start();
- break;
- }
- }
- }
- }
-
// Add the backup agents in the given package to our set of known backup participants.
// If 'packageName' is null, adds all backup agents in the whole system.
void addPackageParticipantsLocked(String packageName) {
// Look for apps that define the android:backupAgent attribute
- if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
+ if (DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: " + packageName);
List<PackageInfo> targetApps = allAgentPackages();
addPackageParticipantsLockedInner(packageName, targetApps);
}
@@ -700,14 +872,12 @@ class BackupManagerService extends IBackupManager.Stub {
private void addPackageParticipantsLockedInner(String packageName,
List<PackageInfo> targetPkgs) {
if (DEBUG) {
- Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
+ Slog.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
for (PackageInfo p : targetPkgs) {
- Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
+ Slog.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
+ " uid=" + p.applicationInfo.uid
+ " killAfterRestore="
+ (((p.applicationInfo.flags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) ? "true" : "false")
- + " restoreNeedsApplication="
- + (((p.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION) != 0) ? "true" : "false")
);
}
}
@@ -724,7 +894,7 @@ class BackupManagerService extends IBackupManager.Stub {
// If we've never seen this app before, schedule a backup for it
if (!mEverStoredApps.contains(pkg.packageName)) {
- if (DEBUG) Log.i(TAG, "New app " + pkg.packageName
+ if (DEBUG) Slog.i(TAG, "New app " + pkg.packageName
+ " never backed up; scheduling");
dataChanged(pkg.packageName);
}
@@ -735,7 +905,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Remove the given package's entry from our known active set. If
// 'packageName' is null, *all* participating apps will be removed.
void removePackageParticipantsLocked(String packageName) {
- if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
+ if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: " + packageName);
List<PackageInfo> allApps = null;
if (packageName != null) {
allApps = new ArrayList<PackageInfo>();
@@ -755,10 +925,10 @@ class BackupManagerService extends IBackupManager.Stub {
private void removePackageParticipantsLockedInner(String packageName,
List<PackageInfo> agents) {
if (DEBUG) {
- Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
+ Slog.v(TAG, "removePackageParticipantsLockedInner (" + packageName
+ ") removing " + agents.size() + " entries");
for (PackageInfo p : agents) {
- Log.v(TAG, " - " + p);
+ Slog.v(TAG, " - " + p);
}
}
for (PackageInfo pkg : agents) {
@@ -794,9 +964,7 @@ class BackupManagerService extends IBackupManager.Stub {
try {
ApplicationInfo app = pkg.applicationInfo;
if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null
- || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
- pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+ || app.backupAgentName == null) {
packages.remove(a);
}
else {
@@ -816,10 +984,10 @@ class BackupManagerService extends IBackupManager.Stub {
// action cannot be passed a null package name.
void updatePackageParticipantsLocked(String packageName) {
if (packageName == null) {
- Log.e(TAG, "updatePackageParticipants called with null package name");
+ Slog.e(TAG, "updatePackageParticipants called with null package name");
return;
}
- if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
+ if (DEBUG) Slog.v(TAG, "updatePackageParticipantsLocked: " + packageName);
// brute force but small code size
List<PackageInfo> allApps = allAgentPackages();
@@ -827,7 +995,7 @@ class BackupManagerService extends IBackupManager.Stub {
addPackageParticipantsLockedInner(packageName, allApps);
}
- // Called from the backup thread: record that the given app has been successfully
+ // Called from the backup task: record that the given app has been successfully
// backed up at least once
void logBackupComplete(String packageName) {
if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
@@ -841,7 +1009,7 @@ class BackupManagerService extends IBackupManager.Stub {
out.seek(out.length());
out.writeUTF(packageName);
} catch (IOException e) {
- Log.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
+ Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
} finally {
try { if (out != null) out.close(); } catch (IOException e) {}
}
@@ -850,7 +1018,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Remove our awareness of having ever backed up the given package
void removeEverBackedUp(String packageName) {
- if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName + ", new set:");
+ if (DEBUG) Slog.v(TAG, "Removing backed-up knowledge of " + packageName + ", new set:");
synchronized (mEverStoredApps) {
// Rewrite the file and rename to overwrite. If we reboot in the middle,
@@ -863,7 +1031,7 @@ class BackupManagerService extends IBackupManager.Stub {
mEverStoredApps.remove(packageName);
for (String s : mEverStoredApps) {
known.writeUTF(s);
- if (DEBUG) Log.v(TAG, " " + s);
+ if (DEBUG) Slog.v(TAG, " " + s);
}
known.close();
known = null;
@@ -875,7 +1043,7 @@ class BackupManagerService extends IBackupManager.Stub {
// abandon the whole process and remove all what's-backed-up
// state entirely, meaning we'll force a backup pass for every
// participant on the next boot or [re]install.
- Log.w(TAG, "Error rewriting " + mEverStored, e);
+ Slog.w(TAG, "Error rewriting " + mEverStored, e);
mEverStoredApps.clear();
tempKnownFile.delete();
mEverStored.delete();
@@ -885,12 +1053,43 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Persistently record the current and ancestral backup tokens as well
+ // as the set of packages with data [supposedly] available in the
+ // ancestral dataset.
+ void writeRestoreTokens() {
+ try {
+ RandomAccessFile af = new RandomAccessFile(mTokenFile, "rwd");
+
+ // First, the version number of this record, for futureproofing
+ af.writeInt(CURRENT_ANCESTRAL_RECORD_VERSION);
+
+ // Write the ancestral and current tokens
+ af.writeLong(mAncestralToken);
+ af.writeLong(mCurrentToken);
+
+ // Now write the set of ancestral packages
+ if (mAncestralPackages == null) {
+ af.writeInt(-1);
+ } else {
+ af.writeInt(mAncestralPackages.size());
+ if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size());
+ for (String pkgName : mAncestralPackages) {
+ af.writeUTF(pkgName);
+ if (DEBUG) Slog.v(TAG, " " + pkgName);
+ }
+ }
+ af.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to write token file:", e);
+ }
+ }
+
// Return the given transport
private IBackupTransport getTransport(String transportName) {
synchronized (mTransports) {
IBackupTransport transport = mTransports.get(transportName);
if (transport == null) {
- Log.w(TAG, "Requested unavailable transport: " + transportName);
+ Slog.w(TAG, "Requested unavailable transport: " + transportName);
}
return transport;
}
@@ -904,7 +1103,7 @@ class BackupManagerService extends IBackupManager.Stub {
mConnectedAgent = null;
try {
if (mActivityManager.bindBackupAgent(app, mode)) {
- Log.d(TAG, "awaiting agent for " + app);
+ Slog.d(TAG, "awaiting agent for " + app);
// success; wait for the agent to arrive
// only wait 10 seconds for the clear data to happen
@@ -921,7 +1120,7 @@ class BackupManagerService extends IBackupManager.Stub {
// if we timed out with no connect, abort and move on
if (mConnecting == true) {
- Log.w(TAG, "Timeout waiting for agent " + app);
+ Slog.w(TAG, "Timeout waiting for agent " + app);
return null;
}
agent = mConnectedAgent;
@@ -939,12 +1138,12 @@ class BackupManagerService extends IBackupManager.Stub {
try {
PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
- if (DEBUG) Log.i(TAG, "allowClearUserData=false so not wiping "
+ if (DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
+ packageName);
return;
}
} catch (NameNotFoundException e) {
- Log.w(TAG, "Tried to clear data for " + packageName + " but not found");
+ Slog.w(TAG, "Tried to clear data for " + packageName + " but not found");
return;
}
@@ -952,15 +1151,11 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized(mClearDataLock) {
mClearingData = true;
- /* This is causing some critical processes to be killed during setup.
- Temporarily revert this change until we find a better solution.
try {
mActivityManager.clearApplicationUserData(packageName, observer);
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
- */
- mPackageManager.clearApplicationUserData(packageName, observer);
// only wait 10 seconds for the clear data to happen
long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
@@ -984,16 +1179,58 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Get the restore-set token for the best-available restore set for this package:
+ // the active set if possible, else the ancestral one. Returns zero if none available.
+ long getAvailableRestoreToken(String packageName) {
+ long token = mAncestralToken;
+ synchronized (mQueueLock) {
+ if (mEverStoredApps.contains(packageName)) {
+ token = mCurrentToken;
+ }
+ }
+ return token;
+ }
+
+ // -----
+ // Utility methods used by the asynchronous-with-timeout backup/restore operations
+ boolean waitUntilOperationComplete(int token) {
+ int finalState = OP_PENDING;
+ synchronized (mCurrentOpLock) {
+ try {
+ while ((finalState = mCurrentOperations.get(token, OP_TIMEOUT)) == OP_PENDING) {
+ try {
+ mCurrentOpLock.wait();
+ } catch (InterruptedException e) {}
+ }
+ } catch (IndexOutOfBoundsException e) {
+ // the operation has been mysteriously cleared from our
+ // bookkeeping -- consider this a success and ignore it.
+ }
+ }
+ mBackupHandler.removeMessages(MSG_TIMEOUT);
+ if (DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
+ + " complete: finalState=" + finalState);
+ return finalState == OP_ACKNOWLEDGED;
+ }
+
+ void prepareOperationTimeout(int token, long interval) {
+ if (DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
+ + " interval=" + interval);
+ mCurrentOperations.put(token, OP_PENDING);
+ Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0);
+ mBackupHandler.sendMessageDelayed(msg, interval);
+ }
+
// ----- Back up a set of applications via a worker thread -----
- class PerformBackupThread extends Thread {
+ class PerformBackupTask implements Runnable {
private static final String TAG = "PerformBackupThread";
IBackupTransport mTransport;
ArrayList<BackupRequest> mQueue;
File mStateDir;
File mJournal;
- public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
+ public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue,
File journal) {
mTransport = transport;
mQueue = queue;
@@ -1006,29 +1243,28 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- @Override
public void run() {
int status = BackupConstants.TRANSPORT_OK;
long startRealtime = SystemClock.elapsedRealtime();
- if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
+ if (DEBUG) Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
// Backups run at background priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
- EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
+ EventLog.writeEvent(EventLogTags.BACKUP_START, mTransport.transportDirName());
// If we haven't stored package manager metadata yet, we must init the transport.
File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
if (status == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
- Log.i(TAG, "Initializing (wiping) backup state and transport storage");
+ Slog.i(TAG, "Initializing (wiping) backup state and transport storage");
resetBackupState(mStateDir); // Just to make sure.
status = mTransport.initializeDevice();
if (status == BackupConstants.TRANSPORT_OK) {
- EventLog.writeEvent(BACKUP_INITIALIZE_EVENT);
+ EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
} else {
- EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "(initialize)");
- Log.e(TAG, "Transport error in initializeDevice()");
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
+ Slog.e(TAG, "Transport error in initializeDevice()");
}
}
@@ -1056,30 +1292,40 @@ class BackupManagerService extends IBackupManager.Stub {
status = mTransport.finishBackup();
if (status == BackupConstants.TRANSPORT_OK) {
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(BACKUP_SUCCESS_EVENT, mQueue.size(), millis);
+ EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, mQueue.size(), millis);
} else {
- EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "(finish)");
- Log.e(TAG, "Transport error in finishBackup()");
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(finish)");
+ Slog.e(TAG, "Transport error in finishBackup()");
}
}
if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
// The backend reports that our dataset has been wiped. We need to
// reset all of our bookkeeping and instead run a new backup pass for
- // everything. This must come after mBackupOrRestoreInProgress is cleared.
- EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName());
+ // everything.
+ EventLog.writeEvent(EventLogTags.BACKUP_RESET, mTransport.transportDirName());
resetBackupState(mStateDir);
}
} catch (Exception e) {
- Log.e(TAG, "Error in backup thread", e);
+ Slog.e(TAG, "Error in backup thread", e);
status = BackupConstants.TRANSPORT_ERROR;
} finally {
+ // If everything actually went through and this is the first time we've
+ // done a backup, we can now record what the current backup dataset token
+ // is.
+ if ((mCurrentToken == 0) && (status != BackupConstants.TRANSPORT_OK)) {
+ try {
+ mCurrentToken = mTransport.getCurrentRestoreSet();
+ } catch (RemoteException e) { /* cannot happen */ }
+ writeRestoreTokens();
+ }
+
// If things went wrong, we need to re-stage the apps we had expected
// to be backing up in this pass. This journals the package names in
// the current active pending-backup file, not in the we are holding
// here in mJournal.
if (status != BackupConstants.TRANSPORT_OK) {
- Log.w(TAG, "Backup pass unsuccessful, restaging");
+ Slog.w(TAG, "Backup pass unsuccessful, restaging");
for (BackupRequest req : mQueue) {
dataChanged(req.appInfo.packageName);
}
@@ -1096,17 +1342,11 @@ class BackupManagerService extends IBackupManager.Stub {
// re-enqueued all of these packages in the current active journal.
// Either way, we no longer need this pass's journal.
if (mJournal != null && !mJournal.delete()) {
- Log.e(TAG, "Unable to remove backup journal file " + mJournal);
- }
-
- // Only once we're entirely finished do we indicate our completion
- // and release the wakelock
- synchronized (mQueueLock) {
- mBackupOrRestoreInProgress = false;
+ Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
}
+ // Only once we're entirely finished do we release the wakelock
if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
- // This must come after mBackupOrRestoreInProgress is cleared.
backupNow();
}
@@ -1116,16 +1356,7 @@ class BackupManagerService extends IBackupManager.Stub {
private int doQueuedBackups(IBackupTransport transport) {
for (BackupRequest request : mQueue) {
- Log.d(TAG, "starting agent for backup of " + request);
-
- // Don't run backup, even if requested, if the target app does not have
- // the requisite permission
- if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
- request.appInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Skipping backup of unprivileged package "
- + request.appInfo.packageName);
- continue;
- }
+ Slog.d(TAG, "starting agent for backup of " + request);
IBackupAgent agent = null;
int mode = (request.fullBackup)
@@ -1139,7 +1370,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
} catch (SecurityException ex) {
// Try for the next one.
- Log.d(TAG, "error in bind/backup", ex);
+ Slog.d(TAG, "error in bind/backup", ex);
} finally {
try { // unbind even on timeout, just in case
mActivityManager.unbindBackupAgent(request.appInfo);
@@ -1153,7 +1384,7 @@ class BackupManagerService extends IBackupManager.Stub {
private int processOneBackup(BackupRequest request, IBackupAgent agent,
IBackupTransport transport) {
final String packageName = request.appInfo.packageName;
- if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
File savedStateName = new File(mStateDir, packageName);
File backupDataName = new File(mDataDir, packageName + ".data");
@@ -1164,6 +1395,7 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor newState = null;
PackageInfo packInfo;
+ int token = mTokenGenerator.nextInt();
try {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
@@ -1195,13 +1427,21 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- // Run the target's backup pass
- agent.doBackup(savedState, backupData, newState);
+ // Initiate the target's backup pass
+ prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
+ agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
+ boolean success = waitUntilOperationComplete(token);
+
+ if (!success) {
+ // timeout -- bail out into the failed-transaction logic
+ throw new RuntimeException("Backup timeout");
+ }
+
logBackupComplete(packageName);
- if (DEBUG) Log.v(TAG, "doBackup() success");
+ if (DEBUG) Slog.v(TAG, "doBackup() success");
} catch (Exception e) {
- Log.e(TAG, "Error backing up " + packageName, e);
- EventLog.writeEvent(BACKUP_AGENT_FAILURE_EVENT, packageName, e.toString());
+ Slog.e(TAG, "Error backing up " + packageName, e);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
backupDataName.delete();
newStateName.delete();
return BackupConstants.TRANSPORT_ERROR;
@@ -1210,6 +1450,9 @@ class BackupManagerService extends IBackupManager.Stub {
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
try { if (newState != null) newState.close(); } catch (IOException e) {}
savedState = backupData = newState = null;
+ synchronized (mCurrentOpLock) {
+ mCurrentOperations.clear();
+ }
}
// Now propagate the newly-backed-up data to the transport
@@ -1232,7 +1475,7 @@ class BackupManagerService extends IBackupManager.Stub {
result = transport.finishBackup();
}
} else {
- if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
+ if (DEBUG) Slog.i(TAG, "no backup data written; not calling transport");
}
// After successful transport, delete the now-stale data
@@ -1241,13 +1484,13 @@ class BackupManagerService extends IBackupManager.Stub {
if (result == BackupConstants.TRANSPORT_OK) {
backupDataName.delete();
newStateName.renameTo(savedStateName);
- EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
+ EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size);
} else {
- EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
}
} catch (Exception e) {
- Log.e(TAG, "Transport error backing up " + packageName, e);
- EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+ Slog.e(TAG, "Transport error backing up " + packageName, e);
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
result = BackupConstants.TRANSPORT_ERROR;
} finally {
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
@@ -1267,14 +1510,14 @@ class BackupManagerService extends IBackupManager.Stub {
// partition will be signed with the device's platform certificate, so on
// different phones the same system app will have different signatures.)
if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (DEBUG) Log.v(TAG, "System app " + target.packageName + " - skipping sig check");
+ if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
return true;
}
// Allow unsigned apps, but not signed on one device and unsigned on the other
// !!! TODO: is this the right policy?
Signature[] deviceSigs = target.signatures;
- if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ " device=" + deviceSigs);
if ((storedSigs == null || storedSigs.length == 0)
&& (deviceSigs == null || deviceSigs.length == 0)) {
@@ -1305,11 +1548,13 @@ class BackupManagerService extends IBackupManager.Stub {
return true;
}
- class PerformRestoreThread extends Thread {
+ class PerformRestoreTask implements Runnable {
private IBackupTransport mTransport;
private IRestoreObserver mObserver;
private long mToken;
+ private PackageInfo mTargetPackage;
private File mStateDir;
+ private int mPmToken;
class RestoreRequest {
public PackageInfo app;
@@ -1321,12 +1566,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer,
- long restoreSetToken) {
+ PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
+ long restoreSetToken, PackageInfo targetPackage, int pmToken) {
mTransport = transport;
- Log.d(TAG, "PerformRestoreThread mObserver=" + mObserver);
mObserver = observer;
mToken = restoreSetToken;
+ mTargetPackage = targetPackage;
+ mPmToken = pmToken;
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
@@ -1335,36 +1581,19 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- @Override
public void run() {
long startRealtime = SystemClock.elapsedRealtime();
- if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
- + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken));
- /**
- * Restore sequence:
- *
- * 1. get the restore set description for our identity
- * 2. for each app in the restore set:
- * 2.a. if it's restorable on this device, add it to the restore queue
- * 3. for each app in the restore queue:
- * 3.a. clear the app data
- * 3.b. get the restore data for the app from the transport
- * 3.c. launch the backup agent for the app
- * 3.d. agent.doRestore() with the data from the server
- * 3.e. unbind the agent [and kill the app?]
- * 4. shut down the transport
- *
- * On errors, we try our best to recover and move on to the next
- * application, but if necessary we abort the whole operation --
- * the user is waiting, after al.
- */
+ if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
+ + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
+ + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
+ PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
// build the set of apps to restore
try {
// TODO: Log this before getAvailableRestoreSets, somehow
- EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName(), mToken);
+ EventLog.writeEvent(EventLogTags.RESTORE_START, mTransport.transportDirName(), mToken);
// Get the list of all packages which have backup enabled.
// (Include the Package Manager metadata pseudo-package first.)
@@ -1374,7 +1603,12 @@ class BackupManagerService extends IBackupManager.Stub {
restorePackages.add(omPackage);
List<PackageInfo> agentPackages = allAgentPackages();
- restorePackages.addAll(agentPackages);
+ if (mTargetPackage == null) {
+ restorePackages.addAll(agentPackages);
+ } else {
+ // Just one package to attempt restore of
+ restorePackages.add(mTargetPackage);
+ }
// let the observer know that we're running
if (mObserver != null) {
@@ -1383,38 +1617,38 @@ class BackupManagerService extends IBackupManager.Stub {
// its startRestore() runs?
mObserver.restoreStarting(restorePackages.size());
} catch (RemoteException e) {
- Log.d(TAG, "Restore observer died at restoreStarting");
+ Slog.d(TAG, "Restore observer died at restoreStarting");
mObserver = null;
}
}
if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
BackupConstants.TRANSPORT_OK) {
- Log.e(TAG, "Error starting restore operation");
- EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ Slog.e(TAG, "Error starting restore operation");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
return;
}
String packageName = mTransport.nextRestorePackage();
if (packageName == null) {
- Log.e(TAG, "Error getting first restore package");
- EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ Slog.e(TAG, "Error getting first restore package");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
return;
} else if (packageName.equals("")) {
- Log.i(TAG, "No restore data available");
+ Slog.i(TAG, "No restore data available");
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(RESTORE_SUCCESS_EVENT, 0, millis);
+ EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, 0, millis);
return;
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
- Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ Slog.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ "\", found only \"" + packageName + "\"");
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
"Package manager data missing");
return;
}
// Pull the Package Manager metadata from the restore set first
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ pmAgent = new PackageManagerBackupAgent(
mPackageManager, agentPackages);
processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
@@ -1422,8 +1656,8 @@ class BackupManagerService extends IBackupManager.Stub {
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
if (!pmAgent.hasMetadata()) {
- Log.e(TAG, "No restore metadata available, so not restoring settings");
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ Slog.e(TAG, "No restore metadata available, so not restoring settings");
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL,
"Package manager restore metadata missing");
return;
}
@@ -1433,26 +1667,27 @@ class BackupManagerService extends IBackupManager.Stub {
packageName = mTransport.nextRestorePackage();
if (packageName == null) {
- Log.e(TAG, "Error getting next restore package");
- EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ Slog.e(TAG, "Error getting next restore package");
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
return;
} else if (packageName.equals("")) {
+ if (DEBUG) Slog.v(TAG, "No next package, finishing restore");
break;
}
if (mObserver != null) {
try {
- mObserver.onUpdate(count);
+ mObserver.onUpdate(count, packageName);
} catch (RemoteException e) {
- Log.d(TAG, "Restore observer died in onUpdate");
+ Slog.d(TAG, "Restore observer died in onUpdate");
mObserver = null;
}
}
Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
if (metaInfo == null) {
- Log.e(TAG, "Missing metadata for " + packageName);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ Slog.e(TAG, "Missing metadata for " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Package metadata missing");
continue;
}
@@ -1462,50 +1697,50 @@ class BackupManagerService extends IBackupManager.Stub {
int flags = PackageManager.GET_SIGNATURES;
packageInfo = mPackageManager.getPackageInfo(packageName, flags);
} catch (NameNotFoundException e) {
- Log.e(TAG, "Invalid package restoring data", e);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ Slog.e(TAG, "Invalid package restoring data", e);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Package missing on device");
continue;
}
if (metaInfo.versionCode > packageInfo.versionCode) {
- String message = "Version " + metaInfo.versionCode
- + " > installed version " + packageInfo.versionCode;
- Log.w(TAG, "Package " + packageName + ": " + message);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, message);
- continue;
+ // Data is from a "newer" version of the app than we have currently
+ // installed. If the app has not declared that it is prepared to
+ // handle this case, we do not attempt the restore.
+ if ((packageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Slog.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
+ packageName, message);
+ continue;
+ } else {
+ if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
+ + " > installed " + packageInfo.versionCode
+ + " but restoreAnyVersion");
+ }
}
if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
- Log.w(TAG, "Signature mismatch restoring " + packageName);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ Slog.w(TAG, "Signature mismatch restoring " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Signature mismatch");
continue;
}
- if (DEBUG) Log.v(TAG, "Package " + packageName
+ if (DEBUG) Slog.v(TAG, "Package " + packageName
+ " restore version [" + metaInfo.versionCode
+ "] is compatible with installed version ["
+ packageInfo.versionCode + "]");
- // Now perform the actual restore: first clear the app's data
- // if appropriate
- clearApplicationDataSynchronous(packageName);
-
- // Then set up and bind the agent (with a restricted Application object
- // unless the application says otherwise)
- boolean useRealApp = (packageInfo.applicationInfo.flags
- & ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION) != 0;
- if (DEBUG && useRealApp) {
- Log.v(TAG, "agent requires real Application subclass for restore");
- }
+ // Then set up and bind the agent
IBackupAgent agent = bindToAgentSynchronous(
packageInfo.applicationInfo,
- (useRealApp ? IApplicationThread.BACKUP_MODE_INCREMENTAL
- : IApplicationThread.BACKUP_MODE_RESTORE));
+ IApplicationThread.BACKUP_MODE_INCREMENTAL);
if (agent == null) {
- Log.w(TAG, "Can't find backup agent for " + packageName);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ Slog.w(TAG, "Can't find backup agent for " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Restore agent missing");
continue;
}
@@ -1521,10 +1756,12 @@ class BackupManagerService extends IBackupManager.Stub {
// The agent was probably running with a stub Application object,
// which isn't a valid run mode for the main app logic. Shut
// down the app so that next time it's launched, it gets the
- // usual full initialization.
- if ((packageInfo.applicationInfo.flags
+ // usual full initialization. Note that this is only done for
+ // full-system restores: when a single app has requested a restore,
+ // it is explicitly not killed following that operation.
+ if (mTargetPackage == null && (packageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
- if (DEBUG) Log.d(TAG, "Restore complete, killing host process of "
+ if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
+ packageInfo.applicationInfo.processName);
mActivityManager.killApplicationProcess(
packageInfo.applicationInfo.processName,
@@ -1536,30 +1773,45 @@ class BackupManagerService extends IBackupManager.Stub {
// if we get this far, report success to the observer
error = 0;
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(RESTORE_SUCCESS_EVENT, count, millis);
+ EventLog.writeEvent(EventLogTags.RESTORE_SUCCESS, count, millis);
} catch (Exception e) {
- Log.e(TAG, "Error in restore thread", e);
+ Slog.e(TAG, "Error in restore thread", e);
} finally {
- if (DEBUG) Log.d(TAG, "finishing restore mObserver=" + mObserver);
+ if (DEBUG) Slog.d(TAG, "finishing restore mObserver=" + mObserver);
try {
mTransport.finishRestore();
} catch (RemoteException e) {
- Log.e(TAG, "Error finishing restore", e);
+ Slog.e(TAG, "Error finishing restore", e);
}
if (mObserver != null) {
try {
mObserver.restoreFinished(error);
} catch (RemoteException e) {
- Log.d(TAG, "Restore observer died at restoreFinished");
+ Slog.d(TAG, "Restore observer died at restoreFinished");
}
}
- // done; we can finally release the wakelock
- synchronized (mQueueLock) {
- mBackupOrRestoreInProgress = false;
+ // If this was a restoreAll operation, record that this was our
+ // ancestral dataset, as well as the set of apps that are possibly
+ // restoreable from the dataset
+ if (mTargetPackage == null && pmAgent != null) {
+ mAncestralPackages = pmAgent.getRestoredPackages();
+ mAncestralToken = mToken;
+ writeRestoreTokens();
+ }
+
+ // We must under all circumstances tell the Package Manager to
+ // proceed with install notifications if it's waiting for us.
+ if (mPmToken > 0) {
+ if (DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken);
+ try {
+ mPackageManagerBinder.finishPackageInstall(mPmToken);
+ } catch (RemoteException e) { /* can't happen */ }
}
+
+ // done; we can finally release the wakelock
mWakelock.release();
}
}
@@ -1569,13 +1821,7 @@ class BackupManagerService extends IBackupManager.Stub {
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
- if (DEBUG) Log.d(TAG, "processOneRestore packageName=" + packageName);
-
- // Don't restore to unprivileged packages
- if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
- packageName) != PackageManager.PERMISSION_GRANTED) {
- Log.d(TAG, "Skipping restore of unprivileged package " + packageName);
- }
+ if (DEBUG) Slog.d(TAG, "processOneRestore packageName=" + packageName);
// !!! TODO: get the dirs from the transport
File backupDataName = new File(mDataDir, packageName + ".restore");
@@ -1585,6 +1831,7 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor backupData = null;
ParcelFileDescriptor newState = null;
+ int token = mTokenGenerator.nextInt();
try {
// Run the transport's restore pass
backupData = ParcelFileDescriptor.open(backupDataName,
@@ -1593,8 +1840,8 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor.MODE_TRUNCATE);
if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
- Log.e(TAG, "Error getting restore data for " + packageName);
- EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ Slog.e(TAG, "Error getting restore data for " + packageName);
+ EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
return;
}
@@ -1608,7 +1855,14 @@ class BackupManagerService extends IBackupManager.Stub {
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
- agent.doRestore(backupData, appVersionCode, newState);
+ // Kick off the restore, checking for hung agents
+ prepareOperationTimeout(token, TIMEOUT_RESTORE_INTERVAL);
+ agent.doRestore(backupData, appVersionCode, newState, token, mBackupManagerBinder);
+ boolean success = waitUntilOperationComplete(token);
+
+ if (!success) {
+ throw new RuntimeException("restore timeout");
+ }
// if everything went okay, remember the recorded state now
//
@@ -1627,10 +1881,10 @@ class BackupManagerService extends IBackupManager.Stub {
//newStateName.renameTo(savedStateName); // TODO: replace with this
int size = (int) backupDataName.length();
- EventLog.writeEvent(RESTORE_PACKAGE_EVENT, packageName, size);
+ EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE, packageName, size);
} catch (Exception e) {
- Log.e(TAG, "Error restoring data for " + packageName, e);
- EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, e.toString());
+ Slog.e(TAG, "Error restoring data for " + packageName, e);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, e.toString());
// If the agent fails restore, it might have put the app's data
// into an incoherent state. For consistency we wipe its data
@@ -1641,20 +1895,20 @@ class BackupManagerService extends IBackupManager.Stub {
try { if (backupData != null) backupData.close(); } catch (IOException e) {}
try { if (newState != null) newState.close(); } catch (IOException e) {}
backupData = newState = null;
+ mCurrentOperations.delete(token);
}
}
}
- class PerformClearThread extends Thread {
+ class PerformClearTask implements Runnable {
IBackupTransport mTransport;
PackageInfo mPackage;
- PerformClearThread(IBackupTransport transport, PackageInfo packageInfo) {
+ PerformClearTask(IBackupTransport transport, PackageInfo packageInfo) {
mTransport = transport;
mPackage = packageInfo;
}
- @Override
public void run() {
try {
// Clear the on-device backup state to ensure a full backup next time
@@ -1676,33 +1930,29 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Last but not least, release the cpu
- synchronized (mQueueLock) {
- mBackupOrRestoreInProgress = false;
- }
mWakelock.release();
}
}
}
- class PerformInitializeThread extends Thread {
+ class PerformInitializeTask implements Runnable {
HashSet<String> mQueue;
- PerformInitializeThread(HashSet<String> transportNames) {
+ PerformInitializeTask(HashSet<String> transportNames) {
mQueue = transportNames;
}
- @Override
public void run() {
try {
for (String transportName : mQueue) {
IBackupTransport transport = getTransport(transportName);
if (transport == null) {
- Log.e(TAG, "Requested init for " + transportName + " but not found");
+ Slog.e(TAG, "Requested init for " + transportName + " but not found");
continue;
}
- Log.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
- EventLog.writeEvent(BACKUP_START_EVENT, transport.transportDirName());
+ Slog.i(TAG, "Initializing (wiping) backup transport storage: " + transportName);
+ EventLog.writeEvent(EventLogTags.BACKUP_START, transport.transportDirName());
long startRealtime = SystemClock.elapsedRealtime();
int status = transport.initializeDevice();
@@ -1712,25 +1962,25 @@ class BackupManagerService extends IBackupManager.Stub {
// Okay, the wipe really happened. Clean up our local bookkeeping.
if (status == BackupConstants.TRANSPORT_OK) {
- Log.i(TAG, "Device init successful");
+ Slog.i(TAG, "Device init successful");
int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
- EventLog.writeEvent(BACKUP_INITIALIZE_EVENT);
+ EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
resetBackupState(new File(mBaseStateDir, transport.transportDirName()));
- EventLog.writeEvent(BACKUP_SUCCESS_EVENT, 0, millis);
+ EventLog.writeEvent(EventLogTags.BACKUP_SUCCESS, 0, millis);
synchronized (mQueueLock) {
recordInitPendingLocked(false, transportName);
}
} else {
// If this didn't work, requeue this one and try again
// after a suitable interval
- Log.e(TAG, "Transport error in initializeDevice()");
- EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "(initialize)");
+ Slog.e(TAG, "Transport error in initializeDevice()");
+ EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
synchronized (mQueueLock) {
recordInitPendingLocked(true, transportName);
}
// do this via another alarm to make sure of the wakelock states
long delay = transport.requestBackupTime();
- if (DEBUG) Log.w(TAG, "init failed on "
+ if (DEBUG) Slog.w(TAG, "init failed on "
+ transportName + " resched in " + delay);
mAlarmManager.set(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + delay, mRunInitIntent);
@@ -1739,12 +1989,9 @@ class BackupManagerService extends IBackupManager.Stub {
} catch (RemoteException e) {
// can't happen; the transports are local
} catch (Exception e) {
- Log.e(TAG, "Unexpected error performing init", e);
+ Slog.e(TAG, "Unexpected error performing init", e);
} finally {
- // Done; indicate that we're finished and release the wakelock
- synchronized (mQueueLock) {
- mInitInProgress = false;
- }
+ // Done; release the wakelock
mWakelock.release();
}
}
@@ -1757,7 +2004,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Record that we need a backup pass for the caller. Since multiple callers
// may share a uid, we need to note all candidates within that uid and schedule
// a backup pass for each of them.
- EventLog.writeEvent(BACKUP_DATA_CHANGED_EVENT, packageName);
+ EventLog.writeEvent(EventLogTags.BACKUP_DATA_CHANGED, packageName);
// If the caller does not hold the BACKUP permission, it can only request a
// backup of its own data.
@@ -1795,9 +2042,9 @@ class BackupManagerService extends IBackupManager.Stub {
if (DEBUG) {
int numKeys = mPendingBackups.size();
- Log.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
+ Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
for (BackupRequest b : mPendingBackups.values()) {
- Log.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
+ Slog.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
}
}
}
@@ -1805,7 +2052,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
} else {
- Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
+ Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
+ " uid=" + Binder.getCallingUid());
}
}
@@ -1818,7 +2065,7 @@ class BackupManagerService extends IBackupManager.Stub {
out.seek(out.length());
out.writeUTF(str);
} catch (IOException e) {
- Log.e(TAG, "Can't write " + str + " to backup journal", e);
+ Slog.e(TAG, "Can't write " + str + " to backup journal", e);
mJournal = null;
} finally {
try { if (out != null) out.close(); } catch (IOException e) {}
@@ -1827,12 +2074,12 @@ class BackupManagerService extends IBackupManager.Stub {
// Clear the given package's backup data from the current transport
public void clearBackupData(String packageName) {
- if (DEBUG) Log.v(TAG, "clearBackupData() of " + packageName);
+ if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName);
PackageInfo info;
try {
info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
} catch (NameNotFoundException e) {
- Log.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
+ Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
return;
}
@@ -1845,7 +2092,7 @@ class BackupManagerService extends IBackupManager.Stub {
} else {
// a caller with full permission can ask to back up any participating app
// !!! TODO: allow data-clear of ANY app?
- if (DEBUG) Log.v(TAG, "Privileged caller, allowing clear of other apps");
+ if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
apps = new HashSet<ApplicationInfo>();
int N = mBackupParticipants.size();
for (int i = 0; i < N; i++) {
@@ -1859,7 +2106,7 @@ class BackupManagerService extends IBackupManager.Stub {
// now find the given package in the set of candidate apps
for (ApplicationInfo app : apps) {
if (app.packageName.equals(packageName)) {
- if (DEBUG) Log.v(TAG, "Found the app - running clear process");
+ if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
// found it; fire off the clear request
synchronized (mQueueLock) {
long oldId = Binder.clearCallingIdentity();
@@ -1879,7 +2126,7 @@ class BackupManagerService extends IBackupManager.Stub {
public void backupNow() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
- if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
+ if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
synchronized (mQueueLock) {
// Because the alarms we are using can jitter, and we want an *immediate*
// backup pass to happen, we restart the timer beginning with "next time,"
@@ -1889,7 +2136,7 @@ class BackupManagerService extends IBackupManager.Stub {
mRunBackupIntent.send();
} catch (PendingIntent.CanceledException e) {
// should never happen
- Log.e(TAG, "run-backup intent cancelled!");
+ Slog.e(TAG, "run-backup intent cancelled!");
}
}
}
@@ -1899,7 +2146,7 @@ class BackupManagerService extends IBackupManager.Stub {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"setBackupEnabled");
- Log.i(TAG, "Backup enabled => " + enable);
+ Slog.i(TAG, "Backup enabled => " + enable);
boolean wasEnabled = mEnabled;
synchronized (this) {
@@ -1914,7 +2161,7 @@ class BackupManagerService extends IBackupManager.Stub {
startBackupAlarmsLocked(BACKUP_INTERVAL);
} else if (!enable) {
// No longer enabled, so stop running backups
- if (DEBUG) Log.i(TAG, "Opting out of backup");
+ if (DEBUG) Slog.i(TAG, "Opting out of backup");
mAlarmManager.cancel(mRunBackupIntent);
@@ -1939,6 +2186,20 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ // Enable/disable automatic restore of app data at install time
+ public void setAutoRestore(boolean doAutoRestore) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "setBackupEnabled");
+
+ Slog.i(TAG, "Auto restore => " + doAutoRestore);
+
+ synchronized (this) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
+ mAutoRestore = doAutoRestore;
+ }
+ }
+
// Mark the backup service as having been provisioned
public void setBackupProvisioned(boolean available) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
@@ -1957,7 +2218,7 @@ class BackupManagerService extends IBackupManager.Stub {
startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
} else if (!available) {
// No longer enabled, so stop running backups
- Log.w(TAG, "Backup service no longer provisioned");
+ Slog.w(TAG, "Backup service no longer provisioned");
mAlarmManager.cancel(mRunBackupIntent);
}
}
@@ -1986,7 +2247,7 @@ class BackupManagerService extends IBackupManager.Stub {
public String getCurrentTransport() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getCurrentTransport");
- Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
+ if (DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
return mCurrentTransport;
}
@@ -2022,10 +2283,10 @@ class BackupManagerService extends IBackupManager.Stub {
mCurrentTransport = transport;
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.BACKUP_TRANSPORT, transport);
- Log.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ " returning " + prevTransport);
} else {
- Log.w(TAG, "Attempt to select unavailable transport " + transport);
+ Slog.w(TAG, "Attempt to select unavailable transport " + transport);
}
return prevTransport;
}
@@ -2036,12 +2297,12 @@ class BackupManagerService extends IBackupManager.Stub {
public void agentConnected(String packageName, IBinder agentBinder) {
synchronized(mAgentConnectLock) {
if (Binder.getCallingUid() == Process.SYSTEM_UID) {
- Log.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
+ Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
mConnectedAgent = agent;
mConnecting = false;
} else {
- Log.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ " claiming agent connected");
}
mAgentConnectLock.notifyAll();
@@ -2058,83 +2319,132 @@ class BackupManagerService extends IBackupManager.Stub {
mConnectedAgent = null;
mConnecting = false;
} else {
- Log.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ " claiming agent disconnected");
}
mAgentConnectLock.notifyAll();
}
}
+ // An application being installed will need a restore pass, then the Package Manager
+ // will need to be told when the restore is finished.
+ public void restoreAtInstall(String packageName, int token) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ + " attemping install-time restore");
+ return;
+ }
+
+ long restoreSet = getAvailableRestoreToken(packageName);
+ if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
+ + " token=" + Integer.toHexString(token));
+
+ if (mAutoRestore && mProvisioned && restoreSet != 0) {
+ // okay, we're going to attempt a restore of this package from this restore set.
+ // The eventual message back into the Package Manager to run the post-install
+ // steps for 'token' will be issued from the restore handling code.
+
+ // We can use a synthetic PackageInfo here because:
+ // 1. We know it's valid, since the Package Manager supplied the name
+ // 2. Only the packageName field will be used by the restore code
+ PackageInfo pkg = new PackageInfo();
+ pkg.packageName = packageName;
+
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
+ restoreSet, pkg, token);
+ mBackupHandler.sendMessage(msg);
+ } else {
+ // Auto-restore disabled or no way to attempt a restore; just tell the Package
+ // Manager to proceed with the post-install handling for this package.
+ if (DEBUG) Slog.v(TAG, "No restore set -- skipping restore");
+ try {
+ mPackageManagerBinder.finishPackageInstall(token);
+ } catch (RemoteException e) { /* can't happen */ }
+ }
+ }
+
// Hand off a restore session
public IRestoreSession beginRestoreSession(String transport) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
synchronized(this) {
if (mActiveRestoreSession != null) {
- Log.d(TAG, "Restore session requested but one already active");
+ Slog.d(TAG, "Restore session requested but one already active");
return null;
}
- mActiveRestoreSession = new RestoreSession(transport);
+ mActiveRestoreSession = new ActiveRestoreSession(transport);
}
return mActiveRestoreSession;
}
+ // Note that a currently-active backup agent has notified us that it has
+ // completed the given outstanding asynchronous backup/restore operation.
+ public void opComplete(int token) {
+ synchronized (mCurrentOpLock) {
+ if (DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token));
+ mCurrentOperations.put(token, OP_ACKNOWLEDGED);
+ mCurrentOpLock.notifyAll();
+ }
+ }
+
// ----- Restore session -----
- class RestoreSession extends IRestoreSession.Stub {
+ class ActiveRestoreSession extends IRestoreSession.Stub {
private static final String TAG = "RestoreSession";
private IBackupTransport mRestoreTransport = null;
RestoreSet[] mRestoreSets = null;
- RestoreSession(String transport) {
+ ActiveRestoreSession(String transport) {
mRestoreTransport = getTransport(transport);
}
// --- Binder interface ---
- public synchronized RestoreSet[] getAvailableRestoreSets() {
+ public synchronized int getAvailableRestoreSets(IRestoreObserver observer) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
+ if (observer == null) {
+ throw new IllegalArgumentException("Observer must not be null");
+ }
+ long oldId = Binder.clearCallingIdentity();
try {
if (mRestoreTransport == null) {
- Log.w(TAG, "Null transport getting restore sets");
- return null;
- }
- if (mRestoreSets == null) { // valid transport; do the one-time fetch
- mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
- if (mRestoreSets == null) EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ Slog.w(TAG, "Null transport getting restore sets");
+ return -1;
}
- return mRestoreSets;
+ // spin off the transport request to our service thread
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_GET_RESTORE_SETS,
+ new RestoreGetSetsParams(mRestoreTransport, this, observer));
+ mBackupHandler.sendMessage(msg);
+ return 0;
} catch (Exception e) {
- Log.e(TAG, "Error in getAvailableRestoreSets", e);
- return null;
+ Slog.e(TAG, "Error in getAvailableRestoreSets", e);
+ return -1;
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
}
- public synchronized int performRestore(long token, IRestoreObserver observer) {
+ public synchronized int restoreAll(long token, IRestoreObserver observer) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"performRestore");
- if (DEBUG) Log.d(TAG, "performRestore token=" + Long.toHexString(token)
+ if (DEBUG) Slog.d(TAG, "performRestore token=" + Long.toHexString(token)
+ " observer=" + observer);
if (mRestoreTransport == null || mRestoreSets == null) {
- Log.e(TAG, "Ignoring performRestore() with no restore set");
+ Slog.e(TAG, "Ignoring performRestore() with no restore set");
return -1;
}
synchronized (mQueueLock) {
- if (mBackupOrRestoreInProgress) {
- Log.e(TAG, "Backup pass in progress, restore aborted");
- return -1;
- }
-
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
long oldId = Binder.clearCallingIdentity();
- // Suppress backups until the restore operation is finished
- mBackupOrRestoreInProgress = true;
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
msg.obj = new RestoreParams(mRestoreTransport, observer, token);
@@ -2145,23 +2455,75 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- Log.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
+ Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
return -1;
}
+ public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
+ if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
+
+ PackageInfo app = null;
+ try {
+ app = mPackageManager.getPackageInfo(packageName, 0);
+ } catch (NameNotFoundException nnf) {
+ Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
+ return -1;
+ }
+
+ // If the caller is not privileged and is not coming from the target
+ // app's uid, throw a permission exception back to the caller.
+ int perm = mContext.checkPermission(android.Manifest.permission.BACKUP,
+ Binder.getCallingPid(), Binder.getCallingUid());
+ if ((perm == PackageManager.PERMISSION_DENIED) &&
+ (app.applicationInfo.uid != Binder.getCallingUid())) {
+ Slog.w(TAG, "restorePackage: bad packageName=" + packageName
+ + " or calling uid=" + Binder.getCallingUid());
+ throw new SecurityException("No permission to restore other packages");
+ }
+
+ // If the package has no backup agent, we obviously cannot proceed
+ if (app.applicationInfo.backupAgentName == null) {
+ Slog.w(TAG, "Asked to restore package " + packageName + " with no agent");
+ return -1;
+ }
+
+ // So far so good; we're allowed to try to restore this package. Now
+ // check whether there is data for it in the current dataset, falling back
+ // to the ancestral dataset if not.
+ long token = getAvailableRestoreToken(packageName);
+
+ // If we didn't come up with a place to look -- no ancestral dataset and
+ // the app has never been backed up from this device -- there's nothing
+ // to do but return failure.
+ if (token == 0) {
+ return -1;
+ }
+
+ // Ready to go: enqueue the restore request and claim success
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+
public synchronized void endRestoreSession() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"endRestoreSession");
- if (DEBUG) Log.d(TAG, "endRestoreSession");
+ if (DEBUG) Slog.d(TAG, "endRestoreSession");
synchronized (this) {
+ long oldId = Binder.clearCallingIdentity();
try {
if (mRestoreTransport != null) mRestoreTransport.finishRestore();
} catch (Exception e) {
- Log.e(TAG, "Error in finishRestore", e);
+ Slog.e(TAG, "Error in finishRestore", e);
} finally {
mRestoreTransport = null;
+ Binder.restoreCallingIdentity(oldId);
}
}
@@ -2169,7 +2531,7 @@ class BackupManagerService extends IBackupManager.Stub {
if (BackupManagerService.this.mActiveRestoreSession == this) {
BackupManagerService.this.mActiveRestoreSession = null;
} else {
- Log.e(TAG, "ending non-current restore session");
+ Slog.e(TAG, "ending non-current restore session");
}
}
}
@@ -2181,9 +2543,8 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized (mQueueLock) {
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ " / " + (!mProvisioned ? "not " : "") + "provisioned / "
- + (!mBackupOrRestoreInProgress ? "not " : "") + "in progress / "
- + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init / "
- + (!mInitInProgress ? "not " : "") + "initializing");
+ + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
+ pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
pw.println("Last backup pass: " + mLastBackupPass
+ " (now = " + System.currentTimeMillis() + ')');
pw.println(" next scheduled: " + mNextBackupPass);
@@ -2197,7 +2558,7 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(" " + f.getName() + " - " + f.length() + " state bytes");
}
} catch (RemoteException e) {
- Log.e(TAG, "Error in transportDirName()", e);
+ Slog.e(TAG, "Error in transportDirName()", e);
pw.println(" Error: " + e);
}
}
@@ -2219,6 +2580,14 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ pw.println("Ancestral packages: "
+ + (mAncestralPackages == null ? "none" : mAncestralPackages.size()));
+ if (mAncestralPackages != null) {
+ for (String pkg : mAncestralPackages) {
+ pw.println(" " + pkg);
+ }
+ }
+
pw.println("Ever backed up: " + mEverStoredApps.size());
for (String pkg : mEverStoredApps) {
pw.println(" " + pkg);
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index bb36936..5cf61bd 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -27,14 +27,14 @@ import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.IBinder;
+import android.os.DropBoxManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UEventObserver;
-import android.provider.Checkin;
import android.provider.Settings;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import java.io.File;
import java.io.FileDescriptor;
@@ -68,23 +68,19 @@ import java.io.PrintWriter;
*/
class BatteryService extends Binder {
private static final String TAG = BatteryService.class.getSimpleName();
-
+
private static final boolean LOCAL_LOGV = false;
-
- 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
// Used locally for determining when to make a last ditch effort to log
// discharge stats before the device dies.
- private static final int CRITICAL_BATTERY_LEVEL = 4;
+ private static final int CRITICAL_BATTERY_LEVEL = 4;
private static final int DUMP_MAX_LENGTH = 24 * 1024;
private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "-u" };
private static final String BATTERY_STATS_SERVICE_NAME = "batteryinfo";
-
+
private static final String DUMPSYS_DATA_PATH = "/data/system/";
// This should probably be exposed in the API, though it's not critical
@@ -92,7 +88,7 @@ class BatteryService extends Binder {
private final Context mContext;
private final IBatteryStats mBatteryStats;
-
+
private boolean mAcOnline;
private boolean mUsbOnline;
private int mBatteryStatus;
@@ -117,12 +113,12 @@ class BatteryService extends Binder {
private int mPlugType;
private int mLastPlugType = -1; // Extra state so we can detect first run
-
+
private long mDischargeStartTime;
private int mDischargeStartLevel;
-
+
private boolean mSentLowBatteryBroadcast = false;
-
+
public BatteryService(Context context) {
mContext = context;
mBatteryStats = BatteryStatsService.getService();
@@ -181,6 +177,7 @@ class BatteryService extends Binder {
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
shutdownIfNoPower();
+ shutdownIfOverTemp();
}
private final void shutdownIfNoPower() {
@@ -194,6 +191,17 @@ class BatteryService extends Binder {
}
}
+ private final void shutdownIfOverTemp() {
+ // shut down gracefully if temperature is too high (> 68.0C)
+ // wait until the system has booted before attempting to display the shutdown dialog.
+ if (mBatteryTemperature > 680 && ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
+
private native void native_update();
private synchronized final void update() {
@@ -203,6 +211,7 @@ class BatteryService extends Binder {
long dischargeDuration = 0;
shutdownIfNoPower();
+ shutdownIfOverTemp();
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
@@ -219,20 +228,20 @@ class BatteryService extends Binder {
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) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
- EventLog.writeEvent(LOG_BATTERY_DISCHARGE_STATUS, dischargeDuration,
+ EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
mDischargeStartLevel, mBatteryLevel);
// make sure we see a discharge event before logging again
- mDischargeStartTime = 0;
+ mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
@@ -244,19 +253,19 @@ class BatteryService extends Binder {
mBatteryHealth != mLastBatteryHealth ||
mBatteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
- EventLog.writeEvent(LOG_BATTERY_STATUS,
+ EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0,
mPlugType, mBatteryTechnology);
}
if (mBatteryLevel != mLastBatteryLevel ||
mBatteryVoltage != mLastBatteryVoltage ||
mBatteryTemperature != mLastBatteryTemperature) {
- EventLog.writeEvent(LOG_BATTERY_LEVEL,
+ EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
}
if (mBatteryLevel != mLastBatteryLevel && mPlugType == BATTERY_PLUGGED_NONE) {
// If the battery level has changed and we are on battery, update the current level.
- // This is used for discharge cycle tracking so this shouldn't be updated while the
+ // This is used for discharge cycle tracking so this shouldn't be updated while the
// battery is charging.
try {
mBatteryStats.recordCurrentLevel(mBatteryLevel);
@@ -271,7 +280,7 @@ class BatteryService extends Binder {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
}
-
+
final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
@@ -285,9 +294,9 @@ class BatteryService extends Binder {
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& mBatteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
-
+
sendIntent();
-
+
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
@@ -311,12 +320,12 @@ class BatteryService extends Binder {
statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
mContext.sendBroadcast(statusIntent);
}
-
+
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
logOutlier(dischargeDuration);
}
-
+
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
mLastBatteryPresent = mBatteryPresent;
@@ -331,13 +340,14 @@ class BatteryService extends Binder {
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);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING);
try {
mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE, mBatteryLevel);
} catch (RemoteException e) {
// Should never happen.
}
-
+
int icon = getIcon(mBatteryLevel);
intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
@@ -352,9 +362,9 @@ class BatteryService extends Binder {
intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
if (false) {
- Log.d(TAG, "updateBattery level:" + mBatteryLevel +
- " scale:" + BATTERY_SCALE + " status:" + mBatteryStatus +
- " health:" + mBatteryHealth + " present:" + mBatteryPresent +
+ Slog.d(TAG, "updateBattery level:" + mBatteryLevel +
+ " scale:" + BATTERY_SCALE + " status:" + mBatteryStatus +
+ " health:" + mBatteryHealth + " present:" + mBatteryPresent +
" voltage: " + mBatteryVoltage +
" temperature: " + mBatteryTemperature +
" technology: " + mBatteryTechnology +
@@ -366,76 +376,65 @@ class BatteryService extends Binder {
}
private final void logBatteryStats() {
-
IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
- if (batteryInfoService != null) {
- byte[] buffer = new byte[DUMP_MAX_LENGTH];
- File dumpFile = null;
- FileOutputStream dumpStream = null;
- try {
- // dump the service to a file
- dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
- dumpStream = new FileOutputStream(dumpFile);
- batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
- dumpStream.getFD().sync();
-
- // read dumped file above into buffer truncated to DUMP_MAX_LENGTH
- // and insert into events table.
- int length = (int) Math.min(dumpFile.length(), DUMP_MAX_LENGTH);
- FileInputStream fileInputStream = new FileInputStream(dumpFile);
- int nread = fileInputStream.read(buffer, 0, length);
- if (nread > 0) {
- Checkin.logEvent(mContext.getContentResolver(),
- Checkin.Events.Tag.BATTERY_DISCHARGE_INFO,
- new String(buffer, 0, nread));
- if (LOCAL_LOGV) Log.v(TAG, "dumped " + nread + "b from " +
- batteryInfoService + "to log");
- if (LOCAL_LOGV) Log.v(TAG, "actual dump:" + new String(buffer, 0, nread));
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to dump service '" + BATTERY_STATS_SERVICE_NAME +
- "':" + e);
- } catch (IOException e) {
- Log.e(TAG, "failed to write dumpsys file: " + e);
- } finally {
- // make sure we clean up
- if (dumpStream != null) {
- try {
- dumpStream.close();
- } catch (IOException e) {
- Log.e(TAG, "failed to close dumpsys output stream");
- }
- }
- if (dumpFile != null && !dumpFile.delete()) {
- Log.e(TAG, "failed to delete temporary dumpsys file: "
- + dumpFile.getAbsolutePath());
+ if (batteryInfoService == null) return;
+
+ DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
+ if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
+
+ File dumpFile = null;
+ FileOutputStream dumpStream = null;
+ try {
+ // dump the service to a file
+ dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
+ dumpStream = new FileOutputStream(dumpFile);
+ batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
+ dumpStream.getFD().sync();
+
+ // add dump file to drop box
+ db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "failed to dump battery service", e);
+ } catch (IOException e) {
+ Slog.e(TAG, "failed to write dumpsys file", e);
+ } finally {
+ // make sure we clean up
+ if (dumpStream != null) {
+ try {
+ dumpStream.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "failed to close dumpsys output stream");
}
}
+ if (dumpFile != null && !dumpFile.delete()) {
+ Slog.e(TAG, "failed to delete temporary dumpsys file: "
+ + dumpFile.getAbsolutePath());
+ }
}
}
-
+
private final void logOutlier(long duration) {
ContentResolver cr = mContext.getContentResolver();
- String dischargeThresholdString = Settings.Gservices.getString(cr,
- Settings.Gservices.BATTERY_DISCHARGE_THRESHOLD);
- String durationThresholdString = Settings.Gservices.getString(cr,
- Settings.Gservices.BATTERY_DISCHARGE_DURATION_THRESHOLD);
-
+ String dischargeThresholdString = Settings.Secure.getString(cr,
+ Settings.Secure.BATTERY_DISCHARGE_THRESHOLD);
+ String durationThresholdString = Settings.Secure.getString(cr,
+ Settings.Secure.BATTERY_DISCHARGE_DURATION_THRESHOLD);
+
if (dischargeThresholdString != null && durationThresholdString != null) {
try {
long durationThreshold = Long.parseLong(durationThresholdString);
int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
- if (duration <= durationThreshold &&
+ if (duration <= durationThreshold &&
mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
// If the discharge cycle is bad enough we want to know about it.
logBatteryStats();
}
- if (LOCAL_LOGV) Log.v(TAG, "duration threshold: " + durationThreshold +
+ if (LOCAL_LOGV) Slog.v(TAG, "duration threshold: " + durationThreshold +
" discharge threshold: " + dischargeThreshold);
- if (LOCAL_LOGV) Log.v(TAG, "duration: " + duration + " discharge: " +
+ if (LOCAL_LOGV) Slog.v(TAG, "duration: " + duration + " discharge: " +
(mDischargeStartLevel - mBatteryLevel));
} catch (NumberFormatException e) {
- Log.e(TAG, "Invalid DischargeThresholds GService string: " +
+ Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
durationThresholdString + " or " + dischargeThresholdString);
return;
}
@@ -458,7 +457,7 @@ class BatteryService extends Binder {
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());
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 590b1e4..f409751 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -1,40 +1,174 @@
/*
-**
-** 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.
-*/
+ * Copyright (C) 2009 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.BroadcastReceiver;
+import android.content.SharedPreferences;
+import android.net.Downloads;
+import android.os.Build;
+import android.os.DropBoxManager;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.RecoverySystem;
+import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Performs a number of miscellaneous, non-system-critical actions
+ * after the system has finished booting.
+ */
+public class BootReceiver extends BroadcastReceiver {
+ private static final String TAG = "BootReceiver";
+
+ // Maximum size of a logged event (files get truncated if they're longer)
+ private static final int LOG_SIZE = 65536;
+
+ private static final File TOMBSTONE_DIR = new File("/data/tombstones");
+
+ // The pre-froyo package and class of the system updater, which
+ // ran in the system process. We need to remove its packages here
+ // in order to clean up after a pre-froyo-to-froyo update.
+ private static final String OLD_UPDATER_PACKAGE =
+ "com.google.android.systemupdater";
+ private static final String OLD_UPDATER_CLASS =
+ "com.google.android.systemupdater.SystemUpdateReceiver";
+
+ // Keep a reference to the observer so the finalizer doesn't disable it.
+ private static FileObserver sTombstoneObserver = null;
-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);
+ public void onReceive(final Context context, Intent intent) {
+ try {
+ // Start the load average overlay, if activated
+ ContentResolver res = context.getContentResolver();
+ if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
+ Intent loadavg = new Intent(context, com.android.server.LoadAverageService.class);
+ context.startService(loadavg);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Can't start load average service", e);
}
+
+ // Log boot events in the background to avoid blocking the main thread with I/O
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ logBootEvents(context);
+ } catch (Exception e) {
+ Slog.e(TAG, "Can't log boot events", e);
+ }
+ try {
+ removeOldUpdatePackages(context);
+ } catch (Exception e) {
+ Slog.e(TAG, "Can't remove old update packages", e);
+ }
+
+ }
+ }.start();
}
-}
+ private void removeOldUpdatePackages(Context ctx) {
+ Downloads.ByUri.removeAllDownloadsByPackage(
+ ctx, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
+ }
+
+ private void logBootEvents(Context ctx) throws IOException {
+ final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
+ final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
+ final String headers = new StringBuilder(512)
+ .append("Build: ").append(Build.FINGERPRINT).append("\n")
+ .append("Hardware: ").append(Build.BOARD).append("\n")
+ .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
+ .append("Radio: ").append(Build.RADIO).append("\n")
+ .append("Kernel: ")
+ .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
+ .append("\n").toString();
+
+ String recovery = RecoverySystem.handleAftermath();
+ if (recovery != null && db != null) {
+ db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
+ }
+
+ if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
+ String now = Long.toString(System.currentTimeMillis());
+ SystemProperties.set("ro.runtime.firstboot", now);
+ if (db != null) db.addText("SYSTEM_BOOT", headers);
+
+ // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
+ addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
+ -LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
+ -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
+ addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
+ -LOG_SIZE, "APANIC_CONSOLE");
+ addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
+ -LOG_SIZE, "APANIC_THREADS");
+ } else {
+ if (db != null) db.addText("SYSTEM_RESTART", headers);
+ }
+
+ // Scan existing tombstones (in case any new ones appeared)
+ File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
+ for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
+ addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
+ LOG_SIZE, "SYSTEM_TOMBSTONE");
+ }
+
+ // Start watching for new tombstone files; will record them as they occur.
+ // This gets registered with the singleton file observer thread.
+ sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
+ @Override
+ public void onEvent(int event, String path) {
+ try {
+ String filename = new File(TOMBSTONE_DIR, path).getPath();
+ addFileToDropBox(db, prefs, headers, filename, LOG_SIZE, "SYSTEM_TOMBSTONE");
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't log tombstone", e);
+ }
+ }
+ };
+
+ sTombstoneObserver.startWatching();
+ }
+
+ private static void addFileToDropBox(
+ DropBoxManager db, SharedPreferences prefs,
+ String headers, String filename, int maxSize, String tag) throws IOException {
+ if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
+
+ File file = new File(filename);
+ long fileTime = file.lastModified();
+ if (fileTime <= 0) return; // File does not exist
+
+ if (prefs != null) {
+ long lastTime = prefs.getLong(filename, 0);
+ if (lastTime == fileTime) return; // Already logged this particular file
+ prefs.edit().putLong(filename, fileTime).commit();
+ }
+
+ Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
+ db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
+ }
+}
diff --git a/services/java/com/android/server/BrickReceiver.java b/services/java/com/android/server/BrickReceiver.java
index 6c4db0d..cff3805 100644
--- a/services/java/com/android/server/BrickReceiver.java
+++ b/services/java/com/android/server/BrickReceiver.java
@@ -20,12 +20,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.os.SystemService;
-import android.util.Log;
+import android.util.Slog;
public class BrickReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Log.w("BrickReceiver", "!!! BRICKING DEVICE !!!");
+ Slog.w("BrickReceiver", "!!! BRICKING DEVICE !!!");
SystemService.start("brick");
}
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3d7025d..81b8d40 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -39,10 +39,12 @@ import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.telephony.Phone;
+import com.android.server.connectivity.Tethering;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -56,15 +58,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = true;
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;
-
// how long to wait before switching back to a radio's default network
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
// system property that can override the above value
private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
"android.telephony.apn-restore";
+
+ private Tethering mTethering;
+ private boolean mTetheringConfigValid = false;
+
/**
* Sometimes we want to refer to the individual network state
* trackers separately, and sometimes we just want to treat them
@@ -78,8 +81,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private List mNetRequestersPids[];
- private WifiWatchdogService mWifiWatchdogService;
-
// priority order of the nettrackers
// (excluding dynamically set mNetworkPreference)
// TODO - move mNetworkTypePreference into this
@@ -101,9 +102,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private List mFeatureUsers;
private boolean mSystemReady;
- private ArrayList<Intent> mDeferredBroadcasts;
+ private Intent mInitialBroadcast;
- private class NetworkAttributes {
+ private static class NetworkAttributes {
/**
* Class for holding settings read from resources.
*/
@@ -115,23 +116,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public NetworkAttributes(String init) {
String fragments[] = init.split(",");
mName = fragments[0].toLowerCase();
- if (fragments[1].toLowerCase().equals("wifi")) {
- mRadio = ConnectivityManager.TYPE_WIFI;
- } else {
- mRadio = ConnectivityManager.TYPE_MOBILE;
- }
- if (mName.equals("default")) {
- mType = mRadio;
- } else if (mName.equals("mms")) {
- mType = ConnectivityManager.TYPE_MOBILE_MMS;
- } else if (mName.equals("supl")) {
- mType = ConnectivityManager.TYPE_MOBILE_SUPL;
- } else if (mName.equals("dun")) {
- mType = ConnectivityManager.TYPE_MOBILE_DUN;
- } else if (mName.equals("hipri")) {
- mType = ConnectivityManager.TYPE_MOBILE_HIPRI;
- }
- mPriority = Integer.parseInt(fragments[2]);
+ mType = Integer.parseInt(fragments[1]);
+ mRadio = Integer.parseInt(fragments[2]);
+ mPriority = Integer.parseInt(fragments[3]);
mLastState = NetworkInfo.State.UNKNOWN;
}
public boolean isDefault() {
@@ -139,22 +126,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
NetworkAttributes[] mNetAttributes;
+ int mNetworksDefined;
- private class RadioAttributes {
- public String mName;
- public int mPriority;
+ private static class RadioAttributes {
public int mSimultaneity;
public int mType;
public RadioAttributes(String init) {
String fragments[] = init.split(",");
- mName = fragments[0].toLowerCase();
- mPriority = Integer.parseInt(fragments[1]);
- mSimultaneity = Integer.parseInt(fragments[2]);
- if (mName.equals("wifi")) {
- mType = ConnectivityManager.TYPE_WIFI;
- } else {
- mType = ConnectivityManager.TYPE_MOBILE;
- }
+ mType = Integer.parseInt(fragments[0]);
+ mSimultaneity = Integer.parseInt(fragments[1]);
}
}
RadioAttributes[] mRadioAttributes;
@@ -187,7 +167,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// Wait until sServiceInstance has been initialized.
thread.wait();
} catch (InterruptedException ignore) {
- Log.e(TAG,
+ Slog.e(TAG,
"Unexpected InterruptedException while waiting"+
" for ConnectivityService thread");
}
@@ -203,7 +183,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
private ConnectivityService(Context context) {
- if (DBG) Log.v(TAG, "ConnectivityService starting up");
+ if (DBG) Slog.v(TAG, "ConnectivityService starting up");
+
+ // setup our unique device name
+ String id = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ if (id != null && id.length() > 0) {
+ String name = new String("android_").concat(id);
+ SystemProperties.set("net.hostname", name);
+ }
+
mContext = context;
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -211,48 +200,87 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetworkPreference = getPersistedNetworkPreference();
+ mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
+ mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
+
// Load device network attributes from resources
- mNetAttributes = new NetworkAttributes[
- ConnectivityManager.MAX_NETWORK_TYPE+1];
- mRadioAttributes = new RadioAttributes[
- ConnectivityManager.MAX_RADIO_TYPE+1];
- String[] naStrings = context.getResources().getStringArray(
- com.android.internal.R.array.networkAttributes);
- // TODO - what if the setting has gaps/unknown types?
- for (String a : naStrings) {
- NetworkAttributes n = new NetworkAttributes(a);
- mNetAttributes[n.mType] = n;
- }
String[] raStrings = context.getResources().getStringArray(
com.android.internal.R.array.radioAttributes);
- for (String a : raStrings) {
- RadioAttributes r = new RadioAttributes(a);
+ for (String raString : raStrings) {
+ RadioAttributes r = new RadioAttributes(raString);
+ if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
+ Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
+ continue;
+ }
+ if (mRadioAttributes[r.mType] != null) {
+ Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
+ r.mType);
+ continue;
+ }
mRadioAttributes[r.mType] = r;
}
+ String[] naStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.networkAttributes);
+ for (String naString : naStrings) {
+ try {
+ NetworkAttributes n = new NetworkAttributes(naString);
+ if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
+ Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
+ n.mType);
+ continue;
+ }
+ if (mNetAttributes[n.mType] != null) {
+ Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
+ n.mType);
+ continue;
+ }
+ if (mRadioAttributes[n.mRadio] == null) {
+ Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
+ "radio " + n.mRadio + " in network type " + n.mType);
+ continue;
+ }
+ mNetAttributes[n.mType] = n;
+ mNetworksDefined++;
+ } catch(Exception e) {
+ // ignore it - leave the entry null
+ }
+ }
+
// high priority first
- mPriorityList = new int[naStrings.length];
+ mPriorityList = new int[mNetworksDefined];
{
- int priority = 0; //lowest
- int nextPos = naStrings.length-1;
- while (nextPos>-1) {
- for (int i = 0; i < mNetAttributes.length; i++) {
- if(mNetAttributes[i].mPriority == priority) {
- mPriorityList[nextPos--] = i;
+ int insertionPoint = mNetworksDefined-1;
+ int currentLowest = 0;
+ int nextLowest = 0;
+ while (insertionPoint > -1) {
+ for (NetworkAttributes na : mNetAttributes) {
+ if (na == null) continue;
+ if (na.mPriority < currentLowest) continue;
+ if (na.mPriority > currentLowest) {
+ if (na.mPriority < nextLowest || nextLowest == 0) {
+ nextLowest = na.mPriority;
+ }
+ continue;
}
+ mPriorityList[insertionPoint--] = na.mType;
}
- priority++;
+ currentLowest = nextLowest;
+ nextLowest = 0;
}
}
- mNetRequestersPids =
- new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
- for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) {
+ mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
+ for (int i : mPriorityList) {
mNetRequestersPids[i] = new ArrayList();
}
mFeatureUsers = new ArrayList();
+ mNumDnsEntries = 0;
+
+ mTestMode = SystemProperties.get("cm.test.mode").equals("true")
+ && SystemProperties.get("ro.build.type").equals("eng");
/*
* Create the network state trackers for Wi-Fi and mobile
* data. Maybe this could be done with a factory class,
@@ -260,49 +288,45 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* the number of different network types is not going
* to change very often.
*/
- if (DBG) Log.v(TAG, "Starting Wifi Service.");
- WifiStateTracker wst = new WifiStateTracker(context, mHandler);
- WifiService wifiService = new WifiService(context, wst);
- ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
-
- mNetTrackers[ConnectivityManager.TYPE_MOBILE] =
- new MobileDataStateTracker(context, mHandler,
- ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT,
- "MOBILE");
-
- mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] =
- new MobileDataStateTracker(context, mHandler,
- ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS,
- "MOBILE_MMS");
-
- mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] =
- new MobileDataStateTracker(context, mHandler,
- ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL,
- "MOBILE_SUPL");
-
- mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] =
- new MobileDataStateTracker(context, mHandler,
- ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN,
- "MOBILE_DUN");
-
- mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] =
- new MobileDataStateTracker(context, mHandler,
- ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI,
- "MOBILE_HIPRI");
-
- mNumDnsEntries = 0;
-
- mTestMode = SystemProperties.get("cm.test.mode").equals("true")
- && SystemProperties.get("ro.build.type").equals("eng");
+ boolean noMobileData = !getMobileDataEnabled();
+ for (int netType : mPriorityList) {
+ switch (mNetAttributes[netType].mRadio) {
+ case ConnectivityManager.TYPE_WIFI:
+ if (DBG) Slog.v(TAG, "Starting Wifi Service.");
+ WifiStateTracker wst = new WifiStateTracker(context, mHandler);
+ WifiService wifiService = new WifiService(context, wst);
+ ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
+ wifiService.startWifi();
+ mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
+ wst.startMonitoring();
+
+ break;
+ case ConnectivityManager.TYPE_MOBILE:
+ mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
+ netType, mNetAttributes[netType].mName);
+ mNetTrackers[netType].startMonitoring();
+ if (noMobileData) {
+ if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
+ mNetTrackers[netType].teardown();
+ }
+ break;
+ default:
+ Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
+ mNetAttributes[netType].mRadio);
+ continue;
+ }
+ }
- for (NetworkStateTracker t : mNetTrackers)
- t.startMonitoring();
+ mTethering = new Tethering(mContext, mHandler.getLooper());
+ mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
+ !mTethering.isDunRequired()) &&
+ (mTethering.getTetherableUsbRegexs().length != 0 ||
+ mTethering.getTetherableWifiRegexs().length != 0) &&
+ mTethering.getUpstreamIfaceRegexs().length != 0);
- // Constructing this starts it too
- mWifiWatchdogService = new WifiWatchdogService(context, wst);
}
+
/**
* Sets the preferred network.
* @param preference the new preference
@@ -310,6 +334,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
if (ConnectivityManager.isNetworkTypeValid(preference) &&
+ mNetAttributes[preference] != null &&
mNetAttributes[preference].isDefault()) {
if (mNetworkPreference != preference) {
persistNetworkPreference(preference);
@@ -357,10 +382,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return;
for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
- if (t != mNetworkPreference &&
+ if (t != mNetworkPreference && mNetTrackers[t] != null &&
mNetTrackers[t].getNetworkInfo().isConnected()) {
if (DBG) {
- Log.d(TAG, "tearing down " +
+ Slog.d(TAG, "tearing down " +
mNetTrackers[t].getNetworkInfo() +
" in enforcePreference");
}
@@ -388,13 +413,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- if (!mNetAttributes[type].isDefault()) {
+ if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
continue;
}
NetworkStateTracker t = mNetTrackers[type];
NetworkInfo info = t.getNetworkInfo();
if (info.isConnected()) {
- if (DBG && type != mActiveDefaultNetwork) Log.e(TAG,
+ if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
"connected default network is not " +
"mActiveDefaultNetwork!");
return info;
@@ -415,10 +440,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public NetworkInfo[] getAllNetworkInfo() {
enforceAccessPermission();
- NetworkInfo[] result = new NetworkInfo[mNetTrackers.length];
+ NetworkInfo[] result = new NetworkInfo[mNetworksDefined];
int i = 0;
for (NetworkStateTracker t : mNetTrackers) {
- result[i++] = t.getNetworkInfo();
+ if(t != null) result[i++] = t.getNetworkInfo();
}
return result;
}
@@ -427,7 +452,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
boolean result = true;
enforceChangePermission();
for (NetworkStateTracker t : mNetTrackers) {
- result = t.setRadio(turnOn) && result;
+ if (t != null) result = t.setRadio(turnOn) && result;
}
return result;
}
@@ -477,14 +502,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
public void binderDied() {
- Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
+ Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
(System.currentTimeMillis() - mCreateTime) + " mSec ago");
stopUsingNetworkFeature(this, false);
}
public void expire() {
- Log.d(TAG, "ConnectivityService FeatureUser expire(" +
+ Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
(System.currentTimeMillis() - mCreateTime) + " mSec ago");
stopUsingNetworkFeature(this, false);
@@ -500,11 +525,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public int startUsingNetworkFeature(int networkType, String feature,
IBinder binder) {
if (DBG) {
- Log.d(TAG, "startUsingNetworkFeature for net " + networkType +
+ Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
": " + feature);
}
enforceChangePermission();
- if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
+ if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
+ mNetAttributes[networkType] == null) {
return Phone.APN_REQUEST_FAILED;
}
@@ -513,6 +539,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// TODO - move this into the MobileDataStateTracker
int usedNetworkType = networkType;
if(networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (!getMobileDataEnabled()) {
+ if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
@@ -532,7 +562,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
NetworkInfo ni = network.getNetworkInfo();
if (ni.isAvailable() == false) {
- if (DBG) Log.d(TAG, "special network not available");
+ if (DBG) Slog.d(TAG, "special network not available");
return Phone.APN_TYPE_NOT_AVAILABLE;
}
@@ -553,17 +583,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (ni.isConnected() == true) {
// add the pid-specific dns
handleDnsConfigurationChange();
- if (DBG) Log.d(TAG, "special network already active");
+ if (DBG) Slog.d(TAG, "special network already active");
return Phone.APN_ALREADY_ACTIVE;
}
- if (DBG) Log.d(TAG, "special network already connecting");
+ if (DBG) Slog.d(TAG, "special network already connecting");
return Phone.APN_REQUEST_STARTED;
}
// check if the radio in play can make another contact
// assume if cannot for now
- if (DBG) Log.d(TAG, "reconnecting to special network");
+ if (DBG) Slog.d(TAG, "reconnecting to special network");
network.reconnect();
return Phone.APN_REQUEST_STARTED;
} else {
@@ -583,6 +613,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// javadoc from interface
public int stopUsingNetworkFeature(int networkType, String feature) {
+ enforceChangePermission();
+
int pid = getCallingPid();
int uid = getCallingUid();
@@ -605,7 +637,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return stopUsingNetworkFeature(u, true);
} else {
// none found!
- if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
+ if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
return 1;
}
}
@@ -620,10 +652,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
boolean callTeardown = false; // used to carry our decision outside of sync block
if (DBG) {
- Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
+ Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
": " + feature);
}
- enforceChangePermission();
+
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return -1;
}
@@ -633,6 +665,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
synchronized(this) {
// check if this process still has an outstanding start request
if (!mFeatureUsers.contains(u)) {
+ if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
return 1;
}
u.unlinkDeathRecipient();
@@ -650,7 +683,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (x.mUid == u.mUid && x.mPid == u.mPid &&
x.mNetworkType == u.mNetworkType &&
TextUtils.equals(x.mFeature, u.mFeature)) {
- if (DBG) Log.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
+ if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
return 1;
}
}
@@ -670,19 +703,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
tracker = mNetTrackers[usedNetworkType];
- if(usedNetworkType != networkType) {
+ if (tracker == null) {
+ if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
+ return -1;
+ }
+ if (usedNetworkType != networkType) {
Integer currentPid = new Integer(pid);
mNetRequestersPids[usedNetworkType].remove(currentPid);
reassessPidDns(pid, true);
if (mNetRequestersPids[usedNetworkType].size() != 0) {
- if (DBG) Log.d(TAG, "not tearing down special network - " +
+ if (DBG) Slog.d(TAG, "not tearing down special network - " +
"others still using it");
return 1;
}
callTeardown = true;
}
}
-
+ if (DBG) Slog.d(TAG, "Doing network teardown");
if (callTeardown) {
tracker.teardown();
return 1;
@@ -708,9 +745,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
NetworkStateTracker tracker = mNetTrackers[networkType];
- if (!tracker.getNetworkInfo().isConnected() || tracker.isTeardownRequested()) {
+ if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
+ tracker.isTeardownRequested()) {
if (DBG) {
- Log.d(TAG, "requestRouteToHost on down network (" + networkType + " - dropped");
+ Slog.d(TAG, "requestRouteToHost on down network (" + networkType + ") - dropped");
}
return false;
}
@@ -744,11 +782,51 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mContext.sendBroadcast(broadcast);
}
+ /**
+ * @see ConnectivityManager#getMobileDataEnabled()
+ */
+ public boolean getMobileDataEnabled() {
+ enforceAccessPermission();
+ boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.MOBILE_DATA, 1) == 1;
+ if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
+ return retVal;
+ }
+
+ /**
+ * @see ConnectivityManager#setMobileDataEnabled(boolean)
+ */
+ public synchronized void setMobileDataEnabled(boolean enabled) {
+ enforceChangePermission();
+ if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
+
+ if (getMobileDataEnabled() == enabled) return;
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
+
+ if (enabled) {
+ if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
+ if (DBG) Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
+ }
+ } else {
+ for (NetworkStateTracker nt : mNetTrackers) {
+ if (nt == null) continue;
+ int netType = nt.getNetworkInfo().getType();
+ if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
+ if (DBG) Slog.d(TAG, "tearing down " + nt);
+ nt.teardown();
+ }
+ }
+ }
+ }
+
private int getNumConnectedNetworks() {
int numConnectedNets = 0;
for (NetworkStateTracker nt : mNetTrackers) {
- if (nt.getNetworkInfo().isConnected() &&
+ if (nt != null && nt.getNetworkInfo().isConnected() &&
!nt.isTeardownRequested()) {
++numConnectedNets;
}
@@ -768,6 +846,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
"ConnectivityService");
}
+ // TODO Make this a special check when it goes public
+ private void enforceTetherChangePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "ConnectivityService");
+ }
+
+ private void enforceTetherAccessPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_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
@@ -798,6 +889,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (info.isFailover()) {
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -848,8 +940,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int newType = -1;
int newPriority = -1;
+ boolean noMobileData = !getMobileDataEnabled();
for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
- if (checkType == prevNetType) {
+ if (checkType == prevNetType) continue;
+ if (mNetAttributes[checkType] == null) continue;
+ if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
+ noMobileData) {
+ if (DBG) {
+ Slog.d(TAG, "not failing over to mobile type " + checkType +
+ " because Mobile Data Disabled");
+ }
continue;
}
if (mNetAttributes[checkType].isDefault()) {
@@ -860,10 +960,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
newType = checkType;
break;
}
- if (mRadioAttributes[mNetAttributes[checkType].mRadio].
- mPriority > newPriority) {
+ if (mNetAttributes[checkType].mPriority > newPriority) {
newType = checkType;
- newPriority = mRadioAttributes[mNetAttributes[newType].mRadio].mPriority;
+ newPriority = mNetAttributes[newType].mPriority;
}
}
}
@@ -886,15 +985,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
if (DBG) {
if (switchTo.isConnected()) {
- Log.v(TAG, "Switching to already connected " +
+ Slog.v(TAG, "Switching to already connected " +
switchTo.getTypeName());
} else {
- Log.v(TAG, "Attempting to switch to " +
+ Slog.v(TAG, "Attempting to switch to " +
switchTo.getTypeName());
}
}
} else {
newNet.reconnect();
+ newNet = null; // not officially avail.. try anyway, but
+ // report no failover
}
}
}
@@ -904,6 +1005,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void sendConnectedBroadcast(NetworkInfo info) {
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (info.isFailover()) {
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -936,11 +1038,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} else {
reasonText = " (" + reason + ").";
}
- Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
+ Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
" failed" + reasonText);
}
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (getActiveNetworkInfo() == null) {
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
@@ -982,26 +1085,20 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void sendStickyBroadcast(Intent intent) {
synchronized(this) {
- if (mSystemReady) {
- mContext.sendStickyBroadcast(intent);
- } else {
- if (mDeferredBroadcasts == null) {
- mDeferredBroadcasts = new ArrayList<Intent>();
- }
- mDeferredBroadcasts.add(intent);
+ if (!mSystemReady) {
+ mInitialBroadcast = new Intent(intent);
}
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendStickyBroadcast(intent);
}
}
void systemReady() {
synchronized(this) {
mSystemReady = true;
- if (mDeferredBroadcasts != null) {
- int count = mDeferredBroadcasts.size();
- for (int i = 0; i < count; i++) {
- mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i));
- }
- mDeferredBroadcasts = null;
+ if (mInitialBroadcast != null) {
+ mContext.sendStickyBroadcast(mInitialBroadcast);
+ mInitialBroadcast = null;
}
}
}
@@ -1022,7 +1119,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetAttributes[type].mPriority) ||
mNetworkPreference == mActiveDefaultNetwork) {
// don't accept this one
- if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +
+ if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
"to torn down network " + info.getTypeName());
teardown(thisNet);
return;
@@ -1030,11 +1127,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// tear down the other
NetworkStateTracker otherNet =
mNetTrackers[mActiveDefaultNetwork];
- if (DBG) Log.v(TAG, "Policy requires " +
+ if (DBG) Slog.v(TAG, "Policy requires " +
otherNet.getNetworkInfo().getTypeName() +
" teardown");
if (!teardown(otherNet)) {
- Log.e(TAG, "Network declined teardown request");
+ Slog.e(TAG, "Network declined teardown request");
return;
}
if (isFailover) {
@@ -1053,7 +1150,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void handleScanResultsAvailable(NetworkInfo info) {
int networkType = info.getType();
if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " +
+ if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
info.getTypeName() + " network. Don't know how to handle.");
}
@@ -1116,7 +1213,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private void reassessPidDns(int myPid, boolean doBump)
{
- if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid);
+ if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
for(int i : mPriorityList) {
if (mNetAttributes[i].isDefault()) {
continue;
@@ -1188,14 +1285,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
for (String dns : dnsList) {
if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
if (DBG) {
- Log.d(TAG, "adding dns " + dns + " for " +
+ Slog.d(TAG, "adding dns " + dns + " for " +
nt.getNetworkInfo().getTypeName());
}
SystemProperties.set("net.dns" + j++, dns);
}
}
for (int k=j ; k<mNumDnsEntries; k++) {
- if (DBG) Log.d(TAG, "erasing net.dns" + k);
+ if (DBG) Slog.d(TAG, "erasing net.dns" + k);
SystemProperties.set("net.dns" + k, "");
}
mNumDnsEntries = j;
@@ -1264,6 +1361,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
pw.println(requester.toString());
}
pw.println();
+
+ mTethering.dump(fd, pw, args);
}
// must be stateless - things change under us.
@@ -1286,7 +1385,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (DBG) {
// TODO - remove this after we validate the dropping doesn't break
// anything
- Log.d(TAG, "Dropping ConnectivityChange for " +
+ Slog.d(TAG, "Dropping ConnectivityChange for " +
info.getTypeName() + ": " +
state + "/" + info.getDetailedState());
}
@@ -1294,7 +1393,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
mNetAttributes[type].mLastState = state;
- if (DBG) Log.d(TAG, "ConnectivityChange for " +
+ if (DBG) Slog.d(TAG, "ConnectivityChange for " +
info.getTypeName() + ": " +
state + "/" + info.getDetailedState());
@@ -1308,7 +1407,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int eventLogParam = (info.getType() & 0x7) |
((info.getDetailedState().ordinal() & 0x3f) << 3) |
(info.getSubtype() << 9);
- EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED,
+ EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
eventLogParam);
if (info.getDetailedState() ==
@@ -1357,4 +1456,84 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
}
+
+ // javadoc from interface
+ public int tether(String iface) {
+ enforceTetherChangePermission();
+
+ if (isTetheringSupported()) {
+ return mTethering.tether(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
+ }
+
+ // javadoc from interface
+ public int untether(String iface) {
+ enforceTetherChangePermission();
+
+ if (isTetheringSupported()) {
+ return mTethering.untether(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
+ }
+
+ // javadoc from interface
+ public int getLastTetherError(String iface) {
+ enforceTetherAccessPermission();
+
+ if (isTetheringSupported()) {
+ return mTethering.getLastTetherError(iface);
+ } else {
+ return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
+ }
+ }
+
+ // TODO - proper iface API for selection by property, inspection, etc
+ public String[] getTetherableUsbRegexs() {
+ enforceTetherAccessPermission();
+ if (isTetheringSupported()) {
+ return mTethering.getTetherableUsbRegexs();
+ } else {
+ return new String[0];
+ }
+ }
+
+ public String[] getTetherableWifiRegexs() {
+ enforceTetherAccessPermission();
+ if (isTetheringSupported()) {
+ return mTethering.getTetherableWifiRegexs();
+ } else {
+ return new String[0];
+ }
+ }
+
+ // TODO - move iface listing, queries, etc to new module
+ // javadoc from interface
+ public String[] getTetherableIfaces() {
+ enforceTetherAccessPermission();
+ return mTethering.getTetherableIfaces();
+ }
+
+ public String[] getTetheredIfaces() {
+ enforceTetherAccessPermission();
+ return mTethering.getTetheredIfaces();
+ }
+
+ public String[] getTetheringErroredIfaces() {
+ enforceTetherAccessPermission();
+ return mTethering.getErroredIfaces();
+ }
+
+ // if ro.tether.denied = true we default to no tethering
+ // gservices could set the secure setting to 1 though to enable it on a build where it
+ // had previously been turned off.
+ public boolean isTetheringSupported() {
+ enforceTetherAccessPermission();
+ int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
+ boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
+ return tetherEnabledInSettings && mTetheringConfigValid;
+ }
}
diff --git a/services/java/com/android/server/DemoDataSet.java b/services/java/com/android/server/DemoDataSet.java
index 0de7c1e..277985f 100644
--- a/services/java/com/android/server/DemoDataSet.java
+++ b/services/java/com/android/server/DemoDataSet.java
@@ -27,7 +27,7 @@ import android.provider.Contacts;
import android.provider.Settings;
import android.provider.MediaStore.Images;
import android.util.Config;
-import android.util.Log;
+import android.util.Slog;
import java.io.File;
import java.io.FileNotFoundException;
@@ -62,7 +62,7 @@ public class DemoDataSet
int count = files.length;
if (count == 0) {
- Log.i(LOG_TAG, "addDefaultImages: no images found!");
+ Slog.i(LOG_TAG, "addDefaultImages: no images found!");
return;
}
@@ -74,14 +74,14 @@ public class DemoDataSet
try {
Images.Media.insertImage(mContentResolver, path, name, null);
} catch (FileNotFoundException e) {
- Log.e(LOG_TAG, "Failed to import image " + path, e);
+ Slog.e(LOG_TAG, "Failed to import image " + path, e);
}
}
}
private final void addDefaultData()
{
- Log.i(LOG_TAG, "Adding default data...");
+ Slog.i(LOG_TAG, "Adding default data...");
// addImage("Violet", "images/violet.png");
// addImage("Corky", "images/corky.png");
@@ -124,7 +124,7 @@ public class DemoDataSet
}
catch (Exception e)
{
- Log.e(LOG_TAG, "Failed to insert image '" + file + "'", e);
+ Slog.e(LOG_TAG, "Failed to insert image '" + file + "'", e);
url = null;
}
@@ -133,7 +133,7 @@ public class DemoDataSet
private final Uri addShortcut(String shortcut, Intent intent)
{
- if (Config.LOGV) Log.v(LOG_TAG, "addShortcut: shortcut=" + shortcut + ", intent=" + intent);
+ if (Config.LOGV) Slog.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/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
new file mode 100644
index 0000000..7fb7db0
--- /dev/null
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.widget.LockPatternUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.Activity;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.IDevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.RecoverySystem;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.util.Xml;
+import android.view.WindowManagerPolicy;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Implementation of the device policy APIs.
+ */
+public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ static final String TAG = "DevicePolicyManagerService";
+
+ final Context mContext;
+ final MyPackageMonitor mMonitor;
+
+ IPowerManager mIPowerManager;
+
+ int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ int mActivePasswordLength = 0;
+ int mFailedPasswordAttempts = 0;
+
+ int mPasswordOwner = -1;
+
+ final HashMap<ComponentName, ActiveAdmin> mAdminMap
+ = new HashMap<ComponentName, ActiveAdmin>();
+ final ArrayList<ActiveAdmin> mAdminList
+ = new ArrayList<ActiveAdmin>();
+
+ static class ActiveAdmin {
+ final DeviceAdminInfo info;
+
+ int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ int minimumPasswordLength = 0;
+ long maximumTimeToUnlock = 0;
+ int maximumFailedPasswordsForWipe = 0;
+
+ ActiveAdmin(DeviceAdminInfo _info) {
+ info = _info;
+ }
+
+ int getUid() { return info.getActivityInfo().applicationInfo.uid; }
+
+ void writeToXml(XmlSerializer out)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ out.startTag(null, "policies");
+ info.writePoliciesToXml(out);
+ out.endTag(null, "policies");
+ if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ out.startTag(null, "password-quality");
+ out.attribute(null, "value", Integer.toString(passwordQuality));
+ out.endTag(null, "password-quality");
+ if (minimumPasswordLength > 0) {
+ out.startTag(null, "min-password-length");
+ out.attribute(null, "value", Integer.toString(minimumPasswordLength));
+ out.endTag(null, "mn-password-length");
+ }
+ }
+ if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ out.startTag(null, "max-time-to-unlock");
+ out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
+ out.endTag(null, "max-time-to-unlock");
+ }
+ if (maximumFailedPasswordsForWipe != 0) {
+ out.startTag(null, "max-failed-password-wipe");
+ out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
+ out.endTag(null, "max-failed-password-wipe");
+ }
+ }
+
+ void readFromXml(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 tag = parser.getName();
+ if ("policies".equals(tag)) {
+ info.readPoliciesFromXml(parser);
+ } else if ("password-quality".equals(tag)) {
+ passwordQuality = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("min-password-length".equals(tag)) {
+ minimumPasswordLength = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else if ("max-time-to-unlock".equals(tag)) {
+ maximumTimeToUnlock = Long.parseLong(
+ parser.getAttributeValue(null, "value"));
+ } else if ("max-failed-password-wipe".equals(tag)) {
+ maximumFailedPasswordsForWipe = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ } else {
+ Slog.w(TAG, "Unknown admin tag: " + tag);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("uid="); pw.println(getUid());
+ pw.print(prefix); pw.println("policies:");
+ ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
+ if (pols != null) {
+ for (int i=0; i<pols.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
+ }
+ }
+ pw.print(prefix); pw.print("passwordQuality=0x");
+ pw.print(Integer.toHexString(passwordQuality));
+ pw.print(" minimumPasswordLength=");
+ pw.println(minimumPasswordLength);
+ pw.print(prefix); pw.print("maximumTimeToUnlock=");
+ pw.println(maximumTimeToUnlock);
+ pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
+ pw.println(maximumFailedPasswordsForWipe);
+ }
+ }
+
+ class MyPackageMonitor extends PackageMonitor {
+ public void onSomePackagesChanged() {
+ synchronized (DevicePolicyManagerService.this) {
+ boolean removed = false;
+ for (int i=mAdminList.size()-1; i>=0; i--) {
+ ActiveAdmin aa = mAdminList.get(i);
+ int change = isPackageDisappearing(aa.info.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ Slog.w(TAG, "Admin unexpectedly uninstalled: "
+ + aa.info.getComponent());
+ removed = true;
+ mAdminList.remove(i);
+ } else if (isPackageModified(aa.info.getPackageName())) {
+ try {
+ mContext.getPackageManager().getReceiverInfo(
+ aa.info.getComponent(), 0);
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Admin package change removed component: "
+ + aa.info.getComponent());
+ removed = true;
+ mAdminList.remove(i);
+ }
+ }
+ }
+ if (removed) {
+ validatePasswordOwnerLocked();
+ }
+ }
+ }
+ }
+
+ /**
+ * Instantiates the service.
+ */
+ public DevicePolicyManagerService(Context context) {
+ mContext = context;
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
+ }
+
+ private IPowerManager getIPowerManager() {
+ if (mIPowerManager == null) {
+ IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
+ mIPowerManager = IPowerManager.Stub.asInterface(b);
+ }
+ return mIPowerManager;
+ }
+
+ ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
+ ActiveAdmin admin = mAdminMap.get(who);
+ if (admin != null
+ && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
+ && who.getClassName().equals(admin.info.getActivityInfo().name)) {
+ return admin;
+ }
+ return null;
+ }
+
+ ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
+ throws SecurityException {
+ final int callingUid = Binder.getCallingUid();
+ if (who != null) {
+ ActiveAdmin admin = mAdminMap.get(who);
+ if (admin == null) {
+ throw new SecurityException("No active admin " + who);
+ }
+ if (admin.getUid() != callingUid) {
+ throw new SecurityException("Admin " + who + " is not owned by uid "
+ + Binder.getCallingUid());
+ }
+ if (!admin.info.usesPolicy(reqPolicy)) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " did not specify uses-policy for: "
+ + admin.info.getTagForPolicy(reqPolicy));
+ }
+ return admin;
+ } else {
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
+ return admin;
+ }
+ }
+ throw new SecurityException("No active admin owned by uid "
+ + Binder.getCallingUid() + " for policy #" + reqPolicy);
+ }
+ }
+
+ void sendAdminCommandLocked(ActiveAdmin admin, String action) {
+ Intent intent = new Intent(action);
+ intent.setComponent(admin.info.getComponent());
+ mContext.sendBroadcast(intent);
+ }
+
+ void sendAdminCommandLocked(String action, int reqPolicy) {
+ final int N = mAdminList.size();
+ if (N > 0) {
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (admin.info.usesPolicy(reqPolicy)) {
+ sendAdminCommandLocked(admin, action);
+ }
+ }
+ }
+ }
+
+ void removeActiveAdminLocked(ComponentName adminReceiver) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+ if (admin != null) {
+ sendAdminCommandLocked(admin,
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
+ // XXX need to wait for it to complete.
+ mAdminList.remove(admin);
+ mAdminMap.remove(adminReceiver);
+ validatePasswordOwnerLocked();
+ }
+ }
+
+ public DeviceAdminInfo findAdmin(ComponentName adminName) {
+ Intent resolveIntent = new Intent();
+ resolveIntent.setComponent(adminName);
+ List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+ resolveIntent, PackageManager.GET_META_DATA);
+ if (infos == null || infos.size() <= 0) {
+ throw new IllegalArgumentException("Unknown admin: " + adminName);
+ }
+
+ try {
+ return new DeviceAdminInfo(mContext, infos.get(0));
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+ return null;
+ } catch (IOException e) {
+ Slog.w(TAG, "Bad device admin requested: " + adminName, e);
+ return null;
+ }
+ }
+
+ private static JournaledFile makeJournaledFile() {
+ final String base = "/data/system/device_policies.xml";
+ return new JournaledFile(new File(base), new File(base + ".tmp"));
+ }
+
+ private void saveSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(journal.chooseForWrite(), false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+ out.startTag(null, "policies");
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin ap = mAdminList.get(i);
+ if (ap != null) {
+ out.startTag(null, "admin");
+ out.attribute(null, "name", ap.info.getComponent().flattenToString());
+ ap.writeToXml(out);
+ out.endTag(null, "admin");
+ }
+ }
+
+ if (mPasswordOwner >= 0) {
+ out.startTag(null, "password-owner");
+ out.attribute(null, "value", Integer.toString(mPasswordOwner));
+ out.endTag(null, "password-owner");
+ }
+
+ if (mFailedPasswordAttempts != 0) {
+ out.startTag(null, "failed-password-attempts");
+ out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
+ out.endTag(null, "failed-password-attempts");
+ }
+
+ if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
+ out.startTag(null, "active-password");
+ out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
+ out.attribute(null, "length", Integer.toString(mActivePasswordLength));
+ out.endTag(null, "active-password");
+ }
+
+ out.endTag(null, "policies");
+
+ out.endDocument();
+ stream.close();
+ journal.commit();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ journal.rollback();
+ }
+ }
+
+ private void loadSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileInputStream stream = null;
+ File file = journal.chooseForRead();
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+ String tag = parser.getName();
+ if (!"policies".equals(tag)) {
+ throw new XmlPullParserException(
+ "Settings do not start with policies tag: found " + tag);
+ }
+ type = parser.next();
+ 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;
+ }
+ tag = parser.getName();
+ if ("admin".equals(tag)) {
+ String name = parser.getAttributeValue(null, "name");
+ try {
+ DeviceAdminInfo dai = findAdmin(
+ ComponentName.unflattenFromString(name));
+ if (dai != null) {
+ ActiveAdmin ap = new ActiveAdmin(dai);
+ ap.readFromXml(parser);
+ mAdminMap.put(ap.info.getComponent(), ap);
+ mAdminList.add(ap);
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed loading admin " + name, e);
+ }
+ } else if ("failed-password-attempts".equals(tag)) {
+ mFailedPasswordAttempts = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ XmlUtils.skipCurrentTag(parser);
+ } else if ("password-owner".equals(tag)) {
+ mPasswordOwner = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
+ XmlUtils.skipCurrentTag(parser);
+ } else if ("active-password".equals(tag)) {
+ mActivePasswordQuality = Integer.parseInt(
+ parser.getAttributeValue(null, "quality"));
+ mActivePasswordLength = Integer.parseInt(
+ parser.getAttributeValue(null, "length"));
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ Slog.w(TAG, "Unknown tag: " + tag);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "failed parsing " + file + " " + e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ // Validate that what we stored for the password quality matches
+ // sufficiently what is currently set. Note that this is only
+ // a sanity check in case the two get out of sync; this should
+ // never normally happen.
+ LockPatternUtils utils = new LockPatternUtils(mContext);
+ if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
+ Slog.w(TAG, "Active password quality 0x"
+ + Integer.toHexString(mActivePasswordQuality)
+ + " does not match actual quality 0x"
+ + Integer.toHexString(utils.getActivePasswordQuality()));
+ mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ mActivePasswordLength = 0;
+ }
+
+ validatePasswordOwnerLocked();
+
+ long timeMs = getMaximumTimeToLock(null);
+ if (timeMs <= 0) {
+ timeMs = Integer.MAX_VALUE;
+ }
+ try {
+ getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure talking with power manager", e);
+ }
+ }
+
+ static void validateQualityConstant(int quality) {
+ switch (quality) {
+ case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
+ case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+ case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+ case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+ return;
+ }
+ throw new IllegalArgumentException("Invalid quality constant: 0x"
+ + Integer.toHexString(quality));
+ }
+
+ void validatePasswordOwnerLocked() {
+ if (mPasswordOwner >= 0) {
+ boolean haveOwner = false;
+ for (int i=mAdminList.size()-1; i>=0; i--) {
+ if (mAdminList.get(i).getUid() == mPasswordOwner) {
+ haveOwner = true;
+ break;
+ }
+ }
+ if (!haveOwner) {
+ Slog.w(TAG, "Previous password owner " + mPasswordOwner
+ + " no longer active; disabling");
+ mPasswordOwner = -1;
+ }
+ }
+ }
+
+ public void systemReady() {
+ synchronized (this) {
+ loadSettingsLocked();
+ }
+ }
+
+ public void setActiveAdmin(ComponentName adminReceiver) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ DeviceAdminInfo info = findAdmin(adminReceiver);
+ if (info == null) {
+ throw new IllegalArgumentException("Bad admin: " + adminReceiver);
+ }
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
+ throw new IllegalArgumentException("Admin is already added");
+ }
+ ActiveAdmin admin = new ActiveAdmin(info);
+ mAdminMap.put(adminReceiver, admin);
+ mAdminList.add(admin);
+ saveSettingsLocked();
+ sendAdminCommandLocked(admin,
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public boolean isAdminActive(ComponentName adminReceiver) {
+ synchronized (this) {
+ return getActiveAdminUncheckedLocked(adminReceiver) != null;
+ }
+ }
+
+ public List<ComponentName> getActiveAdmins() {
+ synchronized (this) {
+ final int N = mAdminList.size();
+ if (N <= 0) {
+ return null;
+ }
+ ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
+ for (int i=0; i<N; i++) {
+ res.add(mAdminList.get(i).info.getComponent());
+ }
+ return res;
+ }
+ }
+
+ public boolean packageHasActiveAdmins(String packageName) {
+ synchronized (this) {
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public void removeActiveAdmin(ComponentName adminReceiver) {
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
+ if (admin == null) {
+ return;
+ }
+ if (admin.getUid() != Binder.getCallingUid()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeActiveAdminLocked(adminReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void setPasswordQuality(ComponentName who, int quality) {
+ validateQualityConstant(quality);
+
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.passwordQuality != quality) {
+ ap.passwordQuality = quality;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordQuality(ComponentName who) {
+ synchronized (this) {
+ int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.passwordQuality : mode;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (mode < admin.passwordQuality) {
+ mode = admin.passwordQuality;
+ }
+ }
+ return mode;
+ }
+ }
+
+ public void setPasswordMinimumLength(ComponentName who, int length) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (ap.minimumPasswordLength != length) {
+ ap.minimumPasswordLength = length;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getPasswordMinimumLength(ComponentName who) {
+ synchronized (this) {
+ int length = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.minimumPasswordLength : length;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (length < admin.minimumPasswordLength) {
+ length = admin.minimumPasswordLength;
+ }
+ }
+ return length;
+ }
+ }
+
+ public boolean isActivePasswordSufficient() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ return mActivePasswordQuality >= getPasswordQuality(null)
+ && mActivePasswordLength >= getPasswordMinimumLength(null);
+ }
+ }
+
+ public int getCurrentFailedPasswordAttempts() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ return mFailedPasswordAttempts;
+ }
+ }
+
+ public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ if (ap.maximumFailedPasswordsForWipe != num) {
+ ap.maximumFailedPasswordsForWipe = num;
+ saveSettingsLocked();
+ }
+ }
+ }
+
+ public int getMaximumFailedPasswordsForWipe(ComponentName who) {
+ synchronized (this) {
+ int count = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.maximumFailedPasswordsForWipe : count;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (count == 0) {
+ count = admin.maximumFailedPasswordsForWipe;
+ } else if (admin.maximumFailedPasswordsForWipe != 0
+ && count > admin.maximumFailedPasswordsForWipe) {
+ count = admin.maximumFailedPasswordsForWipe;
+ }
+ }
+ return count;
+ }
+ }
+
+ public boolean resetPassword(String password, int flags) {
+ int quality;
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
+ quality = getPasswordQuality(null);
+ if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ int realQuality = LockPatternUtils.computePasswordQuality(password);
+ if (realQuality < quality) {
+ Slog.w(TAG, "resetPassword: password quality 0x"
+ + Integer.toHexString(quality)
+ + " does not meet required quality 0x"
+ + Integer.toHexString(quality));
+ return false;
+ }
+ quality = realQuality;
+ }
+ int length = getPasswordMinimumLength(null);
+ if (password.length() < length) {
+ Slog.w(TAG, "resetPassword: password length " + password.length()
+ + " does not meet required length " + length);
+ return false;
+ }
+ }
+
+ int callingUid = Binder.getCallingUid();
+ if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
+ Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
+ return false;
+ }
+
+ // Don't do this with the lock held, because it is going to call
+ // back in to the service.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ LockPatternUtils utils = new LockPatternUtils(mContext);
+ utils.saveLockPassword(password, quality);
+ synchronized (this) {
+ int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
+ != 0 ? callingUid : -1;
+ if (mPasswordOwner != newOwner) {
+ mPasswordOwner = newOwner;
+ saveSettingsLocked();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return true;
+ }
+
+ public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
+ if (ap.maximumTimeToUnlock != timeMs) {
+ ap.maximumTimeToUnlock = timeMs;
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ saveSettingsLocked();
+
+ timeMs = getMaximumTimeToLock(null);
+ if (timeMs <= 0) {
+ timeMs = Integer.MAX_VALUE;
+ }
+
+ try {
+ getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure talking with power manager", e);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+ }
+
+ public long getMaximumTimeToLock(ComponentName who) {
+ synchronized (this) {
+ long time = 0;
+
+ if (who != null) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
+ return admin != null ? admin.maximumTimeToUnlock : time;
+ }
+
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin admin = mAdminList.get(i);
+ if (time == 0) {
+ time = admin.maximumTimeToUnlock;
+ } else if (admin.maximumTimeToUnlock != 0
+ && time > admin.maximumTimeToUnlock) {
+ time = admin.maximumTimeToUnlock;
+ }
+ }
+ return time;
+ }
+ }
+
+ public void lockNow() {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
+ WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ void wipeDataLocked(int flags) {
+ try {
+ RecoverySystem.rebootWipeUserData(mContext);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed requesting data wipe", e);
+ }
+ }
+
+ public void wipeData(int flags) {
+ synchronized (this) {
+ // This API can only be called by an active device admin,
+ // so try to retrieve it to check that the caller is one.
+ getActiveAdminForCallerLocked(null,
+ DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ wipeDataLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
+ if (admin == null) {
+ try {
+ result.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
+ Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
+ intent.setComponent(admin.info.getComponent());
+ mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ result.sendResult(getResultExtras(false));
+ } catch (RemoteException e) {
+ }
+ }
+ }, null, Activity.RESULT_OK, null, null);
+ }
+ }
+
+ public void setActivePasswordState(int quality, int length) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ validateQualityConstant(quality);
+
+ synchronized (this) {
+ if (mActivePasswordQuality != quality || mActivePasswordLength != length
+ || mFailedPasswordAttempts != 0) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mActivePasswordQuality = quality;
+ mActivePasswordLength = length;
+ mFailedPasswordAttempts = 0;
+ saveSettingsLocked();
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+ }
+
+ public void reportFailedPasswordAttempt() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mFailedPasswordAttempts++;
+ saveSettingsLocked();
+ int max = getMaximumFailedPasswordsForWipe(null);
+ if (max > 0 && mFailedPasswordAttempts >= max) {
+ wipeDataLocked(0);
+ }
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void reportSuccessfulPasswordAttempt() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+
+ synchronized (this) {
+ if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mFailedPasswordAttempts = 0;
+ mPasswordOwner = -1;
+ saveSettingsLocked();
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+ } 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 DevicePolicyManagerService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ final Printer p = new PrintWriterPrinter(pw);
+
+ synchronized (this) {
+ p.println("Current Device Policy Manager state:");
+
+ p.println(" Enabled Device Admins:");
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin ap = mAdminList.get(i);
+ if (ap != null) {
+ pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
+ pw.println(":");
+ ap.dump(" ", pw);
+ }
+ }
+
+ pw.println(" ");
+ pw.print(" mActivePasswordQuality=0x");
+ pw.println(Integer.toHexString(mActivePasswordQuality));
+ pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
+ pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
+ pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
+ }
+ }
+}
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 57af029..62cf707 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -34,25 +34,29 @@ import android.os.ServiceManager;
import android.os.StatFs;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.provider.Settings.Gservices;
+import android.provider.Settings;
import android.util.Config;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
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
+ * 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 (a secure settings parameter;
+ * default 10%) 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 secure
+ * settings parameter with a default value of 12 hours. When the free
+ * storage differential goes below a threshold (again a secure
+ * settings 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";
@@ -63,9 +67,6 @@ class DeviceStorageMonitorService extends Binder {
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; // on /data
@@ -104,7 +105,7 @@ class DeviceStorageMonitorService extends Binder {
public void handleMessage(Message msg) {
//dont handle an invalid message
if (msg.what != DEVICE_MEMORY_WHAT) {
- Log.e(TAG, "Will not process invalid message");
+ Slog.e(TAG, "Will not process invalid message");
return;
}
checkMemory(msg.arg1 == _TRUE);
@@ -115,7 +116,7 @@ class DeviceStorageMonitorService extends Binder {
public void onRemoveCompleted(String packageName, boolean succeeded) {
mClearSucceeded = succeeded;
mClearingCache = false;
- if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded
+ if(localLOGV) Slog.i(TAG, " Clear succeeded:"+mClearSucceeded
+", mClearingCache:"+mClearingCache+" Forcing memory check");
postCheckMemoryMsg(false, 0);
}
@@ -134,9 +135,9 @@ class DeviceStorageMonitorService extends Binder {
if (!"".equals(debugFreeMem)) {
mFreeMem = Long.parseLong(debugFreeMem);
}
- // Read the log interval from Gservices
- long freeMemLogInterval = Gservices.getLong(mContentResolver,
- Gservices.SYS_FREE_STORAGE_LOG_INTERVAL,
+ // Read the log interval from secure settings
+ long freeMemLogInterval = Settings.Secure.getLong(mContentResolver,
+ Settings.Secure.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();
@@ -159,18 +160,18 @@ class DeviceStorageMonitorService extends Binder {
// ignore; report -1
}
mCacheFileStats.restat(CACHE_PATH);
- EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT,
+ EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT,
mFreeMem, mFreeSystem, mFreeCache);
}
- // Read the reporting threshold from Gservices
- long threshold = Gservices.getLong(mContentResolver,
- Gservices.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+ // Read the reporting threshold from secure settings
+ long threshold = Settings.Secure.getLong(mContentResolver,
+ Settings.Secure.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);
+ EventLog.writeEvent(EventLogTags.FREE_STORAGE_CHANGED, mFreeMem);
}
}
@@ -181,11 +182,11 @@ class DeviceStorageMonitorService extends Binder {
}
mClearingCache = true;
try {
- if (localLOGV) Log.i(TAG, "Clearing cache");
+ if (localLOGV) Slog.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);
+ Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
mClearingCache = false;
mClearSucceeded = false;
}
@@ -197,15 +198,15 @@ class DeviceStorageMonitorService extends Binder {
// 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");
+ if(localLOGV) Slog.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");
+ Slog.w(TAG, "Thread that clears cache file seems to run for ever");
}
} else {
restatDataDir();
- if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem);
+ if (localLOGV) Slog.v(TAG, "freeMemory="+mFreeMem);
//post intent to NotificationManager to display icon if necessary
long memThreshold = getMemThreshold();
@@ -219,23 +220,23 @@ class DeviceStorageMonitorService extends Binder {
mClearSucceeded = false;
clearCache();
} else {
- Log.i(TAG, "Running low on memory. Sending notification");
+ Slog.i(TAG, "Running low on memory. Sending notification");
sendNotification();
mLowMemFlag = true;
}
} else {
- if (localLOGV) Log.v(TAG, "Running low on memory " +
+ if (localLOGV) Slog.v(TAG, "Running low on memory " +
"notification already sent. do nothing");
}
} else {
if (mLowMemFlag) {
- Log.i(TAG, "Memory available. Cancelling notification");
+ Slog.i(TAG, "Memory available. Cancelling notification");
cancelNotification();
mLowMemFlag = false;
}
}
}
- if(localLOGV) Log.i(TAG, "Posting Message again");
+ if(localLOGV) Slog.i(TAG, "Posting Message again");
//keep posting messages to itself periodically
postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
}
@@ -250,15 +251,15 @@ class DeviceStorageMonitorService extends Binder {
/*
* just query settings to retrieve the memory threshold.
- * Preferred this over using a ContentObserver since Settings.Gservices caches the value
+ * Preferred this over using a ContentObserver since Settings.Secure caches the value
* any way
*/
private long getMemThreshold() {
- int value = Settings.Gservices.getInt(
+ int value = Settings.Secure.getInt(
mContentResolver,
- Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+ Settings.Secure.SYS_STORAGE_THRESHOLD_PERCENTAGE,
DEFAULT_THRESHOLD_PERCENTAGE);
- if(localLOGV) Log.v(TAG, "Threshold Percentage="+value);
+ if(localLOGV) Slog.v(TAG, "Threshold Percentage="+value);
//evaluate threshold value
return mTotalMemory*value;
}
@@ -290,9 +291,9 @@ class DeviceStorageMonitorService extends Binder {
* application
*/
private final void sendNotification() {
- if(localLOGV) Log.i(TAG, "Sending low memory notification");
+ if(localLOGV) Slog.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);
+ EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
// Pack up the values and broadcast them to everyone
Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
lowMemIntent.putExtra("memory", mFreeMem);
@@ -318,7 +319,7 @@ class DeviceStorageMonitorService extends Binder {
* Cancels low storage notification and sends OK intent.
*/
private final void cancelNotification() {
- if(localLOGV) Log.i(TAG, "Canceling low memory notification");
+ if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
NotificationManager mNotificationMgr =
(NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
diff --git a/services/java/com/android/server/DiskStatsService.java b/services/java/com/android/server/DiskStatsService.java
new file mode 100644
index 0000000..8ef974a
--- /dev/null
+++ b/services/java/com/android/server/DiskStatsService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.StatFs;
+import android.os.SystemClock;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * This service exists only as a "dumpsys" target which reports
+ * statistics about the status of the disk.
+ */
+public class DiskStatsService extends Binder {
+ private final Context mContext;
+
+ public DiskStatsService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // This data is accessible to any app -- no permission check needed.
+
+ // Run a quick-and-dirty performance test: write 512 bytes
+ byte[] junk = new byte[512];
+ for (int i = 0; i < junk.length; i++) junk[i] = (byte) i; // Write nonzero bytes
+
+ File tmp = new File(Environment.getDataDirectory(), "system/perftest.tmp");
+ FileOutputStream fos = null;
+ IOException error = null;
+
+ long before = SystemClock.uptimeMillis();
+ try {
+ fos = new FileOutputStream(tmp);
+ fos.write(junk);
+ } catch (IOException e) {
+ error = e;
+ } finally {
+ try { if (fos != null) fos.close(); } catch (IOException e) {}
+ }
+
+ long after = SystemClock.uptimeMillis();
+ if (tmp.exists()) tmp.delete();
+
+ if (error != null) {
+ pw.print("Test-Error: ");
+ pw.println(error.toString());
+ } else {
+ pw.print("Latency: ");
+ pw.print(after - before);
+ pw.println("ms [512B Data Write]");
+ }
+
+ reportFreeSpace(Environment.getDataDirectory(), "Data", pw);
+ reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
+ reportFreeSpace(new File("/system"), "System", pw);
+
+ // TODO: Read /proc/yaffs and report interesting values;
+ // add configurable (through args) performance test parameters.
+ }
+
+ private void reportFreeSpace(File path, String name, PrintWriter pw) {
+ try {
+ StatFs statfs = new StatFs(path.getPath());
+ long bsize = statfs.getBlockSize();
+ long avail = statfs.getAvailableBlocks();
+ long total = statfs.getBlockCount();
+ if (bsize <= 0 || total <= 0) {
+ throw new IllegalArgumentException(
+ "Invalid stat: bsize=" + bsize + " avail=" + avail + " total=" + total);
+ }
+
+ pw.print(name);
+ pw.print("-Free: ");
+ pw.print(avail * bsize / 1024);
+ pw.print("K / ");
+ pw.print(total * bsize / 1024);
+ pw.print("K total = ");
+ pw.print(avail * 100 / total);
+ pw.println("% free");
+ } catch (IllegalArgumentException e) {
+ pw.print(name);
+ pw.print("-Error: ");
+ pw.println(e.toString());
+ return;
+ }
+ }
+}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 2fff54c0..bee8872 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,14 +16,15 @@
package com.android.server;
-import android.app.Activity;
-import android.app.KeyguardManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
@@ -31,8 +32,7 @@ import android.os.UEventObserver;
import android.provider.Settings;
import android.server.BluetoothService;
import android.util.Log;
-
-import com.android.internal.widget.LockPatternUtils;
+import android.util.Slog;
import java.io.FileNotFoundException;
import java.io.FileReader;
@@ -47,81 +47,43 @@ class DockObserver extends UEventObserver {
private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
+ private static final int MSG_DOCK_STATE = 0;
+
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
private boolean mSystemReady;
private final Context mContext;
private PowerManagerService mPowerManager;
- private KeyguardManager.KeyguardLock mKeyguardLock;
- private boolean mKeyguardDisabled;
- private LockPatternUtils mLockPatternUtils;
-
- // The broadcast receiver which receives the result of the ordered broadcast sent when
- // the dock state changes. The original ordered broadcast is sent with an initial result
- // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
- // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
- private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (getResultCode() != Activity.RESULT_OK) {
- return;
- }
-
- // Launch a dock activity
- String category;
- switch (mDockState) {
- case Intent.EXTRA_DOCK_STATE_CAR:
- category = Intent.CATEGORY_CAR_DOCK;
- break;
- case Intent.EXTRA_DOCK_STATE_DESK:
- category = Intent.CATEGORY_DESK_DOCK;
- break;
- default:
- category = null;
- break;
- }
- if (category != null) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(category);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, e.getCause());
- }
- }
- }
- };
-
public DockObserver(Context context, PowerManagerService pm) {
mContext = context;
mPowerManager = pm;
- mLockPatternUtils = new LockPatternUtils(context.getContentResolver());
init(); // set initial status
+
startObserving(DOCK_UEVENT_MATCH);
}
@Override
public void onUEvent(UEventObserver.UEvent event) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Dock UEVENT: " + event.toString());
+ Slog.v(TAG, "Dock UEVENT: " + event.toString());
}
synchronized (this) {
try {
int newState = Integer.parseInt(event.get("SWITCH_STATE"));
if (newState != mDockState) {
- int oldState = mDockState;
+ mPreviousDockState = mDockState;
mDockState = newState;
if (mSystemReady) {
// Don't force screen on when undocking from the desk dock.
// The change in power state will do this anyway.
// FIXME - we should be configurable.
- if (oldState != Intent.EXTRA_DOCK_STATE_DESK ||
- newState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ if (mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK ||
+ mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
false, true);
}
@@ -129,7 +91,7 @@ class DockObserver extends UEventObserver {
}
}
} catch (NumberFormatException e) {
- Log.e(TAG, "Could not parse switch state from event " + event);
+ Slog.e(TAG, "Could not parse switch state from event " + event);
}
}
}
@@ -140,21 +102,17 @@ class DockObserver extends UEventObserver {
try {
FileReader file = new FileReader(DOCK_STATE_PATH);
int len = file.read(buffer, 0, 1024);
- mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
+ mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
} catch (FileNotFoundException e) {
- Log.w(TAG, "This kernel does not have dock station support");
+ Slog.w(TAG, "This kernel does not have dock station support");
} catch (Exception e) {
- Log.e(TAG, "" , e);
+ Slog.e(TAG, "" , e);
}
}
void systemReady() {
synchronized (this) {
- KeyguardManager keyguardManager =
- (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mKeyguardLock = keyguardManager.newKeyguardLock(TAG);
-
// don't bother broadcasting undocked here
if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
update();
@@ -164,37 +122,73 @@ class DockObserver extends UEventObserver {
}
private final void update() {
- mHandler.sendEmptyMessage(0);
+ mHandler.sendEmptyMessage(MSG_DOCK_STATE);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- synchronized (this) {
- Log.i(TAG, "Dock state changed: " + mDockState);
- if (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
- Log.i(TAG, "Device not provisioned, skipping dock broadcast");
- return;
- }
- // Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
- intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-
- // Check if this is Bluetooth Dock
- String address = BluetoothService.readDockBluetoothAddress();
- if (address != null)
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
- BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
-
- // Send the ordered broadcast; the result receiver will receive after all
- // broadcasts have been sent. If any broadcast receiver changes the result
- // code from the initial value of RESULT_OK, then the result receiver will
- // not launch the corresponding dock application. This gives apps a chance
- // to override the behavior and stay in their app even when the device is
- // placed into a dock.
- mContext.sendStickyOrderedBroadcast(
- intent, mResultReceiver, null, Activity.RESULT_OK, null, null);
+ switch (msg.what) {
+ case MSG_DOCK_STATE:
+ synchronized (this) {
+ Slog.i(TAG, "Dock state changed: " + mDockState);
+
+ final ContentResolver cr = mContext.getContentResolver();
+
+ if (Settings.Secure.getInt(cr,
+ Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
+ Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
+ return;
+ }
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+
+ // Check if this is Bluetooth Dock
+ String address = BluetoothService.readDockBluetoothAddress();
+ if (address != null)
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
+ BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
+
+ // User feedback to confirm dock connection. Particularly
+ // useful for flaky contact pins...
+ if (Settings.System.getInt(cr,
+ Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1)
+ {
+ String whichSound = null;
+ if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ whichSound = Settings.System.DESK_UNDOCK_SOUND;
+ } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+ whichSound = Settings.System.CAR_UNDOCK_SOUND;
+ }
+ } else {
+ if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ whichSound = Settings.System.DESK_DOCK_SOUND;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+ whichSound = Settings.System.CAR_DOCK_SOUND;
+ }
+ }
+
+ if (whichSound != null) {
+ final String soundPath = Settings.System.getString(cr, whichSound);
+ if (soundPath != null) {
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
+ }
+ }
+ }
+ }
+ }
+
+ mContext.sendStickyBroadcast(intent);
+ }
+ break;
}
}
};
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
new file mode 100644
index 0000000..0de11c6
--- /dev/null
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2009 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.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Debug;
+import android.os.DropBoxManager;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.StatFs;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.format.Time;
+import android.util.Slog;
+
+import com.android.internal.os.IDropBoxManagerService;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Implementation of {@link IDropBoxManagerService} using the filesystem.
+ * Clients use {@link DropBoxManager} to access this service.
+ */
+public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
+ private static final String TAG = "DropBoxManagerService";
+ private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
+ private static final int DEFAULT_MAX_FILES = 1000;
+ private static final int DEFAULT_QUOTA_KB = 5 * 1024;
+ private static final int DEFAULT_QUOTA_PERCENT = 10;
+ private static final int DEFAULT_RESERVE_PERCENT = 10;
+ private static final int QUOTA_RESCAN_MILLIS = 5000;
+
+ private static final boolean PROFILE_DUMP = false;
+
+ // TODO: This implementation currently uses one file per entry, which is
+ // inefficient for smallish entries -- consider using a single queue file
+ // per tag (or even globally) instead.
+
+ // The cached context and derived objects
+
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
+ private final File mDropBoxDir;
+
+ // Accounting of all currently written log files (set in init()).
+
+ private FileList mAllFiles = null;
+ private HashMap<String, FileList> mFilesByTag = null;
+
+ // Various bits of disk information
+
+ private StatFs mStatFs = null;
+ private int mBlockSize = 0;
+ private int mCachedQuotaBlocks = 0; // Space we can use: computed from free space, etc.
+ private long mCachedQuotaUptimeMillis = 0;
+
+ // Ensure that all log entries have a unique timestamp
+ private long mLastTimestamp = 0;
+
+ /** Receives events that might indicate a need to clean up files. */
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mCachedQuotaUptimeMillis = 0; // Force a re-check of quota size
+
+ // Run the initialization in the background (not this main thread).
+ // The init() and trimToFit() methods are synchronized, so they still
+ // block other users -- but at least the onReceive() call can finish.
+ new Thread() {
+ public void run() {
+ try {
+ init();
+ trimToFit();
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't init", e);
+ }
+ }
+ }.start();
+ }
+ };
+
+ /**
+ * Creates an instance of managed drop box storage. Normally there is one of these
+ * run by the system, but others can be created for testing and other purposes.
+ *
+ * @param context to use for receiving free space & gservices intents
+ * @param path to store drop box entries in
+ */
+ public DropBoxManagerService(final Context context, File path) {
+ mDropBoxDir = path;
+
+ // Set up intent receivers
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ context.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW));
+
+ mContentResolver.registerContentObserver(
+ Settings.Secure.CONTENT_URI, true,
+ new ContentObserver(new Handler()) {
+ public void onChange(boolean selfChange) {
+ mReceiver.onReceive(context, (Intent) null);
+ }
+ });
+
+ // The real work gets done lazily in init() -- that way service creation always
+ // succeeds, and things like disk problems cause individual method failures.
+ }
+
+ /** Unregisters broadcast receivers and any other hooks -- for test instances */
+ public void stop() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ public void add(DropBoxManager.Entry entry) {
+ File temp = null;
+ OutputStream output = null;
+ final String tag = entry.getTag();
+ try {
+ int flags = entry.getFlags();
+ if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();
+
+ init();
+ if (!isTagEnabled(tag)) return;
+ long max = trimToFit();
+ long lastTrim = System.currentTimeMillis();
+
+ byte[] buffer = new byte[mBlockSize];
+ InputStream input = entry.getInputStream();
+
+ // First, accumulate up to one block worth of data in memory before
+ // deciding whether to compress the data or not.
+
+ int read = 0;
+ while (read < buffer.length) {
+ int n = input.read(buffer, read, buffer.length - read);
+ if (n <= 0) break;
+ read += n;
+ }
+
+ // If we have at least one block, compress it -- otherwise, just write
+ // the data in uncompressed form.
+
+ temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp");
+ output = new FileOutputStream(temp);
+ if (read == buffer.length && ((flags & DropBoxManager.IS_GZIPPED) == 0)) {
+ output = new GZIPOutputStream(output);
+ flags = flags | DropBoxManager.IS_GZIPPED;
+ }
+
+ do {
+ output.write(buffer, 0, read);
+
+ long now = System.currentTimeMillis();
+ if (now - lastTrim > 30 * 1000) {
+ max = trimToFit(); // In case data dribbles in slowly
+ lastTrim = now;
+ }
+
+ read = input.read(buffer);
+ if (read <= 0) {
+ output.close(); // Get a final size measurement
+ output = null;
+ } else {
+ output.flush(); // So the size measurement is pseudo-reasonable
+ }
+
+ long len = temp.length();
+ if (len > max) {
+ Slog.w(TAG, "Dropping: " + tag + " (" + temp.length() + " > " + max + " bytes)");
+ temp.delete();
+ temp = null; // Pass temp = null to createEntry() to leave a tombstone
+ break;
+ }
+ } while (read > 0);
+
+ createEntry(temp, tag, flags);
+ temp = null;
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't write: " + tag, e);
+ } finally {
+ try { if (output != null) output.close(); } catch (IOException e) {}
+ entry.close();
+ if (temp != null) temp.delete();
+ }
+ }
+
+ public boolean isTagEnabled(String tag) {
+ return !"disabled".equals(Settings.Secure.getString(
+ mContentResolver, Settings.Secure.DROPBOX_TAG_PREFIX + tag));
+ }
+
+ public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("READ_LOGS permission required");
+ }
+
+ try {
+ init();
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't init", e);
+ return null;
+ }
+
+ FileList list = tag == null ? mAllFiles : mFilesByTag.get(tag);
+ if (list == null) return null;
+
+ for (EntryFile entry : list.contents.tailSet(new EntryFile(millis + 1))) {
+ if (entry.tag == null) continue;
+ if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
+ return new DropBoxManager.Entry(entry.tag, entry.timestampMillis);
+ }
+ try {
+ return new DropBoxManager.Entry(
+ entry.tag, entry.timestampMillis, entry.file, entry.flags);
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't read: " + entry.file, e);
+ // Continue to next file
+ }
+ }
+
+ return null;
+ }
+
+ public synchronized 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 DropBoxManagerService");
+ return;
+ }
+
+ try {
+ init();
+ } catch (IOException e) {
+ pw.println("Can't initialize: " + e);
+ Slog.e(TAG, "Can't init", e);
+ return;
+ }
+
+ if (PROFILE_DUMP) Debug.startMethodTracing("/data/trace/dropbox.dump");
+
+ StringBuilder out = new StringBuilder();
+ boolean doPrint = false, doFile = false;
+ ArrayList<String> searchArgs = new ArrayList<String>();
+ for (int i = 0; args != null && i < args.length; i++) {
+ if (args[i].equals("-p") || args[i].equals("--print")) {
+ doPrint = true;
+ } else if (args[i].equals("-f") || args[i].equals("--file")) {
+ doFile = true;
+ } else if (args[i].startsWith("-")) {
+ out.append("Unknown argument: ").append(args[i]).append("\n");
+ } else {
+ searchArgs.add(args[i]);
+ }
+ }
+
+ out.append("Drop box contents: ").append(mAllFiles.contents.size()).append(" entries\n");
+
+ if (!searchArgs.isEmpty()) {
+ out.append("Searching for:");
+ for (String a : searchArgs) out.append(" ").append(a);
+ out.append("\n");
+ }
+
+ int numFound = 0, numArgs = searchArgs.size();
+ Time time = new Time();
+ out.append("\n");
+ for (EntryFile entry : mAllFiles.contents) {
+ time.set(entry.timestampMillis);
+ String date = time.format("%Y-%m-%d %H:%M:%S");
+ boolean match = true;
+ for (int i = 0; i < numArgs && match; i++) {
+ String arg = searchArgs.get(i);
+ match = (date.contains(arg) || arg.equals(entry.tag));
+ }
+ if (!match) continue;
+
+ numFound++;
+ if (doPrint) out.append("========================================\n");
+ out.append(date).append(" ").append(entry.tag == null ? "(no tag)" : entry.tag);
+ if (entry.file == null) {
+ out.append(" (no file)\n");
+ continue;
+ } else if ((entry.flags & DropBoxManager.IS_EMPTY) != 0) {
+ out.append(" (contents lost)\n");
+ continue;
+ } else {
+ out.append(" (");
+ if ((entry.flags & DropBoxManager.IS_GZIPPED) != 0) out.append("compressed ");
+ out.append((entry.flags & DropBoxManager.IS_TEXT) != 0 ? "text" : "data");
+ out.append(", ").append(entry.file.length()).append(" bytes)\n");
+ }
+
+ if (doFile || (doPrint && (entry.flags & DropBoxManager.IS_TEXT) == 0)) {
+ if (!doPrint) out.append(" ");
+ out.append(entry.file.getPath()).append("\n");
+ }
+
+ if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
+ DropBoxManager.Entry dbe = null;
+ try {
+ dbe = new DropBoxManager.Entry(
+ entry.tag, entry.timestampMillis, entry.file, entry.flags);
+
+ if (doPrint) {
+ InputStreamReader r = new InputStreamReader(dbe.getInputStream());
+ char[] buf = new char[4096];
+ boolean newline = false;
+ for (;;) {
+ int n = r.read(buf);
+ if (n <= 0) break;
+ out.append(buf, 0, n);
+ newline = (buf[n - 1] == '\n');
+
+ // Flush periodically when printing to avoid out-of-memory.
+ if (out.length() > 65536) {
+ pw.write(out.toString());
+ out.setLength(0);
+ }
+ }
+ if (!newline) out.append("\n");
+ } else {
+ String text = dbe.getText(70);
+ boolean truncated = (text.length() == 70);
+ out.append(" ").append(text.trim().replace('\n', '/'));
+ if (truncated) out.append(" ...");
+ out.append("\n");
+ }
+ } catch (IOException e) {
+ out.append("*** ").append(e.toString()).append("\n");
+ Slog.e(TAG, "Can't read: " + entry.file, e);
+ } finally {
+ if (dbe != null) dbe.close();
+ }
+ }
+
+ if (doPrint) out.append("\n");
+ }
+
+ if (numFound == 0) out.append("(No entries found.)\n");
+
+ if (args == null || args.length == 0) {
+ if (!doPrint) out.append("\n");
+ out.append("Usage: dumpsys dropbox [--print|--file] [YYYY-mm-dd] [HH:MM:SS] [tag]\n");
+ }
+
+ pw.write(out.toString());
+ if (PROFILE_DUMP) Debug.stopMethodTracing();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /** Chronologically sorted list of {@link #EntryFile} */
+ private static final class FileList implements Comparable<FileList> {
+ public int blocks = 0;
+ public final TreeSet<EntryFile> contents = new TreeSet<EntryFile>();
+
+ /** Sorts bigger FileList instances before smaller ones. */
+ public final int compareTo(FileList o) {
+ if (blocks != o.blocks) return o.blocks - blocks;
+ if (this == o) return 0;
+ if (hashCode() < o.hashCode()) return -1;
+ if (hashCode() > o.hashCode()) return 1;
+ return 0;
+ }
+ }
+
+ /** Metadata describing an on-disk log file. */
+ private static final class EntryFile implements Comparable<EntryFile> {
+ public final String tag;
+ public final long timestampMillis;
+ public final int flags;
+ public final File file;
+ public final int blocks;
+
+ /** Sorts earlier EntryFile instances before later ones. */
+ public final int compareTo(EntryFile o) {
+ if (timestampMillis < o.timestampMillis) return -1;
+ if (timestampMillis > o.timestampMillis) return 1;
+ if (file != null && o.file != null) return file.compareTo(o.file);
+ if (o.file != null) return -1;
+ if (file != null) return 1;
+ if (this == o) return 0;
+ if (hashCode() < o.hashCode()) return -1;
+ if (hashCode() > o.hashCode()) return 1;
+ return 0;
+ }
+
+ /**
+ * Moves an existing temporary file to a new log filename.
+ * @param temp file to rename
+ * @param dir to store file in
+ * @param tag to use for new log file name
+ * @param timestampMillis of log entry
+ * @param flags for the entry data
+ * @param blockSize to use for space accounting
+ * @throws IOException if the file can't be moved
+ */
+ public EntryFile(File temp, File dir, String tag,long timestampMillis,
+ int flags, int blockSize) throws IOException {
+ if ((flags & DropBoxManager.IS_EMPTY) != 0) throw new IllegalArgumentException();
+
+ this.tag = tag;
+ this.timestampMillis = timestampMillis;
+ this.flags = flags;
+ this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis +
+ ((flags & DropBoxManager.IS_TEXT) != 0 ? ".txt" : ".dat") +
+ ((flags & DropBoxManager.IS_GZIPPED) != 0 ? ".gz" : ""));
+
+ if (!temp.renameTo(this.file)) {
+ throw new IOException("Can't rename " + temp + " to " + this.file);
+ }
+ this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+ }
+
+ /**
+ * Creates a zero-length tombstone for a file whose contents were lost.
+ * @param dir to store file in
+ * @param tag to use for new log file name
+ * @param timestampMillis of log entry
+ * @throws IOException if the file can't be created.
+ */
+ public EntryFile(File dir, String tag, long timestampMillis) throws IOException {
+ this.tag = tag;
+ this.timestampMillis = timestampMillis;
+ this.flags = DropBoxManager.IS_EMPTY;
+ this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + ".lost");
+ this.blocks = 0;
+ new FileOutputStream(this.file).close();
+ }
+
+ /**
+ * Extracts metadata from an existing on-disk log filename.
+ * @param file name of existing log file
+ * @param blockSize to use for space accounting
+ */
+ public EntryFile(File file, int blockSize) {
+ this.file = file;
+ this.blocks = (int) ((this.file.length() + blockSize - 1) / blockSize);
+
+ String name = file.getName();
+ int at = name.lastIndexOf('@');
+ if (at < 0) {
+ this.tag = null;
+ this.timestampMillis = 0;
+ this.flags = DropBoxManager.IS_EMPTY;
+ return;
+ }
+
+ int flags = 0;
+ this.tag = Uri.decode(name.substring(0, at));
+ if (name.endsWith(".gz")) {
+ flags |= DropBoxManager.IS_GZIPPED;
+ name = name.substring(0, name.length() - 3);
+ }
+ if (name.endsWith(".lost")) {
+ flags |= DropBoxManager.IS_EMPTY;
+ name = name.substring(at + 1, name.length() - 5);
+ } else if (name.endsWith(".txt")) {
+ flags |= DropBoxManager.IS_TEXT;
+ name = name.substring(at + 1, name.length() - 4);
+ } else if (name.endsWith(".dat")) {
+ name = name.substring(at + 1, name.length() - 4);
+ } else {
+ this.flags = DropBoxManager.IS_EMPTY;
+ this.timestampMillis = 0;
+ return;
+ }
+ this.flags = flags;
+
+ long millis;
+ try { millis = Long.valueOf(name); } catch (NumberFormatException e) { millis = 0; }
+ this.timestampMillis = millis;
+ }
+
+ /**
+ * Creates a EntryFile object with only a timestamp for comparison purposes.
+ * @param timestampMillis to compare with.
+ */
+ public EntryFile(long millis) {
+ this.tag = null;
+ this.timestampMillis = millis;
+ this.flags = DropBoxManager.IS_EMPTY;
+ this.file = null;
+ this.blocks = 0;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /** If never run before, scans disk contents to build in-memory tracking data. */
+ private synchronized void init() throws IOException {
+ if (mStatFs == null) {
+ if (!mDropBoxDir.isDirectory() && !mDropBoxDir.mkdirs()) {
+ throw new IOException("Can't mkdir: " + mDropBoxDir);
+ }
+ try {
+ mStatFs = new StatFs(mDropBoxDir.getPath());
+ mBlockSize = mStatFs.getBlockSize();
+ } catch (IllegalArgumentException e) { // StatFs throws this on error
+ throw new IOException("Can't statfs: " + mDropBoxDir);
+ }
+ }
+
+ if (mAllFiles == null) {
+ File[] files = mDropBoxDir.listFiles();
+ if (files == null) throw new IOException("Can't list files: " + mDropBoxDir);
+
+ mAllFiles = new FileList();
+ mFilesByTag = new HashMap<String, FileList>();
+
+ // Scan pre-existing files.
+ for (File file : files) {
+ if (file.getName().endsWith(".tmp")) {
+ Slog.i(TAG, "Cleaning temp file: " + file);
+ file.delete();
+ continue;
+ }
+
+ EntryFile entry = new EntryFile(file, mBlockSize);
+ if (entry.tag == null) {
+ Slog.w(TAG, "Unrecognized file: " + file);
+ continue;
+ } else if (entry.timestampMillis == 0) {
+ Slog.w(TAG, "Invalid filename: " + file);
+ file.delete();
+ continue;
+ }
+
+ enrollEntry(entry);
+ }
+ }
+ }
+
+ /** Adds a disk log file to in-memory tracking for accounting and enumeration. */
+ private synchronized void enrollEntry(EntryFile entry) {
+ mAllFiles.contents.add(entry);
+ mAllFiles.blocks += entry.blocks;
+
+ // mFilesByTag is used for trimming, so don't list empty files.
+ // (Zero-length/lost files are trimmed by date from mAllFiles.)
+
+ if (entry.tag != null && entry.file != null && entry.blocks > 0) {
+ FileList tagFiles = mFilesByTag.get(entry.tag);
+ if (tagFiles == null) {
+ tagFiles = new FileList();
+ mFilesByTag.put(entry.tag, tagFiles);
+ }
+ tagFiles.contents.add(entry);
+ tagFiles.blocks += entry.blocks;
+ }
+ }
+
+ /** Moves a temporary file to a final log filename and enrolls it. */
+ private synchronized void createEntry(File temp, String tag, int flags) throws IOException {
+ long t = System.currentTimeMillis();
+
+ // Require each entry to have a unique timestamp; if there are entries
+ // >10sec in the future (due to clock skew), drag them back to avoid
+ // keeping them around forever.
+
+ SortedSet<EntryFile> tail = mAllFiles.contents.tailSet(new EntryFile(t + 10000));
+ EntryFile[] future = null;
+ if (!tail.isEmpty()) {
+ future = tail.toArray(new EntryFile[tail.size()]);
+ tail.clear(); // Remove from mAllFiles
+ }
+
+ if (!mAllFiles.contents.isEmpty()) {
+ t = Math.max(t, mAllFiles.contents.last().timestampMillis + 1);
+ }
+
+ if (future != null) {
+ for (EntryFile late : future) {
+ mAllFiles.blocks -= late.blocks;
+ FileList tagFiles = mFilesByTag.get(late.tag);
+ if (tagFiles != null && tagFiles.contents.remove(late)) {
+ tagFiles.blocks -= late.blocks;
+ }
+ if ((late.flags & DropBoxManager.IS_EMPTY) == 0) {
+ enrollEntry(new EntryFile(
+ late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize));
+ } else {
+ enrollEntry(new EntryFile(mDropBoxDir, late.tag, t++));
+ }
+ }
+ }
+
+ if (temp == null) {
+ enrollEntry(new EntryFile(mDropBoxDir, tag, t));
+ } else {
+ enrollEntry(new EntryFile(temp, mDropBoxDir, tag, t, flags, mBlockSize));
+ }
+ }
+
+ /**
+ * Trims the files on disk to make sure they aren't using too much space.
+ * @return the overall quota for storage (in bytes)
+ */
+ private synchronized long trimToFit() {
+ // Expunge aged items (including tombstones marking deleted data).
+
+ int ageSeconds = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_AGE_SECONDS, DEFAULT_AGE_SECONDS);
+ int maxFiles = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_MAX_FILES, DEFAULT_MAX_FILES);
+ long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000;
+ while (!mAllFiles.contents.isEmpty()) {
+ EntryFile entry = mAllFiles.contents.first();
+ if (entry.timestampMillis > cutoffMillis && mAllFiles.contents.size() < maxFiles) break;
+
+ FileList tag = mFilesByTag.get(entry.tag);
+ if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
+ if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
+ if (entry.file != null) entry.file.delete();
+ }
+
+ // Compute overall quota (a fraction of available free space) in blocks.
+ // The quota changes dynamically based on the amount of free space;
+ // that way when lots of data is available we can use it, but we'll get
+ // out of the way if storage starts getting tight.
+
+ long uptimeMillis = SystemClock.uptimeMillis();
+ if (uptimeMillis > mCachedQuotaUptimeMillis + QUOTA_RESCAN_MILLIS) {
+ int quotaPercent = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_QUOTA_PERCENT, DEFAULT_QUOTA_PERCENT);
+ int reservePercent = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_RESERVE_PERCENT, DEFAULT_RESERVE_PERCENT);
+ int quotaKb = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_QUOTA_KB, DEFAULT_QUOTA_KB);
+
+ mStatFs.restat(mDropBoxDir.getPath());
+ int available = mStatFs.getAvailableBlocks();
+ int nonreserved = available - mStatFs.getBlockCount() * reservePercent / 100;
+ int maximum = quotaKb * 1024 / mBlockSize;
+ mCachedQuotaBlocks = Math.min(maximum, Math.max(0, nonreserved * quotaPercent / 100));
+ mCachedQuotaUptimeMillis = uptimeMillis;
+ }
+
+ // If we're using too much space, delete old items to make room.
+ //
+ // We trim each tag independently (this is why we keep per-tag lists).
+ // Space is "fairly" shared between tags -- they are all squeezed
+ // equally until enough space is reclaimed.
+ //
+ // A single circular buffer (a la logcat) would be simpler, but this
+ // way we can handle fat/bursty data (like 1MB+ bugreports, 300KB+
+ // kernel crash dumps, and 100KB+ ANR reports) without swamping small,
+ // well-behaved data streams (event statistics, profile data, etc).
+ //
+ // Deleted files are replaced with zero-length tombstones to mark what
+ // was lost. Tombstones are expunged by age (see above).
+
+ if (mAllFiles.blocks > mCachedQuotaBlocks) {
+ Slog.i(TAG, "Usage (" + mAllFiles.blocks + ") > Quota (" + mCachedQuotaBlocks + ")");
+
+ // Find a fair share amount of space to limit each tag
+ int unsqueezed = mAllFiles.blocks, squeezed = 0;
+ TreeSet<FileList> tags = new TreeSet<FileList>(mFilesByTag.values());
+ for (FileList tag : tags) {
+ if (squeezed > 0 && tag.blocks <= (mCachedQuotaBlocks - unsqueezed) / squeezed) {
+ break;
+ }
+ unsqueezed -= tag.blocks;
+ squeezed++;
+ }
+ int tagQuota = (mCachedQuotaBlocks - unsqueezed) / squeezed;
+
+ // Remove old items from each tag until it meets the per-tag quota.
+ for (FileList tag : tags) {
+ if (mAllFiles.blocks < mCachedQuotaBlocks) break;
+ while (tag.blocks > tagQuota && !tag.contents.isEmpty()) {
+ EntryFile entry = tag.contents.first();
+ if (tag.contents.remove(entry)) tag.blocks -= entry.blocks;
+ if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks;
+
+ try {
+ if (entry.file != null) entry.file.delete();
+ enrollEntry(new EntryFile(mDropBoxDir, entry.tag, entry.timestampMillis));
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't write tombstone file", e);
+ }
+ }
+ }
+ }
+
+ return mCachedQuotaBlocks * mBlockSize;
+ }
+}
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
index 28f09f5..81ae26f 100644
--- a/services/java/com/android/server/EntropyService.java
+++ b/services/java/com/android/server/EntropyService.java
@@ -27,7 +27,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
-import android.util.Log;
+import android.util.Slog;
/**
* A service designed to load and periodically save &quot;randomness&quot;
@@ -48,14 +48,15 @@ import android.util.Log;
* instead of periodically.
*/
public class EntropyService extends Binder {
- private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
private static final String TAG = "EntropyService";
private static final int ENTROPY_WHAT = 1;
private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000; // 3 hrs
- private static final String RANDOM_DEV = "/dev/urandom";
private static final long START_TIME = System.currentTimeMillis();
private static final long START_NANOTIME = System.nanoTime();
+ private final String randomDevice;
+ private final String entropyFile;
+
/**
* Handler that periodically updates the entropy on disk.
*/
@@ -63,7 +64,7 @@ public class EntropyService extends Binder {
@Override
public void handleMessage(Message msg) {
if (msg.what != ENTROPY_WHAT) {
- Log.e(TAG, "Will not process invalid message");
+ Slog.e(TAG, "Will not process invalid message");
return;
}
writeEntropy();
@@ -72,6 +73,16 @@ public class EntropyService extends Binder {
};
public EntropyService() {
+ this(getSystemDir() + "/entropy.dat", "/dev/urandom");
+ }
+
+ /** Test only interface, not for public use */
+ public EntropyService(String entropyFile, String randomDevice) {
+ if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
+ if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
+
+ this.randomDevice = randomDevice;
+ this.entropyFile = entropyFile;
loadInitialEntropy();
addDeviceSpecificEntropy();
writeEntropy();
@@ -85,17 +96,17 @@ public class EntropyService extends Binder {
private void loadInitialEntropy() {
try {
- RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+ RandomBlock.fromFile(entropyFile).toFile(randomDevice);
} catch (IOException e) {
- Log.w(TAG, "unable to load initial entropy (first boot?)", e);
+ Slog.w(TAG, "unable to load initial entropy (first boot?)", e);
}
}
private void writeEntropy() {
try {
- RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+ RandomBlock.fromFile(randomDevice).toFile(entropyFile);
} catch (IOException e) {
- Log.w(TAG, "unable to write entropy", e);
+ Slog.w(TAG, "unable to write entropy", e);
}
}
@@ -116,7 +127,7 @@ public class EntropyService extends Binder {
private void addDeviceSpecificEntropy() {
PrintWriter out = null;
try {
- out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
+ out = new PrintWriter(new FileOutputStream(randomDevice));
out.println("Copyright (C) 2009 The Android Open Source Project");
out.println("All Your Randomness Are Belong To Us");
out.println(START_TIME);
@@ -131,7 +142,7 @@ public class EntropyService extends Binder {
out.println(System.currentTimeMillis());
out.println(System.nanoTime());
} catch (IOException e) {
- Log.w(TAG, "Unable to add device specific data to the entropy pool", e);
+ Slog.w(TAG, "Unable to add device specific data to the entropy pool", e);
} finally {
if (out != null) {
out.close();
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
new file mode 100644
index 0000000..5429c0c
--- /dev/null
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -0,0 +1,139 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.server
+
+# ---------------------------
+# BatteryService.java
+# ---------------------------
+2722 battery_level (level|1|6),(voltage|1|1),(temperature|1|1)
+2723 battery_status (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3)
+# This is logged when battery goes from discharging to charging.
+# It lets us count the total amount of time between charges and the discharge level
+2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6)
+
+
+# ---------------------------
+# PowerManagerService.java
+# ---------------------------
+# This is logged when the device is being forced to sleep (typically by
+# the user pressing the power button).
+2724 power_sleep_requested (wakeLocksCleared|1|1)
+# This is logged when the screen on broadcast has completed
+2725 power_screen_broadcast_send (wakelockCount|1|1)
+# This is logged when the screen broadcast has completed
+2726 power_screen_broadcast_done (on|1|5),(broadcastDuration|2|3),(wakelockCount|1|1)
+# This is logged when the screen on broadcast has completed
+2727 power_screen_broadcast_stop (which|1|5),(wakelockCount|1|1)
+# This is logged when the screen is turned on or off.
+2728 power_screen_state (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
+# This is logged when the partial wake lock (keeping the device awake
+# regardless of whether the screen is off) is acquired or released.
+2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3)
+
+#
+# Leave IDs through 2739 for more power logs (2730 used by battery_discharge above)
+#
+
+
+# ---------------------------
+# DeviceStorageMonitoryService.java
+# ---------------------------
+# The disk space free on the /data partition, in bytes
+2744 free_storage_changed (data|2|2)
+# Device low memory notification and disk space free on the /data partition, in bytes at that time
+2745 low_storage (data|2|2)
+# disk space free on the /data, /system, and /cache partitions in bytes
+2746 free_storage_left (data|2|2),(system|2|2),(cache|2|2)
+
+
+# ---------------------------
+# NotificationManagerService.java
+# ---------------------------
+# when a NotificationManager.notify is called
+2750 notification_enqueue (pkg|3),(id|1|5),(notification|3)
+# when someone tries to cancel a notification, the notification manager sometimes
+# calls this with flags too
+2751 notification_cancel (pkg|3),(id|1|5),(required_flags|1)
+# when someone tries to cancel all of the notifications for a particular package
+2752 notification_cancel_all (pkg|3),(required_flags|1)
+
+
+# ---------------------------
+# Watchdog.java
+# ---------------------------
+2802 watchdog (Service|3)
+2803 watchdog_proc_pss (Process|3),(Pid|1|5),(Pss|1|2)
+2804 watchdog_soft_reset (Process|3),(Pid|1|5),(MaxPss|1|2),(Pss|1|2),(Skip|3)
+2805 watchdog_hard_reset (Process|3),(Pid|1|5),(MaxPss|1|2),(Pss|1|2)
+2806 watchdog_pss_stats (EmptyPss|1|2),(EmptyCount|1|1),(BackgroundPss|1|2),(BackgroundCount|1|1),(ServicePss|1|2),(ServiceCount|1|1),(VisiblePss|1|2),(VisibleCount|1|1),(ForegroundPss|1|2),(ForegroundCount|1|1),(NoPssCount|1|1)
+2807 watchdog_proc_stats (DeathsInOne|1|1),(DeathsInTwo|1|1),(DeathsInThree|1|1),(DeathsInFour|1|1),(DeathsInFive|1|1)
+2808 watchdog_scheduled_reboot (Now|2|1),(Interval|1|3),(StartTime|1|3),(Window|1|3),(Skip|3)
+2809 watchdog_meminfo (MemFree|1|2),(Buffers|1|2),(Cached|1|2),(Active|1|2),(Inactive|1|2),(AnonPages|1|2),(Mapped|1|2),(Slab|1|2),(SReclaimable|1|2),(SUnreclaim|1|2),(PageTables|1|2)
+2810 watchdog_vmstat (runtime|2|3),(pgfree|1|1),(pgactivate|1|1),(pgdeactivate|1|1),(pgfault|1|1),(pgmajfault|1|1)
+2811 watchdog_requested_reboot (NoWait|1|1),(ScheduleInterval|1|3),(RecheckInterval|1|3),(StartTime|1|3),(Window|1|3),(MinScreenOff|1|3),(MinNextAlarm|1|3)
+
+
+# ---------------------------
+# BackupManagerService.java
+# ---------------------------
+2820 backup_data_changed (Package|3)
+2821 backup_start (Transport|3)
+2822 backup_transport_failure (Package|3)
+2823 backup_agent_failure (Package|3),(Message|3)
+2824 backup_package (Package|3),(Size|1|2)
+2825 backup_success (Packages|1|1),(Time|1|3)
+2826 backup_reset (Transport|3)
+2827 backup_initialize
+2830 restore_start (Transport|3),(Source|2|5)
+2831 restore_transport_failure
+2832 restore_agent_failure (Package|3),(Message|3)
+2833 restore_package (Package|3),(Size|1|2)
+2834 restore_success (Packages|1|1),(Time|1|3)
+
+
+# ---------------------------
+# SystemServer.java
+# ---------------------------
+# SystemServer.run() starts:
+3010 boot_progress_system_run (time|2|3)
+
+
+# ---------------------------
+# PackageManagerService.java
+# ---------------------------
+# Package Manager starts:
+3060 boot_progress_pms_start (time|2|3)
+# Package Manager .apk scan starts:
+3070 boot_progress_pms_system_scan_start (time|2|3)
+# Package Manager .apk scan starts:
+3080 boot_progress_pms_data_scan_start (time|2|3)
+# Package Manager .apk scan ends:
+3090 boot_progress_pms_scan_end (time|2|3)
+# Package Manager ready:
+3100 boot_progress_pms_ready (time|2|3)
+# + check activity_launch_time for Home app
+
+
+# ---------------------------
+# WindowManagerService.java
+# ---------------------------
+# Out of memory for surfaces.
+31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
+
+
+# ---------------------------
+# InputMethodManagerService.java
+# ---------------------------
+# Re-connecting to input method service because we haven't received its interface
+32000 imf_force_reconnect_ime (IME|4),(Time Since Connect|2|3),(Showing|1|1)
+
+
+# ---------------------------
+# ConnectivityService.java
+# ---------------------------
+# 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)
+50020 connectivity_state_changed (custom|1|5)
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/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9d69564..6f0a91d 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -24,7 +24,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.UEventObserver;
-import android.util.Log;
+import android.util.Slog;
import android.media.AudioManager;
import java.io.FileReader;
@@ -66,12 +66,12 @@ class HeadsetObserver extends UEventObserver {
@Override
public void onUEvent(UEventObserver.UEvent event) {
- if (LOG) Log.v(TAG, "Headset UEVENT: " + event.toString());
+ if (LOG) Slog.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);
+ Slog.e(TAG, "Could not parse switch state from event " + event);
}
}
@@ -91,9 +91,9 @@ class HeadsetObserver extends UEventObserver {
newName = new String(buffer, 0, len).trim();
} catch (FileNotFoundException e) {
- Log.w(TAG, "This kernel does not have wired headset support");
+ Slog.w(TAG, "This kernel does not have wired headset support");
} catch (Exception e) {
- Log.e(TAG, "" , e);
+ Slog.e(TAG, "" , e);
}
update(newName, newState);
@@ -167,7 +167,7 @@ class HeadsetObserver extends UEventObserver {
intent.putExtra("name", headsetName);
intent.putExtra("microphone", microphone);
- if (LOG) Log.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
+ if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
// TODO: Should we require a permission?
ActivityManagerNative.broadcastStickyIntent(intent, null);
}
diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java
new file mode 100644
index 0000000..6fbf713
--- /dev/null
+++ b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java
@@ -0,0 +1,24 @@
+
+/*
+ * 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;
+
+interface INativeDaemonConnectorCallbacks {
+
+ void onDaemonConnected();
+ boolean onEvent(int code, String raw, String[] cooked);
+}
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 6f207e0..07a74da 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -16,12 +16,14 @@
package com.android.server;
-import android.util.Log;
+import android.util.Slog;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import java.io.PrintWriter;
+
public class InputDevice {
static final boolean DEBUG_POINTERS = false;
static final boolean DEBUG_HACKS = false;
@@ -32,6 +34,16 @@ public class InputDevice {
/** Maximum number of pointers we will track and report. */
static final int MAX_POINTERS = 10;
+ /**
+ * Slop distance for jumpy pointer detection.
+ * The vertical range of the screen divided by this is our epsilon value.
+ */
+ private static final int JUMPY_EPSILON_DIVISOR = 212;
+
+ /** Number of jumpy points to drop for touchscreens that need it. */
+ private static final int JUMPY_TRANSITION_DROPS = 3;
+ private static final int JUMPY_DROP_LIMIT = 3;
+
final int id;
final int classes;
final String name;
@@ -58,6 +70,7 @@ public class InputDevice {
float yMoveScale;
MotionEvent currentMove = null;
boolean changed = false;
+ boolean everChanged = false;
long mDownTime = 0;
// The currently assigned pointer IDs, corresponding to the last data.
@@ -81,6 +94,9 @@ public class InputDevice {
// Used to determine whether we dropped bad data, to avoid doing
// it repeatedly.
final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
+
+ // Used to count the number of jumpy points dropped.
+ private int mJumpyPointsDropped = 0;
// Used to perform averaging of reported coordinates, to smooth
// the data and filter out transients during a release.
@@ -103,6 +119,56 @@ public class InputDevice {
int mAddingPointerOffset = 0;
final boolean[] mDown = new boolean[MAX_POINTERS];
+ void dumpIntArray(PrintWriter pw, int[] array) {
+ pw.print("[");
+ for (int i=0; i<array.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(array[i]);
+ }
+ pw.print("]");
+ }
+
+ void dumpBooleanArray(PrintWriter pw, boolean[] array) {
+ pw.print("[");
+ for (int i=0; i<array.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(array[i] ? "true" : "false");
+ }
+ pw.print("]");
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
+ pw.print(" yPrecision="); pw.println(yPrecision);
+ pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
+ pw.print(" yMoveScale="); pw.println(yMoveScale);
+ if (currentMove != null) {
+ pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
+ }
+ if (changed || mDownTime != 0) {
+ pw.print(prefix); pw.print("changed="); pw.print(changed);
+ pw.print(" mDownTime="); pw.println(mDownTime);
+ }
+ pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
+ pw.println("");
+ if (mSkipLastPointers || mLastNumPointers != 0) {
+ pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
+ pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
+ pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
+ pw.println("");
+ }
+ if (mNextNumPointers != 0) {
+ pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
+ pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
+ pw.println("");
+ }
+ pw.print(prefix); pw.print("mDroppedBadPoint=");
+ dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
+ pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
+ pw.print(prefix); pw.print("mDown=");
+ dumpBooleanArray(pw, mDown); pw.println("");
+ }
+
MotionState(int mx, int my) {
xPrecision = mx;
yPrecision = my;
@@ -142,7 +208,7 @@ public class InputDevice {
final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
//final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
- if (DEBUG_HACKS) Log.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
boolean dropped = false;
if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
dropped = true;
@@ -156,7 +222,7 @@ public class InputDevice {
int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
//if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
- if (DEBUG_HACKS) Log.v("InputDevice", "Comparing with last point #" + j
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j
+ ": y=" + mLastData[joff] + " dy=" + dy);
if (dy < maxDy) {
dropped = false;
@@ -168,7 +234,7 @@ public class InputDevice {
}
if (dropped) {
dropped = true;
- Log.i("InputDevice", "Dropping bad point #" + i
+ Slog.i("InputDevice", "Dropping bad point #" + i
+ ": newY=" + y + " closestDy=" + closestDy
+ " maxDy=" + maxDy);
mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
@@ -179,6 +245,164 @@ public class InputDevice {
}
}
+ void dropJumpyPoint(InputDevice dev) {
+ // We should always have absY, but let's be paranoid.
+ if (dev.absY == null) {
+ return;
+ }
+ final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR;
+
+ final int nextNumPointers = mNextNumPointers;
+ final int lastNumPointers = mLastNumPointers;
+ final int[] nextData = mNextData;
+ final int[] lastData = mLastData;
+
+ if (nextNumPointers != mLastNumPointers) {
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Different pointer count " + lastNumPointers +
+ " -> " + nextNumPointers);
+ for (int i = 0; i < nextNumPointers; i++) {
+ int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ Slog.d("InputDevice", "Pointer " + i + " (" +
+ mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
+ mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
+ }
+ }
+
+ // Just drop the first few events going from 1 to 2 pointers.
+ // They're bad often enough that they're not worth considering.
+ if (lastNumPointers == 1 && nextNumPointers == 2
+ && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ mNextNumPointers = 1;
+ mJumpyPointsDropped++;
+ } else if (lastNumPointers == 2 && nextNumPointers == 1
+ && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ // The event when we go from 2 -> 1 tends to be messed up too
+ System.arraycopy(lastData, 0, nextData, 0,
+ lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
+ mNextNumPointers = lastNumPointers;
+ mJumpyPointsDropped++;
+
+ if (DEBUG_HACKS) {
+ for (int i = 0; i < mNextNumPointers; i++) {
+ int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ Slog.d("InputDevice", "Pointer " + i + " replaced (" +
+ mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
+ mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
+ }
+ }
+ } else {
+ mJumpyPointsDropped = 0;
+
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Transition - drop limit reset");
+ }
+ }
+ return;
+ }
+
+ // A 'jumpy' point is one where the coordinate value for one axis
+ // has jumped to the other pointer's location. No need to do anything
+ // else if we only have one pointer.
+ if (nextNumPointers < 2) {
+ return;
+ }
+
+ int badPointerIndex = -1;
+ int badPointerReplaceXWith = 0;
+ int badPointerReplaceYWith = 0;
+ int badPointerDistance = Integer.MIN_VALUE;
+ for (int i = nextNumPointers - 1; i >= 0; i--) {
+ boolean dropx = false;
+ boolean dropy = false;
+
+ // Limit how many times a jumpy point can get dropped.
+ if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
+ final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
+ final int x = nextData[ioff + MotionEvent.SAMPLE_X];
+ final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
+
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
+ }
+
+ // Check if a touch point is too close to another's coordinates
+ for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) {
+ if (j == i) {
+ continue;
+ }
+
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ final int xOther = nextData[joff + MotionEvent.SAMPLE_X];
+ final int yOther = nextData[joff + MotionEvent.SAMPLE_Y];
+
+ dropx = Math.abs(x - xOther) <= jumpyEpsilon;
+ dropy = Math.abs(y - yOther) <= jumpyEpsilon;
+ }
+
+ if (dropx) {
+ int xreplace = lastData[MotionEvent.SAMPLE_X];
+ int yreplace = lastData[MotionEvent.SAMPLE_Y];
+ int distance = Math.abs(yreplace - y);
+ for (int j = 1; j < lastNumPointers; j++) {
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ int lasty = lastData[joff + MotionEvent.SAMPLE_Y];
+ int currDist = Math.abs(lasty - y);
+ if (currDist < distance) {
+ xreplace = lastData[joff + MotionEvent.SAMPLE_X];
+ yreplace = lasty;
+ distance = currDist;
+ }
+ }
+
+ int badXDelta = Math.abs(xreplace - x);
+ if (badXDelta > badPointerDistance) {
+ badPointerDistance = badXDelta;
+ badPointerIndex = i;
+ badPointerReplaceXWith = xreplace;
+ badPointerReplaceYWith = yreplace;
+ }
+ } else if (dropy) {
+ int xreplace = lastData[MotionEvent.SAMPLE_X];
+ int yreplace = lastData[MotionEvent.SAMPLE_Y];
+ int distance = Math.abs(xreplace - x);
+ for (int j = 1; j < lastNumPointers; j++) {
+ final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
+ int lastx = lastData[joff + MotionEvent.SAMPLE_X];
+ int currDist = Math.abs(lastx - x);
+ if (currDist < distance) {
+ xreplace = lastx;
+ yreplace = lastData[joff + MotionEvent.SAMPLE_Y];
+ distance = currDist;
+ }
+ }
+
+ int badYDelta = Math.abs(yreplace - y);
+ if (badYDelta > badPointerDistance) {
+ badPointerDistance = badYDelta;
+ badPointerIndex = i;
+ badPointerReplaceXWith = xreplace;
+ badPointerReplaceYWith = yreplace;
+ }
+ }
+ }
+ }
+ if (badPointerIndex >= 0) {
+ if (DEBUG_HACKS) {
+ Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex +
+ " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith +
+ ")");
+ }
+
+ final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA;
+ nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith;
+ nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith;
+ mJumpyPointsDropped++;
+ } else {
+ mJumpyPointsDropped = 0;
+ }
+ }
+
/**
* Special hack for devices that have bad screen data: aggregate and
* compute averages of the coordinate data, to reduce the amount of
@@ -188,7 +412,7 @@ public class InputDevice {
int nextNumPointers) {
final int numPointers = mLastNumPointers;
final int[] rawData = mLastData;
- if (DEBUG_HACKS) Log.v("InputDevice", "lastNumPointers=" + lastNumPointers
+ if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers
+ " nextNumPointers=" + nextNumPointers
+ " numPointers=" + numPointers);
for (int i=0; i<numPointers; i++) {
@@ -202,7 +426,7 @@ public class InputDevice {
if (lastNumPointers < nextNumPointers) {
// This pointer is going down. Clear its history
// and start fresh.
- if (DEBUG_HACKS) Log.v("InputDevice", "Pointer down @ index "
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index "
+ upOrDownPointer + " id " + mPointerIds[i]);
mHistoryDataStart[i] = 0;
mHistoryDataEnd[i] = 0;
@@ -215,7 +439,7 @@ public class InputDevice {
// The pointer is going up. Just fall through to
// recompute the last averaged point (and don't add
// it as a new point to include in the average).
- if (DEBUG_HACKS) Log.v("InputDevice", "Pointer up @ index "
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index "
+ upOrDownPointer + " id " + mPointerIds[i]);
}
} else {
@@ -228,7 +452,7 @@ public class InputDevice {
int dx = newX-oldX;
int dy = newY-oldY;
int delta = dx*dx + dy*dy;
- if (DEBUG_HACKS) Log.v("InputDevice", "Delta from last: " + delta);
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta);
if (delta >= (75*75)) {
// Magic number, if moving farther than this, turn
// off filtering to avoid lag in response.
@@ -284,7 +508,7 @@ public class InputDevice {
totalPressure += pressure;
x /= totalPressure;
y /= totalPressure;
- if (DEBUG_HACKS) Log.v("InputDevice", "Averaging " + totalPressure
+ if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure
+ " weight: (" + x + "," + y + ")");
mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
@@ -305,7 +529,7 @@ public class InputDevice {
final int[] nextData = mNextData;
final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
- if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
+ nextIndex + " dataOff=" + id);
final int x1 = nextData[id + MotionEvent.SAMPLE_X];
final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
@@ -329,7 +553,7 @@ public class InputDevice {
}
}
- if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
+ " best old index=" + bestIndex + " (distance="
+ bestDistance + ")");
next2Last[nextIndex] = bestIndex;
@@ -344,7 +568,7 @@ public class InputDevice {
return false;
}
- if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
+ " has multiple best new pointers!");
last2Next[bestIndex] = -2;
@@ -369,7 +593,7 @@ public class InputDevice {
last2Next[i] = -1;
}
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Update pointers: lastNumPointers=" + lastNumPointers
+ " nextNumPointers=" + nextNumPointers);
@@ -385,7 +609,7 @@ public class InputDevice {
// new pointer locations find their best previous location is
// the same.
if (conflicts) {
- if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
for (int i=0; i<lastNumPointers; i++) {
if (last2Next[i] != -2) {
@@ -396,7 +620,7 @@ public class InputDevice {
// we should do something like the one described at
// http://portal.acm.org/citation.cfm?id=997856
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Resolving last index #" + i);
int numFound;
@@ -416,7 +640,7 @@ public class InputDevice {
}
if (worstJ >= 0) {
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Worst new pointer: " + worstJ
+ " (distance=" + worstDistance + ")");
if (assignPointer(worstJ, false)) {
@@ -434,13 +658,13 @@ public class InputDevice {
if (lastNumPointers < nextNumPointers) {
// We have one or more new pointers that are down. Create a
// new pointer identifier for one of them.
- if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer");
int nextId = 0;
int i=0;
while (i < lastNumPointers) {
if (mPointerIds[i] > nextId) {
// Found a hole, insert the pointer here.
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Inserting new pointer at hole " + i);
System.arraycopy(mPointerIds, i, mPointerIds,
i+1, lastNumPointers-i);
@@ -453,7 +677,7 @@ public class InputDevice {
nextId++;
}
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"New pointer id " + nextId + " at index " + i);
mLastNumPointers++;
@@ -463,7 +687,7 @@ public class InputDevice {
// And assign this identifier to the first new pointer.
for (int j=0; j<nextNumPointers; j++) {
if (next2Last[j] < 0) {
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Assigning new id to new pointer index " + j);
next2Last[j] = i;
break;
@@ -477,7 +701,7 @@ public class InputDevice {
for (int i=0; i<nextNumPointers; i++) {
int lastIndex = next2Last[i];
if (lastIndex >= 0) {
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Copying next pointer index " + i
+ " to last index " + lastIndex);
System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
@@ -489,10 +713,10 @@ public class InputDevice {
if (lastNumPointers > nextNumPointers) {
// One or more pointers has gone up. Find the first one,
// and adjust accordingly.
- if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer");
for (int i=0; i<lastNumPointers; i++) {
if (last2Next[i] == -1) {
- if (DEBUG_POINTERS) Log.v("InputDevice",
+ if (DEBUG_POINTERS) Slog.v("InputDevice",
"Removing old pointer at index " + i);
retIndex = i;
break;
@@ -531,7 +755,7 @@ public class InputDevice {
final int lastNumPointers = mLastNumPointers;
final int nextNumPointers = mNextNumPointers;
if (mNextNumPointers > MAX_POINTERS) {
- Log.w("InputDevice", "Number of pointers " + mNextNumPointers
+ Slog.w("InputDevice", "Number of pointers " + mNextNumPointers
+ " exceeded maximum of " + MAX_POINTERS);
mNextNumPointers = MAX_POINTERS;
}
@@ -549,7 +773,7 @@ public class InputDevice {
final int numPointers = mLastNumPointers;
- if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
+ if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
+ numPointers + " pointers (going from " + lastNumPointers
+ " to " + nextNumPointers + ")");
@@ -570,14 +794,14 @@ public class InputDevice {
mDownTime = curTime;
} else {
action = MotionEvent.ACTION_POINTER_DOWN
- | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
}
} else {
if (numPointers == 1) {
action = MotionEvent.ACTION_UP;
} else {
action = MotionEvent.ACTION_POINTER_UP
- | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
}
}
currentMove = null;
@@ -661,13 +885,13 @@ public class InputDevice {
}
if (currentMove != null) {
- if (false) Log.i("InputDevice", "Adding batch x="
+ if (false) Slog.i("InputDevice", "Adding batch x="
+ reportData[MotionEvent.SAMPLE_X]
+ " y=" + reportData[MotionEvent.SAMPLE_Y]
+ " to " + currentMove);
currentMove.addBatch(curTime, reportData, metaState);
if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
+ Slog.i("KeyInputQueue", "Updating: " + currentMove);
}
return null;
}
@@ -748,13 +972,13 @@ public class InputDevice {
}
if (currentMove != null) {
- if (false) Log.i("InputDevice", "Adding batch x="
+ if (false) Slog.i("InputDevice", "Adding batch x="
+ scaled[MotionEvent.SAMPLE_X]
+ " y=" + scaled[MotionEvent.SAMPLE_Y]
+ " to " + currentMove);
currentMove.addBatch(curTime, scaled, metaState);
if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
+ Slog.i("KeyInputQueue", "Updating: " + currentMove);
}
return null;
}
@@ -775,6 +999,14 @@ public class InputDevice {
int range;
int flat;
int fuzz;
+
+ final void dump(PrintWriter pw) {
+ pw.print("minValue="); pw.print(minValue);
+ pw.print(" maxValue="); pw.print(maxValue);
+ pw.print(" range="); pw.print(range);
+ pw.print(" flat="); pw.print(flat);
+ pw.print(" fuzz="); pw.print(fuzz);
+ }
};
InputDevice(int _id, int _classes, String _name,
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index afcba47..5bf66e4 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -16,6 +16,7 @@
package com.android.server;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.HandlerCaller;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -45,10 +46,10 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
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;
@@ -60,9 +61,10 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.view.IWindowManager;
@@ -89,24 +91,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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;
@@ -115,9 +115,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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
@@ -127,12 +127,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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
@@ -150,17 +150,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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(
@@ -177,122 +177,122 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
}
}
-
+
final HashMap<IBinder, ClientState> mClients
= new HashMap<IBinder, ClientState>();
-
+
/**
* Set once the system is ready to run third party code.
*/
boolean mSystemReady;
-
+
/**
* 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 last window token that gained focus.
*/
IBinder mCurFocusedWindow;
-
+
/**
* 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);
@@ -300,14 +300,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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) {
@@ -319,7 +319,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
hideInputMethodMenu();
return;
} else {
- Log.w(TAG, "Unexpected intent " + intent);
+ Slog.w(TAG, "Unexpected intent " + intent);
}
// Inform the current client of the change in active status
@@ -328,76 +328,117 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient.client.setActive(mScreenOn);
}
} catch (RemoteException e) {
- Log.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
+ Slog.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
+ mCurClient.pid + " uid " + mCurClient.uid);
}
}
}
-
- class PackageReceiver extends android.content.BroadcastReceiver {
+
+ class MyPackageMonitor extends PackageMonitor {
+
@Override
- public void onReceive(Context context, Intent intent) {
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ synchronized (mMethodMap) {
+ String curInputMethodId = Settings.Secure.getString(mContext
+ .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ final int N = mMethodList.size();
+ if (curInputMethodId != null) {
+ for (int i=0; i<N; i++) {
+ InputMethodInfo imi = mMethodList.get(i);
+ if (imi.getId().equals(curInputMethodId)) {
+ for (String pkg : packages) {
+ if (imi.getPackageName().equals(pkg)) {
+ if (!doit) {
+ return true;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, "");
+ chooseNewDefaultIMELocked();
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
synchronized (mMethodMap) {
- buildInputMethodListLocked(mMethodList, mMethodMap);
-
InputMethodInfo curIm = null;
- String curInputMethodId = Settings.Secure.getString(context
+ String curInputMethodId = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
final int N = mMethodList.size();
if (curInputMethodId != null) {
for (int i=0; i<N; i++) {
- if (mMethodList.get(i).getId().equals(curInputMethodId)) {
- curIm = mMethodList.get(i);
+ InputMethodInfo imi = mMethodList.get(i);
+ if (imi.getId().equals(curInputMethodId)) {
+ curIm = imi;
+ }
+ int change = isPackageDisappearing(imi.getPackageName());
+ if (change == PACKAGE_TEMPORARY_CHANGE
+ || change == PACKAGE_PERMANENT_CHANGE) {
+ Slog.i(TAG, "Input method uninstalled, disabling: "
+ + imi.getComponent());
+ setInputMethodEnabledLocked(imi.getId(), false);
}
}
}
-
+
+ buildInputMethodListLocked(mMethodList, mMethodMap);
+
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);
- if (!chooseNewDefaultIME()) {
- changed = true;
- curIm = null;
- curInputMethodId = "";
- Log.i(TAG, "Unsetting current input method");
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD,
- curInputMethodId);
+
+ if (curIm != null) {
+ int change = isPackageDisappearing(curIm.getPackageName());
+ if (change == PACKAGE_TEMPORARY_CHANGE
+ || change == PACKAGE_PERMANENT_CHANGE) {
+ 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...
+ Slog.i(TAG, "Current input method removed: " + curInputMethodId);
+ if (!chooseNewDefaultIMELocked()) {
+ changed = true;
+ curIm = null;
+ curInputMethodId = "";
+ Slog.i(TAG, "Unsetting current input method");
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ curInputMethodId);
+ }
}
}
-
- } else if (curIm == null) {
+ }
+
+ if (curIm == null) {
// We currently don't have a default input method... is
// one now available?
- changed = chooseNewDefaultIME();
+ changed = chooseNewDefaultIMELocked();
}
-
+
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 {
}
@@ -405,7 +446,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
onSessionCreated(mMethod, session);
}
}
-
+
public InputMethodManagerService(Context context, StatusBarService statusBar) {
mContext = context;
mHandler = new Handler(this);
@@ -416,35 +457,29 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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);
-
+
+ (new MyPackageMonitor()).register(mContext, true);
+
IntentFilter screenOnOffFilt = new IntentFilter();
screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF);
screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
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);
+ Slog.i(TAG, "Enabled input methods: " + enabledStr);
if (enabledStr == null) {
- Log.i(TAG, "Enabled input methods has not been set, enabling all");
+ Slog.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());
+ Slog.i(TAG, "Adding: " + imi.getId());
if (i > 0) sb.append(':');
sb.append(imi.getId());
if (defIm == null && imi.getIsDefaultResourceId() != 0) {
@@ -453,7 +488,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
imi.getPackageName(), 0).getResources();
if (res.getBoolean(imi.getIsDefaultResourceId())) {
defIm = imi;
- Log.i(TAG, "Selected default: " + imi.getId());
+ Slog.i(TAG, "Selected default: " + imi.getId());
}
} catch (PackageManager.NameNotFoundException ex) {
} catch (Resources.NotFoundException ex) {
@@ -462,7 +497,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (defIm == null && N > 0) {
defIm = mMethodList.get(0);
- Log.i(TAG, "No default found, using " + defIm.getId());
+ Slog.i(TAG, "No default found, using " + defIm.getId());
}
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.ENABLED_INPUT_METHODS, sb.toString());
@@ -471,12 +506,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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();
}
@@ -490,7 +525,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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);
+ Slog.e(TAG, "Input Method Manager Crash", e);
}
throw e;
}
@@ -503,12 +538,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
startInputInnerLocked();
} catch (RuntimeException e) {
- Log.w(TAG, "Unexpected exception", e);
+ Slog.w(TAG, "Unexpected exception", e);
}
}
}
}
-
+
public List<InputMethodInfo> getInputMethodList() {
synchronized (mMethodMap) {
return new ArrayList<InputMethodInfo>(mMethodList);
@@ -523,14 +558,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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) {
@@ -538,7 +573,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
-
+
return res;
}
@@ -549,13 +584,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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);
@@ -564,10 +599,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
msg.recycle();
}
}
-
+
void unbindCurrentClientLocked() {
if (mCurClient != null) {
- if (DEBUG) Log.v(TAG, "unbindCurrentInputLocked: client = "
+ if (DEBUG) Slog.v(TAG, "unbindCurrentInputLocked: client = "
+ mCurClient.client.asBinder());
if (mBoundToMethod) {
mBoundToMethod = false;
@@ -579,20 +614,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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 "
+ Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
+ mCurClient.pid + " uid " + mCurClient.uid);
}
mCurClient = null;
-
+
hideInputMethodMenuLocked();
}
}
-
+
private int getImeShowFlags() {
int flags = 0;
if (mShowForced) {
@@ -603,7 +638,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return flags;
}
-
+
private int getAppShowFlags() {
int flags = 0;
if (mShowForced) {
@@ -613,7 +648,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return flags;
}
-
+
InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
if (!mBoundToMethod) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
@@ -629,14 +664,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
}
if (mShowRequested) {
- if (DEBUG) Log.v(TAG, "Attach new input asks to show input");
+ if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(getAppShowFlags(), null);
}
return needResult
? new InputBindResult(session.session, mCurId, mCurSeq)
: null;
}
-
+
InputBindResult startInputLocked(IInputMethodClient client,
IInputContext inputContext, EditorInfo attribute,
boolean initial, boolean needResult) {
@@ -644,13 +679,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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
@@ -658,18 +693,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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
+ Slog.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.
unbindCurrentClientLocked();
- if (DEBUG) Log.v(TAG, "switching to client: client = "
+ if (DEBUG) Slog.v(TAG, "switching to client: client = "
+ cs.client.asBinder());
// If the screen is on, inform the new client it is active
@@ -677,19 +712,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
cs.client.setActive(mScreenOn);
} catch (RemoteException e) {
- Log.w(TAG, "Got RemoteException sending setActive notification to pid "
+ Slog.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) {
@@ -701,7 +736,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurMethod != null) {
if (!cs.sessionRequested) {
cs.sessionRequested = true;
- if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
+ if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_CREATE_SESSION, mCurMethod,
new MethodCallback(mCurMethod)));
@@ -720,33 +755,33 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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);
+ EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
+ mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
}
}
}
-
+
return startInputInnerLocked();
}
-
+
InputBindResult startInputInnerLocked() {
if (mCurMethodId == null) {
return mNoBinding;
}
-
+
if (!mSystemReady) {
// If the system is not yet ready, we shouldn't be running third
// party code.
return new InputBindResult(null, mCurMethodId, mCurSeq);
}
-
+
InputMethodInfo info = mMethodMap.get(mCurMethodId);
if (info == null) {
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
}
-
+
unbindCurrentMethodLocked(false);
-
+
mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
mCurIntent.setComponent(info.getComponent());
mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
@@ -759,7 +794,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurId = info.getId();
mCurToken = new Binder();
try {
- if (DEBUG) Log.v(TAG, "Adding window token: " + mCurToken);
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
mIWindowManager.addWindowToken(mCurToken,
WindowManager.LayoutParams.TYPE_INPUT_METHOD);
} catch (RemoteException e) {
@@ -767,12 +802,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(null, mCurId, mCurSeq);
} else {
mCurIntent = null;
- Log.w(TAG, "Failure connecting to input method service: "
+ Slog.w(TAG, "Failure connecting to input method service: "
+ mCurIntent);
}
return null;
}
-
+
public InputBindResult startInput(IInputMethodClient client,
IInputContext inputContext, EditorInfo attribute,
boolean initial, boolean needResult) {
@@ -786,24 +821,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
-
+
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 (mCurToken == null) {
- Log.w(TAG, "Service connected without a token!");
+ Slog.w(TAG, "Service connected without a token!");
unbindCurrentMethodLocked(false);
return;
}
- if (DEBUG) Log.v(TAG, "Initiating attach with token: " + mCurToken);
+ if (DEBUG) Slog.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 "
+ if (DEBUG) Slog.v(TAG, "Creating first session while with client "
+ mCurClient);
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_CREATE_SESSION, mCurMethod,
@@ -830,25 +865,25 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
-
+
void unbindCurrentMethodLocked(boolean reportToClient) {
if (mHaveConnection) {
mContext.unbindService(this);
mHaveConnection = false;
}
-
+
if (mCurToken != null) {
try {
- if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken);
+ if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
mIWindowManager.removeWindowToken(mCurToken);
} catch (RemoteException e) {
}
mCurToken = null;
}
-
+
mCurId = null;
clearCurMethodLocked();
-
+
if (reportToClient && mCurClient != null) {
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
@@ -860,7 +895,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
sessionState.session.finishSession();
} catch (RemoteException e) {
- Log.w(TAG, "Session failed to close due to remote exception", e);
+ Slog.w(TAG, "Session failed to close due to remote exception", e);
}
}
}
@@ -879,10 +914,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mStatusBar.setIconVisibility(mInputMethodIcon, false);
}
-
+
public void onServiceDisconnected(ComponentName name) {
synchronized (mMethodMap) {
- if (DEBUG) Log.v(TAG, "Service disconnected: " + name
+ if (DEBUG) Slog.v(TAG, "Service disconnected: " + name
+ " mCurIntent=" + mCurIntent);
if (mCurMethod != null && mCurIntent != null
&& name.equals(mCurIntent.getComponent())) {
@@ -904,16 +939,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
long ident = Binder.clearCallingIdentity();
try {
if (token == null || mCurToken != token) {
- Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ Slog.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");
+ if (DEBUG) Slog.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");
+ if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
mInputMethodData.iconId = iconId;
mInputMethodData.iconPackage = packageName;
mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
@@ -936,7 +971,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
setInputMethodLocked(id);
} catch (IllegalArgumentException e) {
- Log.w(TAG, "Unknown input method from prefs: " + id, e);
+ Slog.w(TAG, "Unknown input method from prefs: " + id, e);
mCurMethodId = null;
unbindCurrentMethodLocked(true);
}
@@ -946,17 +981,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
unbindCurrentMethodLocked(true);
}
}
-
+
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;
@@ -965,6 +1000,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (ActivityManagerNative.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra("input_method_id", id);
mContext.sendBroadcast(intent);
}
@@ -973,7 +1009,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Binder.restoreCallingIdentity(ident);
}
}
-
+
public boolean showSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
long ident = Binder.clearCallingIdentity();
@@ -986,22 +1022,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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);
+ Slog.w(TAG, "Ignoring showSoftInput of: " + client);
return false;
}
} catch (RemoteException e) {
return false;
}
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be shown");
+
+ if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(flags, resultReceiver);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
-
+
boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
mShowRequested = true;
if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
@@ -1011,11 +1047,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mShowExplicitlyRequested = true;
mShowForced = true;
}
-
+
if (!mSystemReady) {
return false;
}
-
+
boolean res = false;
if (mCurMethod != null) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
@@ -1029,15 +1065,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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,
+ EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, mCurMethodId,
SystemClock.uptimeMillis()-mLastBindTime,1);
mContext.unbindService(this);
mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE);
}
-
+
return res;
}
-
+
public boolean hideSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
long ident = Binder.clearCallingIdentity();
@@ -1050,31 +1086,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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);
+ Slog.w(TAG, "Ignoring hideSoftInput of: " + client);
return false;
}
} catch (RemoteException e) {
return false;
}
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
+
+ if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
return hideCurrentInputLocked(flags, resultReceiver);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
-
+
boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mShowExplicitlyRequested || mShowForced)) {
- if (DEBUG) Log.v(TAG,
+ if (DEBUG) Slog.v(TAG,
"Not hiding: explicit show not cancelled by non-explicit hide");
return false;
}
if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
- if (DEBUG) Log.v(TAG,
+ if (DEBUG) Slog.v(TAG,
"Not hiding: forced show not cancelled by not-always hide");
return false;
}
@@ -1092,20 +1128,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mShowForced = false;
return res;
}
-
+
public void windowGainedFocus(IInputMethodClient client, IBinder windowToken,
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()
+ if (DEBUG) Slog.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 {
@@ -1113,19 +1149,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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, "Client not active, ignoring focus gain of: " + client);
+ Slog.w(TAG, "Client not active, ignoring focus gain of: " + client);
return;
}
} catch (RemoteException e) {
}
}
-
+
if (mCurFocusedWindow == windowToken) {
- Log.w(TAG, "Window already focused, ignoring focus gain of: " + client);
+ Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
return;
}
mCurFocusedWindow = windowToken;
-
+
switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
if (!isTextEditor || (softInputMode &
@@ -1135,7 +1171,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// 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");
+ if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
}
} else if (isTextEditor && (softInputMode &
@@ -1145,7 +1181,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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");
+ if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
}
break;
@@ -1155,23 +1191,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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");
+ if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
hideCurrentInputLocked(0, null);
}
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
- if (DEBUG) Log.v(TAG, "Window asks to hide input");
+ if (DEBUG) Slog.v(TAG, "Window asks to hide input");
hideCurrentInputLocked(0, null);
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");
+ if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
}
break;
case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
- if (DEBUG) Log.v(TAG, "Window asks to always show input");
+ if (DEBUG) Slog.v(TAG, "Window asks to always show input");
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
break;
}
@@ -1180,12 +1216,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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);
+ Slog.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client);
}
mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER);
@@ -1203,7 +1239,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
} else if (mCurToken != token) {
- Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring setInputMethod of token: " + token);
return;
}
@@ -1219,7 +1255,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void hideMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
if (token == null || mCurToken != token) {
- Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring hideInputMethod of token: " + token);
return;
}
long ident = Binder.clearCallingIdentity();
@@ -1230,11 +1266,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
-
+
public void showMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
if (token == null || mCurToken != token) {
- Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ Slog.w(TAG, "Ignoring hideInputMethod of token: " + token);
return;
}
long ident = Binder.clearCallingIdentity();
@@ -1250,7 +1286,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mEnabledSession != session) {
if (mEnabledSession != null) {
try {
- if (DEBUG) Log.v(TAG, "Disabling: " + mEnabledSession);
+ if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
mEnabledSession.method.setSessionEnabled(
mEnabledSession.session, false);
} catch (RemoteException e) {
@@ -1258,23 +1294,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mEnabledSession = session;
try {
- if (DEBUG) Log.v(TAG, "Enabling: " + mEnabledSession);
+ if (DEBUG) Slog.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();
@@ -1308,7 +1344,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_ATTACH_TOKEN:
args = (HandlerCaller.SomeArgs)msg.obj;
try {
- if (DEBUG) Log.v(TAG, "Sending attach of token: " + args.arg2);
+ if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
} catch (RemoteException e) {
}
@@ -1322,7 +1358,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return true;
// ---------------------------------------------------------
-
+
case MSG_START_INPUT:
args = (HandlerCaller.SomeArgs)msg.obj;
try {
@@ -1343,9 +1379,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} catch (RemoteException e) {
}
return true;
-
+
// ---------------------------------------------------------
-
+
case MSG_UNBIND_METHOD:
try {
((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1);
@@ -1359,7 +1395,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
((IInputMethodClient)args.arg1).onBindMethod(
(InputBindResult)args.arg2);
} catch (RemoteException e) {
- Log.w(TAG, "Client died receiving input method " + args.arg2);
+ Slog.w(TAG, "Client died receiving input method " + args.arg2);
}
return true;
}
@@ -1371,12 +1407,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
& ApplicationInfo.FLAG_SYSTEM) != 0;
}
- private boolean chooseNewDefaultIME() {
+ private boolean chooseNewDefaultIMELocked() {
List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
if (enabled != null && enabled.size() > 0) {
+ // We'd prefer to fall back on a system IME, since that is safer.
+ int i=enabled.size();
+ while (i > 0) {
+ i--;
+ if ((enabled.get(i).getServiceInfo().applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ break;
+ }
+ }
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
- enabled.get(0).getId());
+ enabled.get(i).getId());
return true;
}
@@ -1387,153 +1432,174 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
HashMap<String, InputMethodInfo> map) {
list.clear();
map.clear();
-
+
PackageManager pm = mContext.getPackageManager();
+ final Configuration config = mContext.getResources().getConfiguration();
+ final boolean haveHardKeyboard = config.keyboard == Configuration.KEYBOARD_QWERTY;
+ String disabledSysImes = Settings.Secure.getString(mContext.getContentResolver(),
+ Secure.DISABLED_SYSTEM_INPUT_METHODS);
+ if (disabledSysImes == null) disabledSysImes = "";
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
+ Slog.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);
+ if (DEBUG) Slog.d(TAG, "Checking " + compName);
try {
InputMethodInfo p = new InputMethodInfo(mContext, ri);
list.add(p);
- map.put(p.getId(), p);
+ final String id = p.getId();
+ map.put(id, p);
- // System IMEs are enabled by default
- if (isSystemIme(p)) {
- setInputMethodEnabled(p.getId(), true);
+ // System IMEs are enabled by default, unless there's a hard keyboard
+ // and the system IME was explicitly disabled
+ if (isSystemIme(p) && (!haveHardKeyboard || disabledSysImes.indexOf(id) < 0)) {
+ setInputMethodEnabledLocked(id, true);
}
if (DEBUG) {
- Log.d(TAG, "Found a third-party input method " + p);
+ Slog.d(TAG, "Found a third-party input method " + p);
}
-
+
} catch (XmlPullParserException e) {
- Log.w(TAG, "Unable to load input method " + compName, e);
+ Slog.w(TAG, "Unable to load input method " + compName, e);
} catch (IOException e) {
- Log.w(TAG, "Unable to load input method " + compName, e);
+ Slog.w(TAG, "Unable to load input method " + compName, e);
}
}
String defaultIme = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
if (!map.containsKey(defaultIme)) {
- if (chooseNewDefaultIME()) {
+ if (chooseNewDefaultIMELocked()) {
updateFromSettingsLocked();
}
}
}
-
+
// ----------------------------------------------------------------------
-
+
void showInputMethodMenu() {
- if (DEBUG) Log.v(TAG, "Show switching menu");
+ if (DEBUG) Slog.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());
+ if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
- mItems = new CharSequence[N];
- mIms = new InputMethodInfo[N];
+ final List<InputMethodInfo> immis = getEnabledInputMethodList();
- for (int i = 0; i < N; ++i) {
- InputMethodInfo property = immis.get(i);
- mItems[i] = property.loadLabel(pm);
- mIms[i] = property;
+ if (immis == null) {
+ return;
}
+
+ synchronized (mMethodMap) {
+ hideInputMethodMenuLocked();
- int checkedItem = 0;
- for (int i = 0; i < N; ++i) {
- if (mIms[i].getId().equals(lastInputMethodId)) {
- checkedItem = i;
- break;
+ int N = immis.size();
+
+ mItems = new CharSequence[N];
+ mIms = new InputMethodInfo[N];
+
+ int j = 0;
+ for (int i = 0; i < N; ++i) {
+ InputMethodInfo property = immis.get(i);
+ if (property == null) {
+ continue;
+ }
+ mItems[j] = property.loadLabel(pm);
+ mIms[j] = property;
+ j++;
}
- }
-
- AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- hideInputMethodMenu();
+
+ int checkedItem = 0;
+ for (int i = 0; i < N; ++i) {
+ if (mIms[i].getId().equals(lastInputMethodId)) {
+ checkedItem = i;
+ break;
+ }
}
- };
-
- 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];
+
+ 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();
- setInputMethodLocked(im.getId());
}
- }
- });
+ })
+ .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) {
+ if (mIms == null || mIms.length <= which) {
+ return;
+ }
+ InputMethodInfo im = mIms[which];
+ hideInputMethodMenu();
+ if (im != null) {
+ setInputMethodLocked(im.getId());
+ }
+ }
+ }
+ });
- synchronized (mMethodMap) {
mSwitchingDialog = mDialogBuilder.create();
mSwitchingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
mSwitchingDialog.show();
}
}
-
+
void hideInputMethodMenu() {
synchronized (mMethodMap) {
hideInputMethodMenuLocked();
}
}
-
+
void hideInputMethodMenuLocked() {
- if (DEBUG) Log.v(TAG, "Hide switching menu");
+ if (DEBUG) Slog.v(TAG, "Hide switching menu");
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(
@@ -1546,96 +1612,100 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
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 : "");
+ return setInputMethodEnabledLocked(id, enabled);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ boolean setInputMethodEnabledLocked(String id, boolean enabled) {
+ // Make sure this is a valid input method.
+ InputMethodInfo imm = mMethodMap.get(id);
+ if (imm == null) {
+ if (imm == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
+ }
+
+ StringBuilder builder = new StringBuilder(256);
+
+ boolean removed = false;
+ String firstId = null;
+
+ // Look through the currently enabled input methods.
+ String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ if (enabledStr != null) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(enabledStr);
+ while (splitter.hasNext()) {
+ String curId = splitter.next();
+ if (curId.equals(id)) {
+ if (enabled) {
+ // We are enabling this input method, but it is
+ // already enabled. Nothing to do. The previous
+ // state was enabled.
+ return true;
}
- // 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);
}
-
- // 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.
+ }
+ }
+
+ if (!enabled) {
+ if (!removed) {
+ // We are disabling the input method but it is already
+ // disabled. Nothing to do. The previous state was
+ // disabled.
return false;
- } finally {
- Binder.restoreCallingIdentity(ident);
}
+ // Update the setting with the new list of input methods.
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+ // We the disabled input method is currently selected, switch
+ // to another one.
+ String selId = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (id.equals(selId)) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ firstId != null ? firstId : "");
+ }
+ // Previous state was enabled.
+ return true;
}
+
+ // Add in the newly enabled input method.
+ if (enabledStr == null || enabledStr.length() == 0) {
+ enabledStr = id;
+ } else {
+ enabledStr = enabledStr + ':' + id;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+
+ // Previous state was disabled.
+ return false;
}
// ----------------------------------------------------------------------
-
+
@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());
@@ -1644,9 +1714,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
IInputMethod method;
ClientState client;
-
+
final Printer p = new PrintWriterPrinter(pw);
-
+
synchronized (mMethodMap) {
p.println("Current Input Method Manager state:");
int N = mMethodList.size();
@@ -1683,7 +1753,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " mInputShown=" + mInputShown);
p.println(" mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn);
}
-
+
if (client != null) {
p.println(" ");
pw.flush();
@@ -1693,7 +1763,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
p.println("Input method client dead: " + e);
}
}
-
+
if (method != null) {
p.println(" ");
pw.flush();
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/Installer.java
index fe3ad15..2eaa58c 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/Installer.java
@@ -20,7 +20,7 @@ import android.content.pm.PackageStats;
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
import android.util.Config;
-import android.util.Log;
+import android.util.Slog;
import java.io.IOException;
import java.io.InputStream;
@@ -41,7 +41,7 @@ class Installer {
if (mSocket != null) {
return true;
}
- Log.i(TAG, "connecting...");
+ Slog.i(TAG, "connecting...");
try {
mSocket = new LocalSocket();
@@ -60,7 +60,7 @@ class Installer {
}
private void disconnect() {
- Log.i(TAG,"disconnecting...");
+ Slog.i(TAG,"disconnecting...");
try {
if (mSocket != null) mSocket.close();
} catch (IOException ex) { }
@@ -82,16 +82,16 @@ class Installer {
try {
count = mIn.read(buffer, off, len - off);
if (count <= 0) {
- Log.e(TAG, "read error " + count);
+ Slog.e(TAG, "read error " + count);
break;
}
off += count;
} catch (IOException ex) {
- Log.e(TAG,"read exception");
+ Slog.e(TAG,"read exception");
break;
}
}
-// Log.i(TAG, "read "+len+" bytes");
+// Slog.i(TAG, "read "+len+" bytes");
if (off == len) return true;
disconnect();
return false;
@@ -103,7 +103,7 @@ class Installer {
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+")");
+ Slog.e(TAG,"invalid reply length ("+len+")");
disconnect();
return false;
}
@@ -122,7 +122,7 @@ class Installer {
mOut.write(buf, 0, 2);
mOut.write(cmd, 0, len);
} catch (IOException ex) {
- Log.e(TAG,"write error");
+ Slog.e(TAG,"write error");
disconnect();
return false;
}
@@ -131,7 +131,7 @@ class Installer {
private synchronized String transaction(String cmd) {
if (!connect()) {
- Log.e(TAG, "connection failed");
+ Slog.e(TAG, "connection failed");
return "-1";
}
@@ -141,18 +141,18 @@ class Installer {
* write (this one). Try to reconnect and write
* the command one more time before giving up.
*/
- Log.e(TAG, "write command failed? reconnect!");
+ Slog.e(TAG, "write command failed? reconnect!");
if (!connect() || !writeCommand(cmd)) {
return "-1";
}
}
-// Log.i(TAG,"send: '"+cmd+"'");
+// Slog.i(TAG,"send: '"+cmd+"'");
if (readReply()) {
String s = new String(buf, 0, buflen);
-// Log.i(TAG,"recv: '"+s+"'");
+// Slog.i(TAG,"recv: '"+s+"'");
return s;
} else {
-// Log.i(TAG,"fail");
+// Slog.i(TAG,"fail");
return "-1";
}
}
@@ -210,6 +210,15 @@ class Installer {
return execute(builder.toString());
}
+ public int rename(String oldname, String newname) {
+ StringBuilder builder = new StringBuilder("rename");
+ builder.append(' ');
+ builder.append(oldname);
+ builder.append(' ');
+ builder.append(newname);
+ return execute(builder.toString());
+ }
+
public int deleteCacheFiles(String name) {
StringBuilder builder = new StringBuilder("rmcache");
builder.append(' ');
@@ -239,10 +248,15 @@ class Installer {
return execute(builder.toString());
}
- public int setForwardLockPerm(String packageName, int gid) {
+ /*
+ * @param packagePathSuffix The name of the path relative to install
+ * directory. Say if the path name is /data/app/com.test-1.apk,
+ * the package suffix path will be com.test-1
+ */
+ public int setForwardLockPerm(String packagePathSuffix, int gid) {
StringBuilder builder = new StringBuilder("protect");
builder.append(' ');
- builder.append(packageName);
+ builder.append(packagePathSuffix);
builder.append(' ');
builder.append(gid);
return execute(builder.toString());
@@ -257,7 +271,6 @@ class Installer {
builder.append(apkPath);
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
-
String s = transaction(builder.toString());
String res[] = s.split(" ");
@@ -273,4 +286,8 @@ class Installer {
return -1;
}
}
+
+ public int moveFiles() {
+ return execute("movefiles");
+ }
}
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index d8c8c90..8ab65e9 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import android.util.Log;
+import android.util.Slog;
import android.util.LogPrinter;
import android.util.Printer;
@@ -46,9 +47,9 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
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:");
+ Slog.v(TAG, "Adding filter: " + f);
+ f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ Slog.v(TAG, " Building Lookup Maps:");
}
mFilters.add(f);
@@ -72,9 +73,9 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
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:");
+ Slog.v(TAG, "Removing filter: " + f);
+ f.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ Slog.v(TAG, " Cleaning Lookup Maps:");
}
int numS = unregister_intent_filter(f, f.schemesIterator(),
@@ -90,38 +91,64 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
}
}
- void dumpMap(PrintWriter out, String prefix, Map<String, ArrayList<F>> map) {
+ boolean dumpMap(PrintWriter out, String titlePrefix, String title,
+ String prefix, Map<String, ArrayList<F>> map, String packageName) {
String eprefix = prefix + " ";
String fprefix = prefix + " ";
+ boolean printedSomething = false;
for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) {
- out.print(eprefix); out.print(e.getKey()); out.println(":");
ArrayList<F> a = e.getValue();
final int N = a.size();
+ boolean printedHeader = false;
for (int i=0; i<N; i++) {
- dumpFilter(out, fprefix, a.get(i));
+ F filter = a.get(i);
+ if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+ continue;
+ }
+ if (title != null) {
+ out.print(titlePrefix); out.println(title);
+ title = null;
+ }
+ if (!printedHeader) {
+ out.print(eprefix); out.print(e.getKey()); out.println(":");
+ printedHeader = true;
+ }
+ printedSomething = true;
+ dumpFilter(out, fprefix, filter);
}
}
+ return printedSomething;
}
- public void dump(PrintWriter out, String prefix) {
+ public boolean dump(PrintWriter out, String title, String prefix, String packageName) {
String innerPrefix = prefix + " ";
- out.print(prefix); out.println("Full MIME Types:");
- dumpMap(out, innerPrefix, mTypeToFilter);
- out.println(" ");
- out.print(prefix); out.println("Base MIME Types:");
- dumpMap(out, innerPrefix, mBaseTypeToFilter);
- out.println(" ");
- out.print(prefix); out.println("Wild MIME Types:");
- dumpMap(out, innerPrefix, mWildTypeToFilter);
- out.println(" ");
- out.print(prefix); out.println("Schemes:");
- dumpMap(out, innerPrefix, mSchemeToFilter);
- out.println(" ");
- out.print(prefix); out.println("Non-Data Actions:");
- dumpMap(out, innerPrefix, mActionToFilter);
- out.println(" ");
- out.print(prefix); out.println("MIME Typed Actions:");
- dumpMap(out, innerPrefix, mTypedActionToFilter);
+ String sepPrefix = "\n" + prefix;
+ String curPrefix = title + "\n" + prefix;
+ if (dumpMap(out, curPrefix, "Full MIME Types:", innerPrefix,
+ mTypeToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ if (dumpMap(out, curPrefix, "Base MIME Types:", innerPrefix,
+ mBaseTypeToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ if (dumpMap(out, curPrefix, "Wild MIME Types:", innerPrefix,
+ mWildTypeToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ if (dumpMap(out, curPrefix, "Schemes:", innerPrefix,
+ mSchemeToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ if (dumpMap(out, curPrefix, "Non-Data Actions:", innerPrefix,
+ mActionToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ if (dumpMap(out, curPrefix, "MIME Typed Actions:", innerPrefix,
+ mTypedActionToFilter, packageName)) {
+ curPrefix = sepPrefix;
+ }
+ return curPrefix == sepPrefix;
}
private class IteratorWrapper implements Iterator<F> {
@@ -188,7 +215,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
final boolean debug = localLOGV ||
((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
- if (debug) Log.v(
+ if (debug) Slog.v(
TAG, "Resolving type " + resolvedType + " scheme " + scheme
+ " of intent " + intent);
@@ -209,26 +236,26 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
// 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);
+ if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
secondTypeCut = mWildTypeToFilter.get(baseType);
- if (debug) Log.v(TAG, "Second type cut: " + secondTypeCut);
+ if (debug) Slog.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);
+ if (debug) Slog.v(TAG, "First type cut: " + firstTypeCut);
secondTypeCut = mWildTypeToFilter.get(baseType);
- if (debug) Log.v(TAG, "Second type cut: " + secondTypeCut);
+ if (debug) Slog.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);
+ if (debug) Slog.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 (debug) Slog.v(TAG, "Typed Action list: " + firstTypeCut);
}
}
}
@@ -238,7 +265,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
// 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 (debug) Slog.v(TAG, "Scheme list: " + schemeCut);
}
// If the intent does not specify any data -- either a MIME type or
@@ -246,7 +273,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
// data.
if (resolvedType == null && scheme == null && intent.getAction() != null) {
firstTypeCut = mActionToFilter.get(intent.getAction());
- if (debug) Log.v(TAG, "Action list: " + firstTypeCut);
+ if (debug) Slog.v(TAG, "Action list: " + firstTypeCut);
}
if (firstTypeCut != null) {
@@ -268,9 +295,9 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
sortResults(finalList);
if (debug) {
- Log.v(TAG, "Final result list:");
+ Slog.v(TAG, "Final result list:");
for (R r : finalList) {
- Log.v(TAG, " " + r);
+ Slog.v(TAG, " " + r);
}
}
return finalList;
@@ -285,6 +312,10 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
return true;
}
+ protected String packageForFilter(F filter) {
+ return null;
+ }
+
protected R newResult(F filter, int match) {
return (R)filter;
}
@@ -307,7 +338,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
while (i.hasNext()) {
String name = (String)i.next();
num++;
- if (localLOGV) Log.v(TAG, prefix + name);
+ if (localLOGV) Slog.v(TAG, prefix + name);
String baseName = name;
final int slashpos = name.indexOf('/');
if (slashpos > 0) {
@@ -318,7 +349,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
ArrayList<F> array = mTypeToFilter.get(name);
if (array == null) {
- //Log.v(TAG, "Creating new array for " + name);
+ //Slog.v(TAG, "Creating new array for " + name);
array = new ArrayList<F>();
mTypeToFilter.put(name, array);
}
@@ -327,7 +358,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
if (slashpos > 0) {
array = mBaseTypeToFilter.get(baseName);
if (array == null) {
- //Log.v(TAG, "Creating new array for " + name);
+ //Slog.v(TAG, "Creating new array for " + name);
array = new ArrayList<F>();
mBaseTypeToFilter.put(baseName, array);
}
@@ -335,7 +366,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
} else {
array = mWildTypeToFilter.get(baseName);
if (array == null) {
- //Log.v(TAG, "Creating new array for " + name);
+ //Slog.v(TAG, "Creating new array for " + name);
array = new ArrayList<F>();
mWildTypeToFilter.put(baseName, array);
}
@@ -356,7 +387,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
while (i.hasNext()) {
String name = (String)i.next();
num++;
- if (localLOGV) Log.v(TAG, prefix + name);
+ if (localLOGV) Slog.v(TAG, prefix + name);
String baseName = name;
final int slashpos = name.indexOf('/');
if (slashpos > 0) {
@@ -392,10 +423,10 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
while (i.hasNext()) {
String name = i.next();
num++;
- if (localLOGV) Log.v(TAG, prefix + name);
+ if (localLOGV) Slog.v(TAG, prefix + name);
ArrayList<F> array = dest.get(name);
if (array == null) {
- //Log.v(TAG, "Creating new array for " + name);
+ //Slog.v(TAG, "Creating new array for " + name);
array = new ArrayList<F>();
dest.put(name, array);
}
@@ -414,7 +445,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
while (i.hasNext()) {
String name = i.next();
num++;
- if (localLOGV) Log.v(TAG, prefix + name);
+ if (localLOGV) Slog.v(TAG, prefix + name);
if (!remove_all_objects(dest.get(name), filter)) {
dest.remove(name);
}
@@ -447,12 +478,12 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
for (i=0; i<N; i++) {
F filter = src.get(i);
int match;
- if (debug) Log.v(TAG, "Matching against filter " + filter);
+ if (debug) Slog.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");
+ Slog.v(TAG, " Filter's target already added");
}
continue;
}
@@ -460,7 +491,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
match = filter.match(
intent.getAction(), resolvedType, scheme, intent.getData(), categories, TAG);
if (match >= 0) {
- if (debug) Log.v(TAG, " Filter matched! match=0x" +
+ if (debug) Slog.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
final R oneResult = newResult(filter, match);
@@ -480,13 +511,13 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
default: reason = "unknown reason"; break;
}
- Log.v(TAG, " Filter did not match: " + reason);
+ Slog.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");
+ Slog.w(TAG, "resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT");
}
}
diff --git a/services/java/com/android/server/JournaledFile.java b/services/java/com/android/server/JournaledFile.java
deleted file mode 100644
index 3d1f52d..0000000
--- a/services/java/com/android/server/JournaledFile.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2009 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.File;
-import java.io.IOException;
-
-public class JournaledFile {
- File mReal;
- File mTemp;
- boolean mWriting;
-
- public JournaledFile(File real, File temp) {
- mReal = real;
- mTemp = temp;
- }
-
- /** Returns the file for you to read.
- * @more
- * Prefers the real file. If it doesn't exist, uses the temp one, and then copies
- * it to the real one. If there is both a real file and a temp one, assumes that the
- * temp one isn't fully written and deletes it.
- */
- public File chooseForRead() {
- File result;
- if (mReal.exists()) {
- result = mReal;
- if (mTemp.exists()) {
- mTemp.delete();
- }
- } else if (mTemp.exists()) {
- result = mTemp;
- mTemp.renameTo(mReal);
- } else {
- return mReal;
- }
- return result;
- }
-
- /**
- * Returns a file for you to write.
- * @more
- * If a write is already happening, throws. In other words, you must provide your
- * own locking.
- * <p>
- * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes.
- */
- public File chooseForWrite() {
- if (mWriting) {
- throw new IllegalStateException("uncommitted write already in progress");
- }
- if (!mReal.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 chooseForRead code not
- // use the temporary one until it's fully written, create an empty file
- // for real, which will we'll shortly delete.
- try {
- mReal.createNewFile();
- } catch (IOException e) {
- // Ignore
- }
- }
-
- if (mTemp.exists()) {
- mTemp.delete();
- }
- mWriting = true;
- return mTemp;
- }
-
- /**
- * Commit changes.
- */
- public void commit() {
- if (!mWriting) {
- throw new IllegalStateException("no file to commit");
- }
- mWriting = false;
- mTemp.renameTo(mReal);
- }
-
- /**
- * Roll back changes.
- */
- public void rollback() {
- if (!mWriting) {
- throw new IllegalStateException("no file to roll back");
- }
- mWriting = false;
- mTemp.delete();
- }
-}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 1bb897b..f30346b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,11 +18,13 @@ package com.android.server;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Environment;
import android.os.LatencyTimer;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.util.Log;
+import android.os.SystemProperties;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
@@ -43,6 +45,7 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.PrintWriter;
import java.util.ArrayList;
public abstract class KeyInputQueue {
@@ -58,6 +61,12 @@ public abstract class KeyInputQueue {
*/
static boolean BAD_TOUCH_HACK = false;
+ /**
+ * Turn on some hacks to improve touch interaction with another device
+ * where touch coordinate data can get corrupted.
+ */
+ static boolean JUMPY_TOUCH_HACK = false;
+
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
@@ -177,7 +186,7 @@ public abstract class KeyInputQueue {
return;
}
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
+ ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
lastDevice = dev;
@@ -211,11 +220,11 @@ public abstract class KeyInputQueue {
String str = br.readLine();
if (str != null) {
String[] it = str.split(":");
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
final int N = it.length-6;
for (int i=0; i<=N; i+=6) {
if (!"0x01".equals(it[i])) {
- Log.w(TAG, "Unknown virtual key type at elem #" + i
+ Slog.w(TAG, "Unknown virtual key type at elem #" + i
+ ": " + it[i]);
continue;
}
@@ -226,22 +235,22 @@ public abstract class KeyInputQueue {
sb.centery = Integer.parseInt(it[i+3]);
sb.width = Integer.parseInt(it[i+4]);
sb.height = Integer.parseInt(it[i+5]);
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
+ sb.scancode + ": center=" + sb.centerx + ","
+ sb.centery + " size=" + sb.width + "x"
+ sb.height);
mVirtualKeys.add(sb);
} catch (NumberFormatException e) {
- Log.w(TAG, "Bad number at region " + i + " in: "
+ Slog.w(TAG, "Bad number at region " + i + " in: "
+ str, e);
}
}
}
br.close();
} catch (FileNotFoundException e) {
- Log.i(TAG, "No virtual keys found");
+ Slog.i(TAG, "No virtual keys found");
} catch (IOException e) {
- Log.w(TAG, "Error reading virtual keys", e);
+ Slog.w(TAG, "Error reading virtual keys", e);
}
}
@@ -264,14 +273,14 @@ public abstract class KeyInputQueue {
}
String name = parser.getAttributeValue(null, "name");
if (name != null) {
- if (DEBUG) Log.v(TAG, "addExcludedDevice " + name);
+ if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
addExcludedDevice(name);
}
}
} catch (FileNotFoundException e) {
// It's ok if the file does not exist.
} catch (Exception e) {
- Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+ Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
} finally {
try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
@@ -282,8 +291,10 @@ public abstract class KeyInputQueue {
lt = new LatencyTimer(100, 1000);
}
- BAD_TOUCH_HACK = context.getResources().getBoolean(
- com.android.internal.R.bool.config_filterTouchEvents);
+ Resources r = context.getResources();
+ BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
+
+ JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
mHapticFeedbackCallback = hapticFeedbackCallback;
@@ -326,21 +337,21 @@ public abstract class KeyInputQueue {
if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
config.touchscreen
= Configuration.TOUCHSCREEN_FINGER;
- //Log.i("foo", "***** HAVE TOUCHSCREEN!");
+ //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
}
if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
config.keyboard
= Configuration.KEYBOARD_QWERTY;
- //Log.i("foo", "***** HAVE QWERTY!");
+ //Slog.i("foo", "***** HAVE QWERTY!");
}
if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
config.navigation
= Configuration.NAVIGATION_TRACKBALL;
- //Log.i("foo", "***** HAVE TRACKBALL!");
+ //Slog.i("foo", "***** HAVE TRACKBALL!");
} else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
config.navigation
= Configuration.NAVIGATION_DPAD;
- //Log.i("foo", "***** HAVE DPAD!");
+ //Slog.i("foo", "***** HAVE DPAD!");
}
}
}
@@ -491,7 +502,7 @@ public abstract class KeyInputQueue {
Thread mThread = new Thread("InputDeviceReader") {
public void run() {
- if (DEBUG) Log.v(TAG, "InputDeviceReader.run()");
+ if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
@@ -507,7 +518,7 @@ public abstract class KeyInputQueue {
boolean configChanged = false;
if (false) {
- Log.i(TAG, "Input event: dev=0x"
+ Slog.i(TAG, "Input event: dev=0x"
+ Integer.toHexString(ev.deviceId)
+ " type=0x" + Integer.toHexString(ev.type)
+ " scancode=" + ev.scancode
@@ -531,7 +542,7 @@ public abstract class KeyInputQueue {
} else {
// We won't do anything with this device.
mIgnoredDevices.put(ev.deviceId, di);
- Log.i(TAG, "Ignoring non-input device: id=0x"
+ Slog.i(TAG, "Ignoring non-input device: id=0x"
+ Integer.toHexString(di.id)
+ ", name=" + di.name);
}
@@ -539,7 +550,7 @@ public abstract class KeyInputQueue {
} else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
synchronized (mFirst) {
if (false) {
- Log.i(TAG, "Device removed: id=0x"
+ Slog.i(TAG, "Device removed: id=0x"
+ Integer.toHexString(ev.deviceId));
}
di = mDevices.get(ev.deviceId);
@@ -551,7 +562,7 @@ public abstract class KeyInputQueue {
} else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
mIgnoredDevices.remove(ev.deviceId);
} else {
- Log.w(TAG, "Removing bad device id: "
+ Slog.w(TAG, "Removing bad device id: "
+ Integer.toHexString(ev.deviceId));
continue;
}
@@ -591,7 +602,7 @@ public abstract class KeyInputQueue {
//curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
final long curTime = SystemClock.uptimeMillis();
final long curTimeNano = System.nanoTime();
- //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
+ //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
final int classes = di.classes;
final int type = ev.type;
@@ -646,14 +657,14 @@ public abstract class KeyInputQueue {
di.mAbs.changed = true;
di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ MotionEvent.SAMPLE_X] = ev.value;
- if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
+ di.mAbs.mAddingPointerOffset
+ " X:" + ev.value);
} else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
di.mAbs.changed = true;
di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ MotionEvent.SAMPLE_Y] = ev.value;
- if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
+ di.mAbs.mAddingPointerOffset
+ " Y:" + ev.value);
} else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
@@ -711,7 +722,7 @@ public abstract class KeyInputQueue {
+ MotionEvent.SAMPLE_PRESSURE] != 0) {
final int num = di.mAbs.mNextNumPointers+1;
di.mAbs.mNextNumPointers = num;
- if (DEBUG_POINTERS) Log.v(TAG,
+ if (DEBUG_POINTERS) Slog.v(TAG,
"MT_REPORT: now have " + num + " pointers");
final int newOffset = (num <= InputDevice.MAX_POINTERS)
? (num * MotionEvent.NUM_SAMPLE_DATA)
@@ -721,7 +732,7 @@ public abstract class KeyInputQueue {
di.mAbs.mNextData[newOffset
+ MotionEvent.SAMPLE_PRESSURE] = 0;
} else {
- if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
+ if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
}
}
@@ -738,6 +749,7 @@ public abstract class KeyInputQueue {
InputDevice.MotionState ms = di.mAbs;
if (ms.changed) {
+ ms.everChanged = true;
ms.changed = false;
if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
@@ -755,6 +767,9 @@ public abstract class KeyInputQueue {
if (BAD_TOUCH_HACK) {
ms.dropBadPoint(di);
}
+ if (JUMPY_TOUCH_HACK) {
+ ms.dropJumpyPoint(di);
+ }
boolean doMotion = !monitorVirtualKey(di,
ev, curTime, curTimeNano);
@@ -775,14 +790,14 @@ public abstract class KeyInputQueue {
me = ms.generateAbsMotion(di, curTime,
curTimeNano, mDisplay,
mOrientation, mGlobalMetaState);
- if (DEBUG_POINTERS) Log.v(TAG, "Absolute: x="
+ if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
+ di.mAbs.mNextData[MotionEvent.SAMPLE_X]
+ " y="
+ di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
+ " ev=" + me);
if (me != null) {
if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i(TAG, "Enqueueing: " + me);
+ Slog.i(TAG, "Enqueueing: " + me);
}
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_TOUCHSCREEN, me);
@@ -809,12 +824,13 @@ public abstract class KeyInputQueue {
ms = di.mRel;
if (ms.changed) {
+ ms.everChanged = true;
ms.changed = false;
me = ms.generateRelMotion(di, curTime,
curTimeNano,
mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Relative: x="
+ if (false) Slog.v(TAG, "Relative: x="
+ di.mRel.mNextData[MotionEvent.SAMPLE_X]
+ " y="
+ di.mRel.mNextData[MotionEvent.SAMPLE_Y]
@@ -823,15 +839,13 @@ public abstract class KeyInputQueue {
addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_TRACKBALL, me);
}
-
- ms.finish();
}
}
}
}
} catch (RuntimeException exc) {
- Log.e(TAG, "InputReaderThread uncaught exception", exc);
+ Slog.e(TAG, "InputReaderThread uncaught exception", exc);
}
}
}
@@ -849,7 +863,7 @@ public abstract class KeyInputQueue {
&& absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
&& absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
&& absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input ("
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
+ absm.mNextData[MotionEvent.SAMPLE_X]
+ "," + absm.mNextData[MotionEvent.SAMPLE_Y]
+ ") inside of display");
@@ -869,7 +883,7 @@ public abstract class KeyInputQueue {
for (int i=0; i<N; i++) {
VirtualKey sb = mVirtualKeys.get(i);
sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test ("
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
+ absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
+ sb.scancode + " - (" + sb.hitLeft
@@ -877,7 +891,7 @@ public abstract class KeyInputQueue {
+ sb.hitBottom + ")");
if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
absm.mNextData[MotionEvent.SAMPLE_Y])) {
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
return sb;
}
}
@@ -900,7 +914,7 @@ public abstract class KeyInputQueue {
vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
ms.mLastNumPointers = ms.mNextNumPointers;
di.mKeyDownTime = curTime;
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
"Generate key down for: " + vk.scancode
+ " (keycode=" + vk.lastKeycode + ")");
KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
@@ -926,7 +940,7 @@ public abstract class KeyInputQueue {
final InputDevice.AbsoluteInfo absx = di.absX;
final InputDevice.AbsoluteInfo absy = di.absY;
final InputDevice.MotionState absm = di.mAbs;
- Log.v(TAG, "Rejecting ("
+ Slog.v(TAG, "Rejecting ("
+ absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
+ absx.minValue + "," + absy.minValue
@@ -947,7 +961,7 @@ public abstract class KeyInputQueue {
if (ms.mNextNumPointers <= 0) {
mPressedVirtualKey = null;
ms.mLastNumPointers = 0;
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode);
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
vk.lastKeycode, 0, vk.scancode,
KeyEvent.FLAG_VIRTUAL_HARD_KEY);
@@ -962,7 +976,7 @@ public abstract class KeyInputQueue {
// virtual key and start a pointer
// motion.
mPressedVirtualKey = null;
- if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode);
+ if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
vk.lastKeycode, 0, vk.scancode,
KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
@@ -1138,12 +1152,12 @@ public abstract class KeyInputQueue {
void recycleEvent(QueuedEvent ev) {
synchronized (mFirst) {
- //Log.i(TAG, "Recycle event: " + ev);
+ //Slog.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);
+ if (false) Slog.i(TAG, "Detach rel " + ev.event);
ev.inputDevice.mRel.currentMove = null;
ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
@@ -1237,7 +1251,7 @@ public abstract class KeyInputQueue {
InputDevice.AbsoluteInfo absPressure = null;
InputDevice.AbsoluteInfo absSize = null;
if (classes != 0) {
- Log.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
+ Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
+ ", name=" + name
+ ", classes=" + Integer.toHexString(classes));
if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
@@ -1269,15 +1283,102 @@ public abstract class KeyInputQueue {
InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
if (getAbsoluteInfo(id, channel, info)
&& info.minValue != info.maxValue) {
- Log.i(TAG, " " + name + ": min=" + info.minValue
+ Slog.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");
+ Slog.i(TAG, " " + name + ": unknown values");
return null;
}
private static native boolean readEvent(RawInputEvent outEvent);
+
+ void dump(PrintWriter pw, String prefix) {
+ synchronized (mFirst) {
+ for (int i=0; i<mDevices.size(); i++) {
+ InputDevice dev = mDevices.valueAt(i);
+ pw.print(prefix); pw.print("Device #");
+ pw.print(mDevices.keyAt(i)); pw.print(" ");
+ pw.print(dev.name); pw.print(" (classes=0x");
+ pw.print(Integer.toHexString(dev.classes));
+ pw.println("):");
+ pw.print(prefix); pw.print(" mKeyDownTime=");
+ pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
+ pw.println(dev.mMetaKeysState);
+ if (dev.absX != null) {
+ pw.print(prefix); pw.print(" absX: "); dev.absX.dump(pw);
+ pw.println("");
+ }
+ if (dev.absY != null) {
+ pw.print(prefix); pw.print(" absY: "); dev.absY.dump(pw);
+ pw.println("");
+ }
+ if (dev.absPressure != null) {
+ pw.print(prefix); pw.print(" absPressure: ");
+ dev.absPressure.dump(pw); pw.println("");
+ }
+ if (dev.absSize != null) {
+ pw.print(prefix); pw.print(" absSize: ");
+ dev.absSize.dump(pw); pw.println("");
+ }
+ if (dev.mAbs.everChanged) {
+ pw.print(prefix); pw.println(" mAbs:");
+ dev.mAbs.dump(pw, prefix + " ");
+ }
+ if (dev.mRel.everChanged) {
+ pw.print(prefix); pw.println(" mRel:");
+ dev.mRel.dump(pw, prefix + " ");
+ }
+ }
+ pw.println(" ");
+ for (int i=0; i<mIgnoredDevices.size(); i++) {
+ InputDevice dev = mIgnoredDevices.valueAt(i);
+ pw.print(prefix); pw.print("Ignored Device #");
+ pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
+ pw.print(dev.name); pw.print(" (classes=0x");
+ pw.print(Integer.toHexString(dev.classes));
+ pw.println(")");
+ }
+ pw.println(" ");
+ for (int i=0; i<mVirtualKeys.size(); i++) {
+ VirtualKey vk = mVirtualKeys.get(i);
+ pw.print(prefix); pw.print("Virtual Key #");
+ pw.print(i); pw.println(":");
+ pw.print(prefix); pw.print(" scancode="); pw.println(vk.scancode);
+ pw.print(prefix); pw.print(" centerx="); pw.print(vk.centerx);
+ pw.print(" centery="); pw.print(vk.centery);
+ pw.print(" width="); pw.print(vk.width);
+ pw.print(" height="); pw.println(vk.height);
+ pw.print(prefix); pw.print(" hitLeft="); pw.print(vk.hitLeft);
+ pw.print(" hitTop="); pw.print(vk.hitTop);
+ pw.print(" hitRight="); pw.print(vk.hitRight);
+ pw.print(" hitBottom="); pw.println(vk.hitBottom);
+ if (vk.lastDevice != null) {
+ pw.print(prefix); pw.print(" lastDevice=#");
+ pw.println(vk.lastDevice.id);
+ }
+ if (vk.lastKeycode != 0) {
+ pw.print(prefix); pw.print(" lastKeycode=");
+ pw.println(vk.lastKeycode);
+ }
+ }
+ pw.println(" ");
+ pw.print(prefix); pw.print(" Default keyboard: ");
+ pw.println(SystemProperties.get("hw.keyboards.0.devname"));
+ pw.print(prefix); pw.print(" mGlobalMetaState=");
+ pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
+ pw.println(mHaveGlobalMetaState);
+ pw.print(prefix); pw.print(" mDisplayWidth=");
+ pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
+ pw.println(mDisplayHeight);
+ pw.print(prefix); pw.print(" mOrientation=");
+ pw.println(mOrientation);
+ if (mPressedVirtualKey != null) {
+ pw.print(prefix); pw.print(" mPressedVirtualKey.scancode=");
+ pw.println(mPressedVirtualKey.scancode);
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/LightsService.java
new file mode 100644
index 0000000..c056eef
--- /dev/null
+++ b/services/java/com/android/server/LightsService.java
@@ -0,0 +1,163 @@
+/*
+ * 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.Handler;
+import android.os.Message;
+import android.util.Slog;
+
+public class LightsService {
+ private static final String TAG = "LightsService";
+
+ static final int LIGHT_ID_BACKLIGHT = 0;
+ static final int LIGHT_ID_KEYBOARD = 1;
+ static final int LIGHT_ID_BUTTONS = 2;
+ static final int LIGHT_ID_BATTERY = 3;
+ static final int LIGHT_ID_NOTIFICATIONS = 4;
+ static final int LIGHT_ID_ATTENTION = 5;
+ static final int LIGHT_ID_BLUETOOTH = 6;
+ static final int LIGHT_ID_WIFI = 7;
+ static final int LIGHT_ID_COUNT = 8;
+
+ static final int LIGHT_FLASH_NONE = 0;
+ static final int LIGHT_FLASH_TIMED = 1;
+ static final int LIGHT_FLASH_HARDWARE = 2;
+
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ static final int BRIGHTNESS_MODE_USER = 0;
+
+ /**
+ * Light brightness is managed by a light sensor.
+ */
+ static final int BRIGHTNESS_MODE_SENSOR = 1;
+
+ private final Light mLights[] = new Light[LIGHT_ID_COUNT];
+
+ public final class Light {
+
+ private Light(int id) {
+ mId = id;
+ }
+
+ public void setBrightness(int brightness) {
+ setBrightness(brightness, BRIGHTNESS_MODE_USER);
+ }
+
+ public void setBrightness(int brightness, int brightnessMode) {
+ synchronized (this) {
+ int color = brightness & 0x000000ff;
+ color = 0xff000000 | (color << 16) | (color << 8) | color;
+ setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
+ }
+ }
+
+ public void setColor(int color) {
+ synchronized (this) {
+ setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
+ }
+ }
+
+ public void setFlashing(int color, int mode, int onMS, int offMS) {
+ synchronized (this) {
+ setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
+ }
+ }
+
+
+ public void pulse() {
+ pulse(0x00ffffff, 7);
+ }
+
+ public void pulse(int color, int onMS) {
+ synchronized (this) {
+ if (mColor == 0 && !mFlashing) {
+ setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
+ mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
+ }
+ }
+ }
+
+ public void turnOff() {
+ synchronized (this) {
+ setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
+ }
+ }
+
+ private void stopFlashing() {
+ synchronized (this) {
+ setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
+ }
+ }
+
+ private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
+ if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
+ mColor = color;
+ mMode = mode;
+ mOnMS = onMS;
+ mOffMS = offMS;
+ setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ }
+ }
+
+ private int mId;
+ private int mColor;
+ private int mMode;
+ private int mOnMS;
+ private int mOffMS;
+ private boolean mFlashing;
+ }
+
+ LightsService(Context context) {
+
+ mNativePointer = init_native();
+ mContext = context;
+
+ for (int i = 0; i < LIGHT_ID_COUNT; i++) {
+ mLights[i] = new Light(i);
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ finalize_native(mNativePointer);
+ super.finalize();
+ }
+
+ public Light getLight(int id) {
+ return mLights[id];
+ }
+
+ private Handler mH = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Light light = (Light)msg.obj;
+ light.stopFlashing();
+ }
+ };
+
+ private static native int init_native();
+ private static native void finalize_native(int ptr);
+
+ private static native void setLight_native(int ptr, int light, int color, int mode,
+ int onMS, int offMS, int brightnessMode);
+
+ private final Context mContext;
+
+ private int mNativePointer;
+}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 024d8da..ef57056 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -27,26 +27,30 @@ import java.util.Observable;
import java.util.Observer;
import java.util.Set;
+import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.Cursor;
import android.location.Address;
-import android.location.IGeocodeProvider;
+import android.location.GeocoderParams;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -61,12 +65,15 @@ import android.os.Process;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
+import android.util.Slog;
import android.util.PrintWriterPrinter;
+import com.android.internal.location.GeocoderProxy;
import com.android.internal.location.GpsLocationProvider;
+import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.LocationProviderProxy;
import com.android.internal.location.MockProvider;
-import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.PassiveProvider;
/**
* The service class that manages LocationProviders and issues location
@@ -104,14 +111,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private static boolean sProvidersLoaded = false;
private final Context mContext;
- private IGeocodeProvider mGeocodeProvider;
+ private GeocoderProxy mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
// Cache the real providers for use in addTestProvider() and removeTestProvider()
- LocationProviderProxy mNetworkLocationProvider;
- LocationProviderProxy mGpsLocationProvider;
+ LocationProviderInterface mNetworkLocationProvider;
+ LocationProviderInterface mGpsLocationProvider;
// Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1;
@@ -130,10 +137,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
/**
* List of location providers.
*/
- private final ArrayList<LocationProviderProxy> mProviders =
- new ArrayList<LocationProviderProxy>();
- private final HashMap<String, LocationProviderProxy> mProvidersByName
- = new HashMap<String, LocationProviderProxy>();
+ private final ArrayList<LocationProviderInterface> mProviders =
+ new ArrayList<LocationProviderInterface>();
+ private final HashMap<String, LocationProviderInterface> mProvidersByName
+ = new HashMap<String, LocationProviderInterface>();
/**
* Object used internally for synchronization
@@ -347,7 +354,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void binderDied() {
if (LOCAL_LOGV) {
- Log.v(TAG, "Location listener died");
+ Slog.v(TAG, "Location listener died");
}
synchronized (mLock) {
removeUpdatesLocked(this);
@@ -407,14 +414,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- private void addProvider(LocationProviderProxy provider) {
+ private void addProvider(LocationProviderInterface provider) {
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
}
- private void removeProvider(LocationProviderProxy provider) {
+ private void removeProvider(LocationProviderInterface provider) {
mProviders.remove(provider);
- provider.unlinkProvider();
mProvidersByName.remove(provider.getName());
}
@@ -434,7 +440,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
try {
_loadProvidersLocked();
} catch (Exception e) {
- Log.e(TAG, "Exception loading providers:", e);
+ Slog.e(TAG, "Exception loading providers:", e);
}
}
@@ -442,12 +448,32 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Attempt to load "real" providers first
if (GpsLocationProvider.isSupported()) {
// Create a gps location provider
- GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
- mGpsStatusProvider = provider.getGpsStatusProvider();
- mNetInitiatedListener = provider.getNetInitiatedListener();
- LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
- addProvider(proxy);
- mGpsLocationProvider = proxy;
+ GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
+ mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
+ mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
+ addProvider(gpsProvider);
+ mGpsLocationProvider = gpsProvider;
+ }
+
+ // create a passive location provider, which is always enabled
+ PassiveProvider passiveProvider = new PassiveProvider(this);
+ addProvider(passiveProvider);
+ mEnabledProviders.add(passiveProvider.getName());
+
+ // initialize external network location and geocoder services
+ Resources resources = mContext.getResources();
+ String serviceName = resources.getString(
+ com.android.internal.R.string.config_networkLocationProvider);
+ if (serviceName != null) {
+ mNetworkLocationProvider =
+ new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
+ serviceName, mLocationHandler);
+ addProvider(mNetworkLocationProvider);
+ }
+
+ serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
+ if (serviceName != null) {
+ mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
}
updateProvidersLocked();
@@ -460,14 +486,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
super();
mContext = context;
- Thread thread = new Thread(null, this, "LocationManagerService");
- thread.start();
-
if (LOCAL_LOGV) {
- Log.v(TAG, "Constructed LocationManager Service");
+ Slog.v(TAG, "Constructed LocationManager Service");
}
}
+ void systemReady() {
+ // we defer starting up the service until the system is ready
+ Thread thread = new Thread(null, this, "LocationManagerService");
+ thread.start();
+ }
+
private void initialize() {
// Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -482,7 +511,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Register for Package Manager updates
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mBroadcastReceiver, sdFilter);
// listen for settings changes
ContentResolver resolver = mContext.getContentResolver();
@@ -504,45 +536,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
Looper.loop();
}
- public void installLocationProvider(String name, ILocationProvider provider) {
- if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
- }
-
- synchronized (mLock) {
- // check to see if we are reinstalling a dead provider
- LocationProviderProxy oldProvider = mProvidersByName.get(name);
- if (oldProvider != null) {
- if (oldProvider.isDead()) {
- Log.d(TAG, "replacing dead provider");
- removeProvider(oldProvider);
- } else {
- throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
- }
- }
-
- LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
- addProvider(proxy);
- updateProvidersLocked();
- if (LocationManager.NETWORK_PROVIDER.equals(name)) {
- mNetworkLocationProvider = proxy;
- }
-
- // notify provider of current network state
- proxy.updateNetworkState(mNetworkState, null);
- }
- }
-
- public void installGeocodeProvider(IGeocodeProvider provider) {
- if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
- }
-
- mGeocodeProvider = provider;
- }
-
private boolean isAllowedBySettingsLocked(String provider) {
if (mEnabledProviders.contains(provider)) {
return true;
@@ -552,14 +545,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
// Use system settings
ContentResolver resolver = mContext.getContentResolver();
- String allowedProviders = Settings.Secure.getString(resolver,
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
- return ((allowedProviders != null) && (allowedProviders.contains(provider)));
+ return Settings.Secure.isLocationProviderEnabled(resolver, provider);
}
private void checkPermissionsSafe(String provider) {
- if (LocationManager.GPS_PROVIDER.equals(provider)
+ if ((LocationManager.GPS_PROVIDER.equals(provider)
+ || LocationManager.PASSIVE_PROVIDER.equals(provider))
&& (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
@@ -575,7 +567,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private boolean isAllowedProviderSafe(String provider) {
- if (LocationManager.GPS_PROVIDER.equals(provider)
+ if ((LocationManager.GPS_PROVIDER.equals(provider)
+ || LocationManager.PASSIVE_PROVIDER.equals(provider))
&& (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
return false;
@@ -599,18 +592,18 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
- Log.e(TAG, "getAllProviders got exception:", e);
+ Slog.e(TAG, "getAllProviders got exception:", e);
return null;
}
}
private List<String> _getAllProvidersLocked() {
if (LOCAL_LOGV) {
- Log.v(TAG, "getAllProviders");
+ Slog.v(TAG, "getAllProviders");
}
ArrayList<String> out = new ArrayList<String>(mProviders.size());
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
out.add(p.getName());
}
return out;
@@ -624,18 +617,18 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
- Log.e(TAG, "getProviders got exception:", e);
+ Slog.e(TAG, "getProviders got exception:", e);
return null;
}
}
private List<String> _getProvidersLocked(boolean enabledOnly) {
if (LOCAL_LOGV) {
- Log.v(TAG, "getProviders");
+ Slog.v(TAG, "getProviders");
}
ArrayList<String> out = new ArrayList<String>(mProviders.size());
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
String name = p.getName();
if (isAllowedProviderSafe(name)) {
if (enabledOnly && !isAllowedBySettingsLocked(name)) {
@@ -649,7 +642,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private void updateProvidersLocked() {
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy p = mProviders.get(i);
+ LocationProviderInterface p = mProviders.get(i);
boolean isEnabled = p.isEnabled();
String name = p.getName();
boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
@@ -666,7 +659,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private void updateProviderListenersLocked(String provider, boolean enabled) {
int listeners = 0;
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
return;
}
@@ -772,7 +765,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
pw.println(prefix + "mUid=" + mUid);
pw.println(prefix + "mLastFixBroadcast:");
- mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
+ if (mLastFixBroadcast != null) {
+ mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
+ }
pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
}
}
@@ -789,7 +784,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
receiver.getListener().asBinder().linkToDeath(receiver, 0);
}
} catch (RemoteException e) {
- Log.e(TAG, "linkToDeath failed:", e);
+ Slog.e(TAG, "linkToDeath failed:", e);
return null;
}
}
@@ -832,8 +827,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "requestUpdates got exception:", e);
+ Slog.e(TAG, "requestUpdates got exception:", e);
}
}
@@ -845,19 +842,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "requestUpdates got exception:", e);
+ Slog.e(TAG, "requestUpdates got exception:", e);
}
}
private void requestLocationUpdatesLocked(String provider,
long minTime, float minDistance, Receiver receiver) {
if (LOCAL_LOGV) {
- Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
+ Slog.v(TAG, "_requestLocationUpdates: listener = " + receiver);
}
- LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (proxy == null) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -875,14 +874,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
if (newUid) {
- proxy.addListener(callingUid);
+ p.addListener(callingUid);
}
boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
if (isProviderEnabled) {
long minTimeForProvider = getMinTimeLocked(provider);
- proxy.setMinTime(minTimeForProvider);
- proxy.enableLocationTracking(true);
+ p.setMinTime(minTimeForProvider);
+ p.enableLocationTracking(true);
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(provider, false);
@@ -899,8 +898,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "removeUpdates got exception:", e);
+ Slog.e(TAG, "removeUpdates got exception:", e);
}
}
@@ -911,14 +912,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "removeUpdates got exception:", e);
+ Slog.e(TAG, "removeUpdates got exception:", e);
}
}
private void removeUpdatesLocked(Receiver receiver) {
if (LOCAL_LOGV) {
- Log.v(TAG, "_removeUpdates: listener = " + receiver);
+ Slog.v(TAG, "_removeUpdates: listener = " + receiver);
}
// so wakelock calls will succeed
@@ -942,9 +945,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Call dispose() on the obsolete update records.
for (UpdateRecord record : oldRecords.values()) {
if (!providerHasListener(record.mProvider, callingUid, receiver)) {
- LocationProviderProxy proxy = mProvidersByName.get(record.mProvider);
- if (proxy != null) {
- proxy.removeListener(callingUid);
+ LocationProviderInterface p = mProvidersByName.get(record.mProvider);
+ if (p != null) {
+ p.removeListener(callingUid);
}
}
record.disposeLocked();
@@ -968,7 +971,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
hasOtherListener = true;
}
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p != null) {
if (hasOtherListener) {
p.setMinTime(getMinTimeLocked(provider));
@@ -994,7 +997,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
try {
mGpsStatusProvider.addGpsStatusListener(listener);
} catch (RemoteException e) {
- Log.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
+ Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
return false;
}
return true;
@@ -1005,7 +1008,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
try {
mGpsStatusProvider.removeGpsStatusListener(listener);
} catch (Exception e) {
- Log.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
+ Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
}
}
}
@@ -1025,12 +1028,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
synchronized (mLock) {
- LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (proxy == null) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) {
return false;
}
- return proxy.sendExtraCommand(command, extras);
+ return p.sendExtraCommand(command, extras);
}
}
@@ -1045,7 +1048,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
catch (RemoteException e)
{
- Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
+ Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
return false;
}
}
@@ -1140,7 +1143,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
alert.isInProximity(latitude, longitude, accuracy);
if (!entered && inProximity) {
if (LOCAL_LOGV) {
- Log.v(TAG, "Entered alert");
+ Slog.v(TAG, "Entered alert");
}
mProximitiesEntered.add(alert);
Intent enteredIntent = new Intent();
@@ -1156,7 +1159,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) {
- Log.v(TAG, "Canceled proximity alert: " + alert, e);
+ Slog.v(TAG, "Canceled proximity alert: " + alert, e);
}
if (intentsToRemove == null) {
intentsToRemove = new ArrayList<PendingIntent>();
@@ -1165,7 +1168,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} else if (entered && !inProximity) {
if (LOCAL_LOGV) {
- Log.v(TAG, "Exited alert");
+ Slog.v(TAG, "Exited alert");
}
mProximitiesEntered.remove(alert);
Intent exitedIntent = new Intent();
@@ -1181,7 +1184,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (PendingIntent.CanceledException e) {
if (LOCAL_LOGV) {
- Log.v(TAG, "Canceled proximity alert: " + alert, e);
+ Slog.v(TAG, "Canceled proximity alert: " + alert, e);
}
if (intentsToRemove == null) {
intentsToRemove = new ArrayList<PendingIntent>();
@@ -1192,7 +1195,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} else {
// Mark alert for expiration
if (LOCAL_LOGV) {
- Log.v(TAG, "Expiring proximity alert: " + alert);
+ Slog.v(TAG, "Expiring proximity alert: " + alert);
}
if (intentsToRemove == null) {
intentsToRemove = new ArrayList<PendingIntent>();
@@ -1204,8 +1207,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Remove expired alerts
if (intentsToRemove != null) {
for (PendingIntent i : intentsToRemove) {
- ProximityAlert alert = mProximityAlerts.remove(i);
+ ProximityAlert alert = mProximityAlerts.get(i);
mProximitiesEntered.remove(alert);
+ removeProximityAlertLocked(i);
}
}
}
@@ -1248,15 +1252,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "addProximityAlert got exception:", e);
+ Slog.e(TAG, "addProximityAlert got exception:", e);
}
}
private void addProximityAlertLocked(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
if (LOCAL_LOGV) {
- Log.v(TAG, "addProximityAlert: latitude = " + latitude +
+ Slog.v(TAG, "addProximityAlert: latitude = " + latitude +
", longitude = " + longitude +
", expiration = " + expiration +
", intent = " + intent);
@@ -1280,7 +1286,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mProximityReceiver = new Receiver(mProximityListener);
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy provider = mProviders.get(i);
+ LocationProviderInterface provider = mProviders.get(i);
requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
}
}
@@ -1293,14 +1299,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "removeProximityAlert got exception:", e);
+ Slog.e(TAG, "removeProximityAlert got exception:", e);
}
}
private void removeProximityAlertLocked(PendingIntent intent) {
if (LOCAL_LOGV) {
- Log.v(TAG, "removeProximityAlert: intent = " + intent);
+ Slog.v(TAG, "removeProximityAlert: intent = " + intent);
}
mProximityAlerts.remove(intent);
@@ -1312,7 +1320,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
/**
- * @return null if the provider does not exits
+ * @return null if the provider does not exist
* @throws SecurityException if the provider is not allowed to be
* accessed by the caller
*/
@@ -1323,14 +1331,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "_getProviderInfo got exception:", e);
+ Slog.e(TAG, "_getProviderInfo got exception:", e);
return null;
}
}
private Bundle _getProviderInfoLocked(String provider) {
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
return null;
}
@@ -1358,13 +1368,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "isProviderEnabled got exception:", e);
+ Slog.e(TAG, "isProviderEnabled got exception:", e);
return false;
}
}
- public void reportLocation(Location location) {
+ public void reportLocation(Location location, boolean passive) {
if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
@@ -1372,13 +1384,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
+ m.arg1 = (passive ? 1 : 0);
mLocationHandler.sendMessageAtFrontOfQueue(m);
}
private boolean _isProviderEnabledLocked(String provider) {
checkPermissionsSafe(provider);
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -1392,8 +1405,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
} catch (SecurityException se) {
throw se;
+ } catch (IllegalArgumentException iae) {
+ throw iae;
} catch (Exception e) {
- Log.e(TAG, "getLastKnownLocation got exception:", e);
+ Slog.e(TAG, "getLastKnownLocation got exception:", e);
return null;
}
}
@@ -1401,7 +1416,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private Location _getLastKnownLocationLocked(String provider) {
checkPermissionsSafe(provider);
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
@@ -1436,14 +1451,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return true;
}
- private void handleLocationChangedLocked(Location location) {
- String provider = location.getProvider();
+ private void handleLocationChangedLocked(Location location, boolean passive) {
+ String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records == null || records.size() == 0) {
return;
}
- LocationProviderProxy p = mProvidersByName.get(provider);
+ LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
return;
}
@@ -1480,7 +1495,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
lastLoc.set(location);
}
if (!receiver.callLocationChangedLocked(location)) {
- Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
+ Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
if (deadReceivers == null) {
deadReceivers = new ArrayList<Receiver>();
}
@@ -1494,7 +1509,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
r.mLastStatusBroadcast = newStatusUpdateTime;
if (!receiver.callStatusChangedLocked(provider, status, extras)) {
- Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
+ Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
if (deadReceivers == null) {
deadReceivers = new ArrayList<Receiver>();
}
@@ -1523,23 +1538,26 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (mLock) {
Location location = (Location) msg.obj;
String provider = location.getProvider();
-
- // notify other providers of the new location
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy proxy = mProviders.get(i);
- if (!provider.equals(proxy.getName())) {
- proxy.updateLocation(location);
+ boolean passive = (msg.arg1 == 1);
+
+ if (!passive) {
+ // notify other providers of the new location
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ LocationProviderInterface p = mProviders.get(i);
+ if (!provider.equals(p.getName())) {
+ p.updateLocation(location);
+ }
}
}
if (isAllowedBySettingsLocked(provider)) {
- handleLocationChangedLocked(location);
+ handleLocationChangedLocked(location, passive);
}
}
}
} catch (Exception e) {
// Log, don't crash!
- Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
+ Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
}
}
}
@@ -1548,45 +1566,65 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
-
- if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
- || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
+ boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ if (queryRestart
+ || action.equals(Intent.ACTION_PACKAGE_REMOVED)
+ || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+ || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
synchronized (mLock) {
- 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);
+ int uidList[] = null;
+ if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+ uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ } else {
+ uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
+ }
+ if (uidList == null || uidList.length == 0) {
+ return;
+ }
+ for (int uid : uidList) {
+ 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 (queryRestart) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ 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);
+ ArrayList<ProximityAlert> removedAlerts = null;
+ for (ProximityAlert i : mProximityAlerts.values()) {
+ if (i.mUid == uid) {
+ if (queryRestart) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ if (removedAlerts == null) {
+ removedAlerts = new ArrayList<ProximityAlert>();
+ }
+ if (!removedAlerts.contains(i)) {
+ removedAlerts.add(i);
+ }
}
}
- }
- if (removedRecs != null) {
- for (int i=removedRecs.size()-1; i>=0; i--) {
- removeUpdatesLocked(removedRecs.get(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);
+ if (removedAlerts != null) {
+ for (int i=removedAlerts.size()-1; i>=0; i--) {
+ removeProximityAlertLocked(removedAlerts.get(i).mIntent);
+ }
}
}
}
@@ -1600,13 +1638,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
}
NetworkInfo info =
- (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+ (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
// Notify location providers of current network state
synchronized (mLock) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderProxy provider = mProviders.get(i);
- if (provider.requiresNetwork()) {
+ LocationProviderInterface provider = mProviders.get(i);
+ if (provider.isEnabled() && provider.requiresNetwork()) {
provider.updateNetworkState(mNetworkState, info);
}
}
@@ -1626,7 +1664,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} 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);
+ Slog.e(TAG, "exception in acquireWakeLock()", e);
}
}
}
@@ -1646,7 +1684,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} 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);
+ Slog.e(TAG, "exception in releaseWakeLock()", e);
}
}
}
@@ -1655,15 +1693,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Geocoder
public String getFromLocation(double latitude, double longitude, int maxResults,
- String language, String country, String variant, String appName, List<Address> addrs) {
+ GeocoderParams params, List<Address> addrs) {
if (mGeocodeProvider != null) {
- try {
- return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
- variant, appName, addrs);
- } catch (RemoteException e) {
- Log.e(TAG, "getFromLocation failed", e);
- mGeocodeProvider = null;
- }
+ return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
+ params, addrs);
}
return null;
}
@@ -1672,17 +1705,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
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) {
+ GeocoderParams params, List<Address> addrs) {
if (mGeocodeProvider != null) {
- try {
- return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, language, country, variant, appName, addrs);
- } catch (RemoteException e) {
- Log.e(TAG, "getFromLocationName failed", e);
- mGeocodeProvider = null;
- }
+ return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
}
return null;
}
@@ -1707,6 +1735,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
checkMockPermissionsSafe();
+ if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
+ throw new IllegalArgumentException("Cannot mock the passive location provider");
+ }
+
long identity = Binder.clearCallingIdentity();
synchronized (mLock) {
MockProvider provider = new MockProvider(name, this,
@@ -1716,16 +1748,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)) {
- LocationProviderProxy proxy = mProvidersByName.get(name);
- if (proxy != null) {
- proxy.enableLocationTracking(false);
- removeProvider(proxy);
+ LocationProviderInterface p = mProvidersByName.get(name);
+ if (p != null) {
+ p.enableLocationTracking(false);
+ removeProvider(p);
}
}
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
- addProvider(new LocationProviderProxy(name, provider));
+ addProvider(provider);
mMockProviders.put(name, provider);
mLastKnownLocation.put(name, null);
updateProvidersLocked();
@@ -1843,7 +1875,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private void log(String log) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, log);
+ Slog.d(TAG, log);
}
}
@@ -1924,6 +1956,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
i.getValue().dump(pw, " ");
}
}
+ for (LocationProviderInterface provider: mProviders) {
+ String state = provider.getInternalState();
+ if (state != null) {
+ pw.println(provider.getName() + " Internal State:");
+ pw.write(state);
+ }
+ }
}
}
}
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index 3c366da..27a8a74 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -16,38 +16,33 @@
package com.android.server;
+import android.content.BroadcastReceiver;
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.os.RecoverySystem;
import android.util.Log;
+import android.util.Slog;
-public class MasterClearReceiver extends BroadcastReceiver {
+import java.io.IOException;
+public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
- if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
- Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
+ if (!"google.com".equals(intent.getStringExtra("from"))) {
+ Slog.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()");
- }
+
+ try {
+ Slog.w(TAG, "!!! FACTORY RESET !!!");
+ RecoverySystem.rebootWipeUserData(context);
+ Log.wtf(TAG, "Still running after master clear?!");
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
}
diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java
deleted file mode 100644
index 3e53585..0000000
--- a/services/java/com/android/server/MountListener.java
+++ /dev/null
@@ -1,325 +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);
- mountMedia(Environment.getExternalStorageDirectory().getAbsolutePath());
-
- 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
index ddf7c56..6ceeb95 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -16,630 +16,1295 @@
package com.android.server;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
+import com.android.server.am.ActivityManagerService;
+
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.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.os.storage.IMountShutdownObserver;
+import android.os.storage.StorageResultCode;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Environment;
+import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UEventObserver;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileReader;
+import android.util.Slog;
+import java.util.ArrayList;
+import java.util.HashSet;
/**
- * MountService implements an to the mount service daemon
- * @hide
+ * MountService implements back-end services for platform storage
+ * management.
+ * @hide - Applications should use android.os.storage.StorageManager
+ * to access the MountService.
*/
-class MountService extends IMountService.Stub {
+class MountService extends IMountService.Stub
+ implements INativeDaemonConnectorCallbacks {
+ private static final boolean LOCAL_LOGD = false;
+ private static final boolean DEBUG_UNMOUNT = false;
+ private static final boolean DEBUG_EVENTS = false;
private static final String TAG = "MountService";
- /**
- * Binder context for this service
- */
- private Context mContext;
-
- /**
- * listener object for communicating with the mount service daemon
+ /*
+ * Internal vold volume state constants
*/
- private MountListener mListener;
+ class VolumeState {
+ public static final int Init = -1;
+ public static final int NoMedia = 0;
+ public static final int Idle = 1;
+ public static final int Pending = 2;
+ public static final int Checking = 3;
+ public static final int Mounted = 4;
+ public static final int Unmounting = 5;
+ public static final int Formatting = 6;
+ public static final int Shared = 7;
+ public static final int SharedMnt = 8;
+ }
- /**
- * The notification that is shown when a USB mass storage host
- * is connected.
- * <p>
- * This is lazily created, so use {@link #setUsbStorageNotification()}.
+ /*
+ * Internal vold response code constants
*/
- private Notification mUsbStorageNotification;
+ class VoldResponseCode {
+ /*
+ * 100 series - Requestion action was initiated; expect another reply
+ * before proceeding with a new command.
+ */
+ public static final int VolumeListResult = 110;
+ public static final int AsecListResult = 111;
+ public static final int StorageUsersListResult = 112;
+
+ /*
+ * 200 series - Requestion action has been successfully completed.
+ */
+ public static final int ShareStatusResult = 210;
+ public static final int AsecPathResult = 211;
+ public static final int ShareEnabledResult = 212;
+
+ /*
+ * 400 series - Command was accepted, but the requested action
+ * did not take place.
+ */
+ public static final int OpFailedNoMedia = 401;
+ public static final int OpFailedMediaBlank = 402;
+ public static final int OpFailedMediaCorrupt = 403;
+ public static final int OpFailedVolNotMounted = 404;
+ public static final int OpFailedStorageBusy = 405;
+ public static final int OpFailedStorageNotFound = 406;
+
+ /*
+ * 600 series - Unsolicited broadcasts.
+ */
+ public static final int VolumeStateChange = 605;
+ public static final int ShareAvailabilityChange = 620;
+ public static final int VolumeDiskInserted = 630;
+ public static final int VolumeDiskRemoved = 631;
+ public static final int VolumeBadRemoval = 632;
+ }
+ private Context mContext;
+ private NativeDaemonConnector mConnector;
+ private String mLegacyState = Environment.MEDIA_REMOVED;
+ private PackageManagerService mPms;
+ private boolean mUmsEnabling;
+ // Used as a lock for methods that register/unregister listeners.
+ final private ArrayList<MountServiceBinderListener> mListeners =
+ new ArrayList<MountServiceBinderListener>();
+ private boolean mBooted = false;
+ private boolean mReady = false;
+ private boolean mSendUmsConnectedOnBoot = false;
/**
- * 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 hash of currently mounted secure containers.
+ * Used as a lock in methods to manipulate secure containers.
*/
- private Notification mMediaStorageNotification;
-
- private boolean mShowSafeUnmountNotificationWhenUnmounted;
+ final private HashSet<String> mAsecMountSet = new HashSet<String>();
+
+ private static final int H_UNMOUNT_PM_UPDATE = 1;
+ private static final int H_UNMOUNT_PM_DONE = 2;
+ private static final int H_UNMOUNT_MS = 3;
+ private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
+ private static final int MAX_UNMOUNT_RETRIES = 4;
+
+ class UnmountCallBack {
+ String path;
+ int retries;
+ boolean force;
+
+ UnmountCallBack(String path, boolean force) {
+ retries = 0;
+ this.path = path;
+ this.force = force;
+ }
- private boolean mPlaySounds;
+ void handleFinished() {
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
+ doUnmountVolume(path, true);
+ }
+ }
- private boolean mMounted;
+ class UmsEnableCallBack extends UnmountCallBack {
+ String method;
- private boolean mAutoStartUms;
+ UmsEnableCallBack(String path, String method, boolean force) {
+ super(path, force);
+ this.method = method;
+ }
- /**
- * Constructs a new MountService instance
- *
- * @param context Binder context for this service
- */
- public MountService(Context context) {
- mContext = context;
+ @Override
+ void handleFinished() {
+ super.handleFinished();
+ doShareUnshareVolume(path, method, true);
+ }
+ }
- // 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);
+ class ShutdownCallBack extends UnmountCallBack {
+ IMountShutdownObserver observer;
+ ShutdownCallBack(String path, IMountShutdownObserver observer) {
+ super(path, true);
+ this.observer = observer;
+ }
- mListener = new MountListener(this);
- mShowSafeUnmountNotificationWhenUnmounted = false;
+ @Override
+ void handleFinished() {
+ int ret = doUnmountVolume(path, true);
+ if (observer != null) {
+ try {
+ observer.onShutDownComplete(ret);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException when shutting down");
+ }
+ }
+ }
+ }
- mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
+ class MountServiceHandler extends Handler {
+ ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
+ boolean mUpdatingStatus = false;
- mAutoStartUms = SystemProperties.get("persist.service.mount.umsauto", "0").equals("1");
- }
+ MountServiceHandler(Looper l) {
+ super(l);
+ }
- BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case H_UNMOUNT_PM_UPDATE: {
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
+ UnmountCallBack ucb = (UnmountCallBack) msg.obj;
+ mForceUnmounts.add(ucb);
+ if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
+ // Register only if needed.
+ if (!mUpdatingStatus) {
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
+ mUpdatingStatus = true;
+ mPms.updateExternalMediaStatus(false, true);
+ }
+ break;
+ }
+ case H_UNMOUNT_PM_DONE: {
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
+ mUpdatingStatus = false;
+ int size = mForceUnmounts.size();
+ int sizeArr[] = new int[size];
+ int sizeArrN = 0;
+ // Kill processes holding references first
+ ActivityManagerService ams = (ActivityManagerService)
+ ServiceManager.getService("activity");
+ for (int i = 0; i < size; i++) {
+ UnmountCallBack ucb = mForceUnmounts.get(i);
+ String path = ucb.path;
+ boolean done = false;
+ if (!ucb.force) {
+ done = true;
+ } else {
+ int pids[] = getStorageUsers(path);
+ if (pids == null || pids.length == 0) {
+ done = true;
+ } else {
+ // Eliminate system process here?
+ ams.killPids(pids, "unmount media");
+ // Confirm if file references have been freed.
+ pids = getStorageUsers(path);
+ if (pids == null || pids.length == 0) {
+ done = true;
+ }
+ }
+ }
+ if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
+ // Retry again
+ Slog.i(TAG, "Retrying to kill storage users again");
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
+ ucb.retries++),
+ RETRY_UNMOUNT_DELAY);
+ } else {
+ if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
+ Slog.i(TAG, "Failed to unmount media inspite of " +
+ MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
+ }
+ sizeArr[sizeArrN++] = i;
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
+ ucb));
+ }
+ }
+ // Remove already processed elements from list.
+ for (int i = (sizeArrN-1); i >= 0; i--) {
+ mForceUnmounts.remove(sizeArr[i]);
+ }
+ break;
+ }
+ case H_UNMOUNT_MS : {
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
+ UnmountCallBack ucb = (UnmountCallBack) msg.obj;
+ ucb.handleFinished();
+ break;
+ }
+ }
+ }
+ };
+ final private HandlerThread mHandlerThread;
+ final private Handler mHandler;
+
+ private void waitForReady() {
+ while (mReady == false) {
+ for (int retries = 5; retries > 0; retries--) {
+ if (mReady) {
+ return;
+ }
+ SystemClock.sleep(1000);
+ }
+ Slog.w(TAG, "Waiting too long for mReady!");
+ }
+ }
+
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- Thread thread = new Thread(mListener, MountListener.class.getName());
- thread.start();
+ mBooted = true;
+
+ /*
+ * In the simulator, we need to broadcast a volume mounted event
+ * to make the media scanner run.
+ */
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
+ return;
+ }
+ new Thread() {
+ public void run() {
+ try {
+ String path = Environment.getExternalStorageDirectory().getPath();
+ String state = getVolumeState(path);
+
+ if (state.equals(Environment.MEDIA_UNMOUNTED)) {
+ int rc = doMountVolume(path);
+ if (rc != StorageResultCode.OperationSucceeded) {
+ Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc));
+ }
+ } else if (state.equals(Environment.MEDIA_SHARED)) {
+ /*
+ * Bootstrap UMS enabled state since vold indicates
+ * the volume is shared (runtime restart while ums enabled)
+ */
+ notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
+ }
+
+ /*
+ * If UMS was connected on boot, send the connected event
+ * now that we're up.
+ */
+ if (mSendUmsConnectedOnBoot) {
+ sendUmsIntent(true);
+ mSendUmsConnectedOnBoot = false;
+ }
+ } catch (Exception ex) {
+ Slog.e(TAG, "Boot-time mount exception", ex);
+ }
+ }
+ }.start();
}
}
};
- public void shutdown() {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.SHUTDOWN)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires SHUTDOWN permission");
+ private final class MountServiceBinderListener implements IBinder.DeathRecipient {
+ final IMountServiceListener mListener;
+
+ MountServiceBinderListener(IMountServiceListener listener) {
+ mListener = listener;
+
}
- Log.d(TAG, "Shutting down");
- String state = Environment.getExternalStorageState();
+ public void binderDied() {
+ if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
+ synchronized(mListeners) {
+ mListeners.remove(this);
+ mListener.asBinder().unlinkToDeath(this, 0);
+ }
+ }
+ }
- if (state.equals(Environment.MEDIA_SHARED)) {
- /*
- * If the media is currently shared, unshare it.
- * XXX: This is still dangerous!. We should not
- * be rebooting at *all* if UMS is enabled, since
- * the UMS host could have dirty FAT cache entries
- * yet to flush.
- */
- try {
- setMassStorageEnabled(false);
- } catch (Exception e) {
- Log.e(TAG, "ums disable failed", e);
+ private void doShareUnshareVolume(String path, String method, boolean enable) {
+ // TODO: Add support for multiple share methods
+ if (!method.equals("ums")) {
+ throw new IllegalArgumentException(String.format("Method %s not supported", method));
+ }
+
+ try {
+ mConnector.doCommand(String.format(
+ "volume %sshare %s %s", (enable ? "" : "un"), path, method));
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to share/unshare", e);
+ }
+ }
+
+ private void updatePublicVolumeState(String path, String state) {
+ if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
+ Slog.w(TAG, "Multiple volumes not currently supported");
+ return;
+ }
+
+ if (mLegacyState.equals(state)) {
+ Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
+ return;
+ }
+ // Update state on PackageManager
+ if (Environment.MEDIA_UNMOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(false, false);
+ } else if (Environment.MEDIA_MOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(true, false);
+ }
+ String oldState = mLegacyState;
+ mLegacyState = state;
+
+ synchronized (mListeners) {
+ for (int i = mListeners.size() -1; i >= 0; i--) {
+ MountServiceBinderListener bl = mListeners.get(i);
+ try {
+ bl.mListener.onStorageStateChanged(path, oldState, state);
+ } catch (RemoteException rex) {
+ Slog.e(TAG, "Listener dead");
+ mListeners.remove(i);
+ } catch (Exception ex) {
+ Slog.e(TAG, "Listener failed", ex);
+ }
}
- } else if (state.equals(Environment.MEDIA_CHECKING)) {
- /*
- * If the media is being checked, then we need to wait for
- * it to complete before being able to proceed.
- */
- // XXX: @hackbod - Should we disable the ANR timer here?
- int retries = 30;
- while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
+ }
+ }
+
+ /**
+ *
+ * Callback from NativeDaemonConnector
+ */
+ public void onDaemonConnected() {
+ /*
+ * Since we'll be calling back into the NativeDaemonConnector,
+ * we need to do our work in a new thread.
+ */
+ new Thread() {
+ public void run() {
+ /**
+ * Determine media state and UMS detection status
+ */
+ String path = Environment.getExternalStorageDirectory().getPath();
+ String state = Environment.MEDIA_REMOVED;
+
try {
- Thread.sleep(1000);
- } catch (InterruptedException iex) {
- Log.e(TAG, "Interrupted while waiting for media", iex);
- break;
+ String[] vols = mConnector.doListCommand(
+ "volume list", VoldResponseCode.VolumeListResult);
+ for (String volstr : vols) {
+ String[] tok = volstr.split(" ");
+ // FMT: <label> <mountpoint> <state>
+ if (!tok[1].equals(path)) {
+ Slog.w(TAG, String.format(
+ "Skipping unknown volume '%s'",tok[1]));
+ continue;
+ }
+ int st = Integer.parseInt(tok[2]);
+ if (st == VolumeState.NoMedia) {
+ state = Environment.MEDIA_REMOVED;
+ } else if (st == VolumeState.Idle) {
+ state = Environment.MEDIA_UNMOUNTED;
+ } else if (st == VolumeState.Mounted) {
+ state = Environment.MEDIA_MOUNTED;
+ Slog.i(TAG, "Media already mounted on daemon connection");
+ } else if (st == VolumeState.Shared) {
+ state = Environment.MEDIA_SHARED;
+ Slog.i(TAG, "Media shared on daemon connection");
+ } else {
+ throw new Exception(String.format("Unexpected state %d", st));
+ }
+ }
+ if (state != null) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
+ updatePublicVolumeState(path, state);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Error processing initial volume state", e);
+ updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
}
- state = Environment.getExternalStorageState();
+
+ try {
+ boolean avail = doGetShareMethodAvailable("ums");
+ notifyShareAvailabilityChange("ums", avail);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Failed to get share availability");
+ }
+ /*
+ * Now that we've done our initialization, release
+ * the hounds!
+ */
+ mReady = true;
}
- if (retries == 0) {
- Log.e(TAG, "Timed out waiting for media to check");
+ }.start();
+ }
+
+ /**
+ * Callback from NativeDaemonConnector
+ */
+ public boolean onEvent(int code, String raw, String[] cooked) {
+ Intent in = null;
+
+ if (DEBUG_EVENTS) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("onEvent::");
+ builder.append(" raw= " + raw);
+ if (cooked != null) {
+ builder.append(" cooked = " );
+ for (String str : cooked) {
+ builder.append(" " + str);
+ }
}
+ Slog.i(TAG, builder.toString());
}
-
- if (state.equals(Environment.MEDIA_MOUNTED)) {
+ if (code == VoldResponseCode.VolumeStateChange) {
/*
- * If the media is mounted, then gracefully unmount it.
+ * One of the volumes we're managing has changed state.
+ * Format: "NNN Volume <label> <path> state changed
+ * from <old_#> (<old_str>) to <new_#> (<new_str>)"
*/
+ notifyVolumeStateChange(
+ cooked[2], cooked[3], Integer.parseInt(cooked[7]),
+ Integer.parseInt(cooked[10]));
+ } else if (code == VoldResponseCode.ShareAvailabilityChange) {
+ // FMT: NNN Share method <method> now <available|unavailable>
+ boolean avail = false;
+ if (cooked[5].equals("available")) {
+ avail = true;
+ }
+ notifyShareAvailabilityChange(cooked[3], avail);
+ } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
+ (code == VoldResponseCode.VolumeDiskRemoved) ||
+ (code == VoldResponseCode.VolumeBadRemoval)) {
+ // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
+ // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
+ // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
+ final String label = cooked[2];
+ final String path = cooked[3];
+ int major = -1;
+ int minor = -1;
+
try {
- String m = Environment.getExternalStorageDirectory().toString();
- unmountMedia(m);
+ String devComp = cooked[6].substring(1, cooked[6].length() -1);
+ String[] devTok = devComp.split(":");
+ major = Integer.parseInt(devTok[0]);
+ minor = Integer.parseInt(devTok[1]);
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to parse major/minor", ex);
+ }
- int retries = 12;
- while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException iex) {
- Log.e(TAG, "Interrupted while waiting for media", iex);
- break;
+ if (code == VoldResponseCode.VolumeDiskInserted) {
+ new Thread() {
+ public void run() {
+ try {
+ int rc;
+ if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
+ Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
+ }
+ } catch (Exception ex) {
+ Slog.w(TAG, "Failed to mount media on insertion", ex);
+ }
}
- state = Environment.getExternalStorageState();
+ }.start();
+ } else if (code == VoldResponseCode.VolumeDiskRemoved) {
+ /*
+ * This event gets trumped if we're already in BAD_REMOVAL state
+ */
+ if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
+ return true;
}
- if (retries == 0) {
- Log.e(TAG, "Timed out waiting for media to unmount");
- }
- } catch (Exception e) {
- Log.e(TAG, "external storage unmount failed", e);
+ /* Send the media unmounted event first */
+ if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
+ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+ in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+ mContext.sendBroadcast(in);
+
+ if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
+ updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
+ in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
+ } else if (code == VoldResponseCode.VolumeBadRemoval) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
+ /* Send the media unmounted event first */
+ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+ in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+ mContext.sendBroadcast(in);
+
+ if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
+ updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
+ in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
+ } else {
+ Slog.e(TAG, String.format("Unknown code {%d}", code));
}
+ } else {
+ return false;
+ }
+
+ if (in != null) {
+ mContext.sendBroadcast(in);
}
+ return true;
}
- /**
- * @return true if USB mass storage support is enabled.
- */
- public boolean getMassStorageEnabled() throws RemoteException {
- return mListener.getMassStorageEnabled();
+ private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
+ String vs = getVolumeState(path);
+ if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs);
+
+ Intent in = null;
+
+ if (oldState == VolumeState.Shared && newState != oldState) {
+ if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED,
+ Uri.parse("file://" + path)));
+ }
+
+ if (newState == VolumeState.Init) {
+ } else if (newState == VolumeState.NoMedia) {
+ // NoMedia is handled via Disk Remove events
+ } else if (newState == VolumeState.Idle) {
+ /*
+ * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
+ * if we're in the process of enabling UMS
+ */
+ if (!vs.equals(
+ Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
+ Environment.MEDIA_NOFS) && !vs.equals(
+ Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
+ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+ in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+ }
+ } else if (newState == VolumeState.Pending) {
+ } else if (newState == VolumeState.Checking) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
+ updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
+ in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
+ } else if (newState == VolumeState.Mounted) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
+ updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
+ in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
+ in.putExtra("read-only", false);
+ } else if (newState == VolumeState.Unmounting) {
+ in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
+ } else if (newState == VolumeState.Formatting) {
+ } else if (newState == VolumeState.Shared) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
+ /* Send the media unmounted event first */
+ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+ in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+ mContext.sendBroadcast(in);
+
+ if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
+ updatePublicVolumeState(path, Environment.MEDIA_SHARED);
+ in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
+ if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
+ } else if (newState == VolumeState.SharedMnt) {
+ Slog.e(TAG, "Live shared mounts not supported yet!");
+ return;
+ } else {
+ Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
+ }
+
+ if (in != null) {
+ mContext.sendBroadcast(in);
+ }
}
- /**
- * 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);
+ private boolean doGetShareMethodAvailable(String method) {
+ ArrayList<String> rsp = mConnector.doCommand("share status " + method);
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code;
+ try {
+ code = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
+ return false;
+ }
+ if (code == VoldResponseCode.ShareStatusResult) {
+ if (tok[2].equals("available"))
+ return true;
+ return false;
+ } else {
+ Slog.e(TAG, String.format("Unexpected response code %d", code));
+ return false;
+ }
+ }
+ Slog.e(TAG, "Got an empty response");
+ return false;
}
- /**
- * @return true if USB mass storage is connected.
- */
- public boolean getMassStorageConnected() throws RemoteException {
- return mListener.getMassStorageConnected();
+ private int doMountVolume(String path) {
+ int rc = StorageResultCode.OperationSucceeded;
+
+ if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
+ try {
+ mConnector.doCommand(String.format("volume mount %s", path));
+ } catch (NativeDaemonConnectorException e) {
+ /*
+ * Mount failed for some reason
+ */
+ Intent in = null;
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedNoMedia) {
+ /*
+ * Attempt to mount but no media inserted
+ */
+ rc = StorageResultCode.OperationFailedNoMedia;
+ } else if (code == VoldResponseCode.OpFailedMediaBlank) {
+ if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
+ /*
+ * Media is blank or does not contain a supported filesystem
+ */
+ updatePublicVolumeState(path, Environment.MEDIA_NOFS);
+ in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
+ rc = StorageResultCode.OperationFailedMediaBlank;
+ } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+ if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
+ /*
+ * Volume consistency check failed
+ */
+ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
+ in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
+ rc = StorageResultCode.OperationFailedMediaCorrupt;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
+
+ /*
+ * Send broadcast intent (if required for the failure)
+ */
+ if (in != null) {
+ mContext.sendBroadcast(in);
+ }
+ }
+
+ return rc;
}
-
- /**
- * Attempt to mount external media
+
+ /*
+ * If force is not set, we do not unmount if there are
+ * processes holding references to the volume about to be unmounted.
+ * If force is set, all the processes holding references need to be
+ * killed via the ActivityManager before actually unmounting the volume.
+ * This might even take a while and might be retried after timed delays
+ * to make sure we dont end up in an instable state and kill some core
+ * processes.
*/
- 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");
+ private int doUnmountVolume(String path, boolean force) {
+ if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
+ return VoldResponseCode.OpFailedVolNotMounted;
+ }
+ // Redundant probably. But no harm in updating state again.
+ mPms.updateExternalMediaStatus(false, false);
+ try {
+ mConnector.doCommand(String.format(
+ "volume unmount %s%s", path, (force ? " force" : "")));
+ // We unmounted the volume. None of the asec containers are available now.
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.clear();
+ }
+ return StorageResultCode.OperationSucceeded;
+ } catch (NativeDaemonConnectorException e) {
+ // Don't worry about mismatch in PackageManager since the
+ // call back will handle the status changes any way.
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedVolNotMounted) {
+ return StorageResultCode.OperationFailedStorageNotMounted;
+ } else if (code == VoldResponseCode.OpFailedStorageBusy) {
+ return StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ return StorageResultCode.OperationFailedInternalError;
+ }
}
- 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");
+ private int doFormatVolume(String path) {
+ try {
+ String cmd = String.format("volume format %s", path);
+ mConnector.doCommand(cmd);
+ return StorageResultCode.OperationSucceeded;
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedNoMedia) {
+ return StorageResultCode.OperationFailedNoMedia;
+ } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+ return StorageResultCode.OperationFailedMediaCorrupt;
+ } else {
+ return StorageResultCode.OperationFailedInternalError;
+ }
}
+ }
- // Set a flag so that when we get the unmounted event, we know
- // to display the notification
- mShowSafeUnmountNotificationWhenUnmounted = true;
+ private boolean doGetVolumeShared(String path, String method) {
+ String cmd = String.format("volume shared %s %s", path, method);
+ ArrayList<String> rsp = mConnector.doCommand(cmd);
- // tell mountd to unmount the media
- mListener.ejectMedia(mountPath);
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code;
+ try {
+ code = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
+ return false;
+ }
+ if (code == VoldResponseCode.ShareEnabledResult) {
+ if (tok[2].equals("enabled"))
+ return true;
+ return false;
+ } else {
+ Slog.e(TAG, String.format("Unexpected response code %d", code));
+ return false;
+ }
+ }
+ Slog.e(TAG, "Got an empty response");
+ return false;
}
- /**
- * 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");
+ private void notifyShareAvailabilityChange(String method, final boolean avail) {
+ if (!method.equals("ums")) {
+ Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
+ return;
+ }
+
+ synchronized (mListeners) {
+ for (int i = mListeners.size() -1; i >= 0; i--) {
+ MountServiceBinderListener bl = mListeners.get(i);
+ try {
+ bl.mListener.onUsbMassStorageConnectionChanged(avail);
+ } catch (RemoteException rex) {
+ Slog.e(TAG, "Listener dead");
+ mListeners.remove(i);
+ } catch (Exception ex) {
+ Slog.e(TAG, "Listener failed", ex);
+ }
+ }
+ }
+
+ if (mBooted == true) {
+ sendUmsIntent(avail);
+ } else {
+ mSendUmsConnectedOnBoot = avail;
}
- mListener.formatMedia(formatPath);
+ final String path = Environment.getExternalStorageDirectory().getPath();
+ if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
+ /*
+ * USB mass storage disconnected while enabled
+ */
+ new Thread() {
+ public void run() {
+ try {
+ int rc;
+ Slog.w(TAG, "Disabling UMS after cable disconnect");
+ doShareUnshareVolume(path, "ums", false);
+ if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
+ Slog.e(TAG, String.format(
+ "Failed to remount {%s} on UMS enabled-disconnect (%d)",
+ path, rc));
+ }
+ } catch (Exception ex) {
+ Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
+ }
+ }
+ }.start();
+ }
}
- /**
- * Returns true if we're playing media notification sounds.
- */
- public boolean getPlayNotificationSounds() {
- return mPlaySounds;
+ private void sendUmsIntent(boolean c) {
+ mContext.sendBroadcast(
+ new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
}
- /**
- * 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");
+ private void validatePermission(String perm) {
+ if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(String.format("Requires %s permission", perm));
}
- mPlaySounds = enabled;
- SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
}
/**
- * Returns true if we auto-start UMS on cable insertion.
+ * Constructs a new MountService instance
+ *
+ * @param context Binder context for this service
*/
- public boolean getAutoStartUms() {
- return mAutoStartUms;
- }
+ public MountService(Context context) {
+ mContext = context;
- /**
- * Set whether or not we're playing media notification sounds.
- */
- public void setAutoStartUms(boolean enabled) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires WRITE_SETTINGS permission");
+ // XXX: This will go away soon in favor of IMountServiceObserver
+ mPms = (PackageManagerService) ServiceManager.getService("package");
+
+ mContext.registerReceiver(mBroadcastReceiver,
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
+ mHandlerThread = new HandlerThread("MountService");
+ mHandlerThread.start();
+ mHandler = new MountServiceHandler(mHandlerThread.getLooper());
+
+ /*
+ * Vold does not run in the simulator, so pretend the connector thread
+ * ran and did its thing.
+ */
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ mReady = true;
+ mUmsEnabling = true;
+ return;
}
- mAutoStartUms = enabled;
- SystemProperties.set("persist.service.mount.umsauto", (enabled ? "1" : "0"));
+
+ mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
+ mReady = false;
+ Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+ thread.start();
}
/**
- * Update the state of the USB mass storage notification
+ * Exposed API calls below here
*/
- void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
-
- try {
- if (getMassStorageConnected() && !suppressIfConnected) {
- Intent intent = new Intent();
- intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- 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);
+ public void registerListener(IMountServiceListener listener) {
+ synchronized (mListeners) {
+ MountServiceBinderListener bl = new MountServiceBinderListener(listener);
+ try {
+ listener.asBinder().linkToDeath(bl, 0);
+ mListeners.add(bl);
+ } catch (RemoteException rex) {
+ Slog.e(TAG, "Failed to link to listener death");
}
- } 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);
+ public void unregisterListener(IMountServiceListener listener) {
+ synchronized (mListeners) {
+ for(MountServiceBinderListener bl : mListeners) {
+ if (bl.mListener == listener) {
+ mListeners.remove(mListeners.indexOf(bl));
+ return;
+ }
+ }
}
}
- /**
- * 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)) {
+ public void shutdown(final IMountShutdownObserver observer) {
+ validatePermission(android.Manifest.permission.SHUTDOWN);
+
+ Slog.i(TAG, "Shutting down");
+
+ String path = Environment.getExternalStorageDirectory().getPath();
+ String state = getVolumeState(path);
- if (mAutoStartUms) {
+ if (state.equals(Environment.MEDIA_SHARED)) {
+ /*
+ * If the media is currently shared, unshare it.
+ * XXX: This is still dangerous!. We should not
+ * be rebooting at *all* if UMS is enabled, since
+ * the UMS host could have dirty FAT cache entries
+ * yet to flush.
+ */
+ setUsbMassStorageEnabled(false);
+ } else if (state.equals(Environment.MEDIA_CHECKING)) {
+ /*
+ * If the media is being checked, then we need to wait for
+ * it to complete before being able to proceed.
+ */
+ // XXX: @hackbod - Should we disable the ANR timer here?
+ int retries = 30;
+ while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
try {
- setMassStorageEnabled(true);
- } catch (RemoteException e) {
+ Thread.sleep(1000);
+ } catch (InterruptedException iex) {
+ Slog.e(TAG, "Interrupted while waiting for media", iex);
+ break;
}
- } else {
- updateUsbMassStorageNotification(false, true);
+ state = Environment.getExternalStorageState();
+ }
+ if (retries == 0) {
+ Slog.e(TAG, "Timed out waiting for media to check");
}
}
- Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
- mContext.sendBroadcast(intent);
+ if (state.equals(Environment.MEDIA_MOUNTED)) {
+ // Post a unmount message.
+ ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
+ }
}
- /**
- * 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);
+ private boolean getUmsEnabling() {
+ synchronized (mListeners) {
+ return mUmsEnabling;
+ }
}
- /**
- * Broadcasts the media removed event to all clients.
- */
- void notifyMediaRemoved(String path) {
- updateUsbMassStorageNotification(true, false);
+ private void setUmsEnabling(boolean enable) {
+ synchronized (mListeners) {
+ mUmsEnabling = true;
+ }
+ }
- 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_notify_sdcard_usb,
- true, false, null);
- handlePossibleExplicitUnmountBroadcast(path);
+ public boolean isUsbMassStorageConnected() {
+ waitForReady();
+
+ if (getUmsEnabling()) {
+ return true;
+ }
+ return doGetShareMethodAvailable("ums");
+ }
- Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ public void setUsbMassStorageEnabled(boolean enable) {
+ waitForReady();
+ validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+
+ // TODO: Add support for multiple share methods
+
+ /*
+ * If the volume is mounted and we're enabling then unmount it
+ */
+ String path = Environment.getExternalStorageDirectory().getPath();
+ String vs = getVolumeState(path);
+ String method = "ums";
+ if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
+ // Override for isUsbMassStorageEnabled()
+ setUmsEnabling(enable);
+ UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
+ // Clear override
+ setUmsEnabling(false);
+ }
+ /*
+ * If we disabled UMS then mount the volume
+ */
+ if (!enable) {
+ doShareUnshareVolume(path, method, enable);
+ if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
+ Slog.e(TAG, "Failed to remount " + path +
+ " after disabling share method " + method);
+ /*
+ * Even though the mount failed, the unshare didn't so don't indicate an error.
+ * The mountVolume() call will have set the storage state and sent the necessary
+ * broadcasts.
+ */
+ }
+ }
}
+ public boolean isUsbMassStorageEnabled() {
+ waitForReady();
+ return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
+ }
+
/**
- * Broadcasts the media unmounted event to all clients.
+ * @return state of the volume at the specified mount point
*/
- 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_sdcard,
- true, true, null);
- mShowSafeUnmountNotificationWhenUnmounted = false;
- } else {
- setMediaStorageNotification(0, 0, 0, false, false, null);
+ public String getVolumeState(String mountPoint) {
+ /*
+ * XXX: Until we have multiple volume discovery, just hardwire
+ * this to /sdcard
+ */
+ if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
+ Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
+ throw new IllegalArgumentException();
}
- updateUsbMassStorageNotification(false, false);
- Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ return mLegacyState;
}
- /**
- * 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_sdcard_prepare,
- true, false, null);
+ public int mountVolume(String path) {
+ validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- updateUsbMassStorageNotification(true, false);
- Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ waitForReady();
+ return doMountVolume(path);
}
- /**
- * 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_notify_sdcard_usb,
- true, false, pi);
- updateUsbMassStorageNotification(false, false);
- intent = new Intent(Intent.ACTION_MEDIA_NOFS,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ public void unmountVolume(String path, boolean force) {
+ validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
+ String volState = getVolumeState(path);
+ if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force);
+ if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
+ Environment.MEDIA_REMOVED.equals(volState) ||
+ Environment.MEDIA_SHARED.equals(volState) ||
+ Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
+ // Media already unmounted or cannot be unmounted.
+ // TODO return valid return code when adding observer call back.
+ return;
+ }
+ UnmountCallBack ucb = new UnmountCallBack(path, force);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
}
- /**
- * 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);
+ public int formatVolume(String path) {
+ validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+ waitForReady();
+
+ return doFormatVolume(path);
}
- /**
- * 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);
+ public int []getStorageUsers(String path) {
+ validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+ try {
+ String[] r = mConnector.doListCommand(
+ String.format("storage users %s", path),
+ VoldResponseCode.StorageUsersListResult);
+ // FMT: <pid> <process name>
+ int[] data = new int[r.length];
+ for (int i = 0; i < r.length; i++) {
+ String []tok = r[i].split(" ");
+ try {
+ data[i] = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
+ return new int[0];
+ }
+ }
+ return data;
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to retrieve storage users list", e);
+ return new int[0];
+ }
}
- /**
- * 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);
+ private void warnOnNotMounted() {
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
+ }
+ }
- handlePossibleExplicitUnmountBroadcast(path);
- Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ public String[] getSecureContainerList() {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
- intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
- Uri.parse("file://" + path));
- mContext.sendBroadcast(intent);
+ try {
+ return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
+ } catch (NativeDaemonConnectorException e) {
+ return new String[0];
+ }
}
- /**
- * 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_notify_sdcard_usb,
- true, false, pi);
- updateUsbMassStorageNotification(false, false);
+ public int createSecureContainer(String id, int sizeMb, String fstype,
+ String key, int ownerUid) {
+ validatePermission(android.Manifest.permission.ASEC_CREATE);
+ waitForReady();
+ warnOnNotMounted();
- handlePossibleExplicitUnmountBroadcast(path);
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
- 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);
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.add(id);
+ }
+ }
+ return rc;
}
-
- /**
- * 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;
+ public int finalizeSecureContainer(String id) {
+ validatePermission(android.Manifest.permission.ASEC_CREATE);
+ warnOnNotMounted();
+
+ int rc = StorageResultCode.OperationSucceeded;
+ try {
+ mConnector.doCommand(String.format("asec finalize %s", id));
+ /*
+ * Finalization does a remount, so no need
+ * to update mAsecMountSet
+ */
+ } catch (NativeDaemonConnectorException e) {
+ rc = StorageResultCode.OperationFailedInternalError;
}
+ return rc;
+ }
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
+ public int destroySecureContainer(String id, boolean force) {
+ validatePermission(android.Manifest.permission.ASEC_DESTROY);
+ waitForReady();
+ warnOnNotMounted();
- if (notificationManager == null) {
- return;
+ int rc = StorageResultCode.OperationSucceeded;
+ try {
+ mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
}
-
- 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 (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ if (mAsecMountSet.contains(id)) {
+ mAsecMountSet.remove(id);
+ }
}
+ }
- if (sound && mPlaySounds) {
- mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
- } else {
- mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ return rc;
+ }
+
+ public int mountSecureContainer(String id, String key, int ownerUid) {
+ validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+ waitForReady();
+ warnOnNotMounted();
+
+ synchronized (mAsecMountSet) {
+ if (mAsecMountSet.contains(id)) {
+ return StorageResultCode.OperationFailedStorageMounted;
}
-
- mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ }
- mUsbStorageNotification.tickerText = title;
- if (pi == null) {
- Intent intent = new Intent();
- pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code != VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedInternalError;
}
-
- mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
}
-
- final int notificationId = mUsbStorageNotification.icon;
- if (visible) {
- notificationManager.notify(notificationId, mUsbStorageNotification);
- } else {
- notificationManager.cancel(notificationId);
+
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.add(id);
+ }
}
+ return rc;
}
- private synchronized boolean getMediaStorageNotificationDismissable() {
- if ((mMediaStorageNotification != null) &&
- ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
- Notification.FLAG_AUTO_CANCEL))
- return true;
+ public int unmountSecureContainer(String id, boolean force) {
+ validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+ waitForReady();
+ warnOnNotMounted();
- return false;
- }
+ synchronized (mAsecMountSet) {
+ if (!mAsecMountSet.contains(id)) {
+ return StorageResultCode.OperationFailedStorageNotMounted;
+ }
+ }
- /**
- * Sets the media storage notification.
- */
- private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
- boolean dismissable, PendingIntent pi) {
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageBusy) {
+ rc = StorageResultCode.OperationFailedStorageBusy;
+ } else {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
+ }
- if (!visible && mMediaStorageNotification == null) {
- return;
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.remove(id);
+ }
}
+ return rc;
+ }
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
+ public boolean isSecureContainerMounted(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
- if (notificationManager == null) {
- return;
+ synchronized (mAsecMountSet) {
+ return mAsecMountSet.contains(id);
}
+ }
- if (mMediaStorageNotification != null && visible) {
+ public int renameSecureContainer(String oldId, String newId) {
+ validatePermission(android.Manifest.permission.ASEC_RENAME);
+ waitForReady();
+ warnOnNotMounted();
+
+ synchronized (mAsecMountSet) {
/*
- * Dismiss the previous notification - we're about to
- * re-use it.
+ * Because a mounted container has active internal state which cannot be
+ * changed while active, we must ensure both ids are not currently mounted.
*/
- final int notificationId = mMediaStorageNotification.icon;
- notificationManager.cancel(notificationId);
+ if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
+ return StorageResultCode.OperationFailedStorageMounted;
+ }
}
-
- 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;
- }
+ int rc = StorageResultCode.OperationSucceeded;
+ String cmd = String.format("asec rename %s %s", oldId, newId);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ rc = StorageResultCode.OperationFailedInternalError;
+ }
- if (mPlaySounds) {
- mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
- } else {
- mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
- }
+ return rc;
+ }
- if (dismissable) {
- mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
- } else {
- mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
- }
+ public String getSecureContainerPath(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
- mMediaStorageNotification.tickerText = title;
- if (pi == null) {
- Intent intent = new Intent();
- pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ try {
+ ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
+ String []tok = rsp.get(0).split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code != VoldResponseCode.AsecPathResult) {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ return tok[1];
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageNotFound) {
+ throw new IllegalArgumentException(String.format("Container '%s' not found", id));
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
-
- mMediaStorageNotification.icon = icon;
- mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
- }
-
- final int notificationId = mMediaStorageNotification.icon;
- if (visible) {
- notificationManager.notify(notificationId, mMediaStorageNotification);
- } else {
- notificationManager.cancel(notificationId);
}
}
+
+ public void finishMediaUpdate() {
+ mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ }
}
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
new file mode 100644
index 0000000..08d7ce6
--- /dev/null
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -0,0 +1,291 @@
+/*
+ * 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.Slog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.ListIterator;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Generic connector class for interfacing with a native
+ * daemon which uses the libsysutils FrameworkListener
+ * protocol.
+ */
+final class NativeDaemonConnector implements Runnable {
+ private static final boolean LOCAL_LOGD = false;
+
+ private BlockingQueue<String> mResponseQueue;
+ private OutputStream mOutputStream;
+ private String TAG = "NativeDaemonConnector";
+ private String mSocket;
+ private INativeDaemonConnectorCallbacks mCallbacks;
+
+ private final int BUFFER_SIZE = 4096;
+
+ class ResponseCode {
+ public static final int ActionInitiated = 100;
+
+ public static final int CommandOkay = 200;
+
+ // The range of 400 -> 599 is reserved for cmd failures
+ public static final int OperationFailed = 400;
+ public static final int CommandSyntaxError = 500;
+ public static final int CommandParameterError = 501;
+
+ public static final int UnsolicitedInformational = 600;
+
+ //
+ public static final int FailedRangeStart = 400;
+ public static final int FailedRangeEnd = 599;
+ }
+
+ NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks,
+ String socket, int responseQueueSize, String logTag) {
+ mCallbacks = callbacks;
+ if (logTag != null)
+ TAG = logTag;
+ mSocket = socket;
+ mResponseQueue = new LinkedBlockingQueue<String>(responseQueueSize);
+ }
+
+ public void run() {
+
+ while (true) {
+ try {
+ listenToSocket();
+ } catch (Exception e) {
+ Slog.e(TAG, "Error in NativeDaemonConnector", e);
+ SystemClock.sleep(5000);
+ }
+ }
+ }
+
+ private void listenToSocket() throws IOException {
+ LocalSocket socket = null;
+
+ try {
+ socket = new LocalSocket();
+ LocalSocketAddress address = new LocalSocketAddress(mSocket,
+ LocalSocketAddress.Namespace.RESERVED);
+
+ socket.connect(address);
+ mCallbacks.onDaemonConnected();
+
+ InputStream inputStream = socket.getInputStream();
+ mOutputStream = socket.getOutputStream();
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int start = 0;
+
+ while (true) {
+ int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
+ if (count < 0) break;
+
+ for (int i = 0; i < count; i++) {
+ if (buffer[i] == 0) {
+ String event = new String(buffer, start, i - start);
+ if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
+
+ String[] tokens = event.split(" ");
+ try {
+ int code = Integer.parseInt(tokens[0]);
+
+ if (code >= ResponseCode.UnsolicitedInformational) {
+ try {
+ if (!mCallbacks.onEvent(code, event, tokens)) {
+ Slog.w(TAG, String.format(
+ "Unhandled event (%s)", event));
+ }
+ } catch (Exception ex) {
+ Slog.e(TAG, String.format(
+ "Error handling '%s'", event), ex);
+ }
+ } else {
+ try {
+ mResponseQueue.put(event);
+ } catch (InterruptedException ex) {
+ Slog.e(TAG, "Failed to put response onto queue", ex);
+ }
+ }
+ } catch (NumberFormatException nfe) {
+ Slog.w(TAG, String.format("Bad msg (%s)", event));
+ }
+ start = i + 1;
+ }
+ }
+ if (start != count) {
+ final int remaining = BUFFER_SIZE - start;
+ System.arraycopy(buffer, start, buffer, 0, remaining);
+ start = remaining;
+ } else {
+ start = 0;
+ }
+ }
+ } catch (IOException ex) {
+ Slog.e(TAG, "Communications error", ex);
+ throw ex;
+ } finally {
+ synchronized (this) {
+ if (mOutputStream != null) {
+ try {
+ mOutputStream.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed closing output stream", e);
+ }
+ mOutputStream = null;
+ }
+ }
+
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed closing socket", ex);
+ }
+ }
+ }
+
+ private void sendCommand(String command) {
+ sendCommand(command, null);
+ }
+
+ /**
+ * Sends a command to the daemon with a single argument
+ *
+ * @param command The command to send to the daemon
+ * @param argument The argument to send with the command (or null)
+ */
+ private void sendCommand(String command, String argument) {
+ synchronized (this) {
+ if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument));
+ if (mOutputStream == null) {
+ Slog.e(TAG, "No connection to daemon", 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) {
+ Slog.e(TAG, "IOException in sendCommand", ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Issue a command to the native daemon and return the responses
+ */
+ public synchronized ArrayList<String> doCommand(String cmd)
+ throws NativeDaemonConnectorException {
+ sendCommand(cmd);
+
+ ArrayList<String> response = new ArrayList<String>();
+ boolean complete = false;
+ int code = -1;
+
+ while (!complete) {
+ try {
+ String line = mResponseQueue.take();
+ if (LOCAL_LOGD) Slog.d(TAG, String.format("RSP <- {%s}", line));
+ String[] tokens = line.split(" ");
+ try {
+ code = Integer.parseInt(tokens[0]);
+ } catch (NumberFormatException nfe) {
+ throw new NativeDaemonConnectorException(
+ String.format("Invalid response from daemon (%s)", line));
+ }
+
+ if ((code >= 200) && (code < 600)) {
+ complete = true;
+ }
+ response.add(line);
+ } catch (InterruptedException ex) {
+ Slog.e(TAG, "Failed to process response", ex);
+ }
+ }
+
+ if (code >= ResponseCode.FailedRangeStart &&
+ code <= ResponseCode.FailedRangeEnd) {
+ /*
+ * Note: The format of the last response in this case is
+ * "NNN <errmsg>"
+ */
+ throw new NativeDaemonConnectorException(
+ code, cmd, response.get(response.size()-1).substring(4));
+ }
+ return response;
+ }
+
+ /*
+ * Issues a list command and returns the cooked list
+ */
+ public String[] doListCommand(String cmd, int expectedResponseCode)
+ throws NativeDaemonConnectorException {
+
+ ArrayList<String> rsp = doCommand(cmd);
+ String[] rdata = new String[rsp.size()-1];
+ int idx = 0;
+
+ for (int i = 0; i < rsp.size(); i++) {
+ String line = rsp.get(i);
+ try {
+ String[] tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == expectedResponseCode) {
+ rdata[idx++] = line.substring(tok[0].length() + 1);
+ } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+ if (LOCAL_LOGD) Slog.d(TAG, String.format("List terminated with {%s}", line));
+ int last = rsp.size() -1;
+ if (i != last) {
+ Slog.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd));
+ for (int j = i; j <= last ; j++) {
+ Slog.w(TAG, String.format("ExtraData <%s>", rsp.get(i)));
+ }
+ }
+ return rdata;
+ } else {
+ throw new NativeDaemonConnectorException(
+ String.format("Expected list response %d, but got %d",
+ expectedResponseCode, code));
+ }
+ } catch (NumberFormatException nfe) {
+ throw new NativeDaemonConnectorException(
+ String.format("Error reading code '%s'", line));
+ }
+ }
+ throw new NativeDaemonConnectorException("Got an empty response");
+ }
+}
diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/java/com/android/server/NativeDaemonConnectorException.java
new file mode 100644
index 0000000..426742b
--- /dev/null
+++ b/services/java/com/android/server/NativeDaemonConnectorException.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+ * An exception that indicates there was an error with a NativeDaemonConnector operation
+ */
+public class NativeDaemonConnectorException extends RuntimeException
+{
+ private int mCode = -1;
+ private String mCmd;
+
+ public NativeDaemonConnectorException() {}
+
+ public NativeDaemonConnectorException(String error)
+ {
+ super(error);
+ }
+
+ public NativeDaemonConnectorException(int code, String cmd, String error)
+ {
+ super(String.format("Cmd {%s} failed with code %d : {%s}", cmd, code, error));
+ mCode = code;
+ mCmd = cmd;
+ }
+
+ public int getCode() {
+ return mCode;
+ }
+
+ public String getCmd() {
+ return mCmd;
+ }
+}
diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java
index 1ea0bac..7fe6743 100644
--- a/services/java/com/android/server/NetStatService.java
+++ b/services/java/com/android/server/NetStatService.java
@@ -17,44 +17,80 @@
package com.android.server;
import android.content.Context;
+import android.net.TrafficStats;
import android.os.INetStatService;
-import android.os.NetStat;
+import android.os.SystemClock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
public class NetStatService extends INetStatService.Stub {
+ private final Context mContext;
public NetStatService(Context context) {
-
+ mContext = context;
}
public long getMobileTxPackets() {
- return NetStat.getMobileTxPkts();
+ return TrafficStats.getMobileTxPackets();
}
public long getMobileRxPackets() {
- return NetStat.getMobileRxPkts();
+ return TrafficStats.getMobileRxPackets();
}
public long getMobileTxBytes() {
- return NetStat.getMobileTxBytes();
+ return TrafficStats.getMobileTxBytes();
}
public long getMobileRxBytes() {
- return NetStat.getMobileRxBytes();
+ return TrafficStats.getMobileRxBytes();
}
public long getTotalTxPackets() {
- return NetStat.getTotalTxPkts();
+ return TrafficStats.getTotalTxPackets();
}
public long getTotalRxPackets() {
- return NetStat.getTotalRxPkts();
+ return TrafficStats.getTotalRxPackets();
}
public long getTotalTxBytes() {
- return NetStat.getTotalTxBytes();
+ return TrafficStats.getTotalTxBytes();
}
public long getTotalRxBytes() {
- return NetStat.getTotalRxBytes();
+ return TrafficStats.getTotalRxBytes();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // This data is accessible to any app -- no permission check needed.
+
+ pw.print("Elapsed: total=");
+ pw.print(SystemClock.elapsedRealtime());
+ pw.print("ms awake=");
+ pw.print(SystemClock.uptimeMillis());
+ pw.println("ms");
+
+ pw.print("Mobile: Tx=");
+ pw.print(getMobileTxBytes());
+ pw.print("B/");
+ pw.print(getMobileTxPackets());
+ pw.print("Pkts Rx=");
+ pw.print(getMobileRxBytes());
+ pw.print("B/");
+ pw.print(getMobileRxPackets());
+ pw.println("Pkts");
+
+ pw.print("Total: Tx=");
+ pw.print(getTotalTxBytes());
+ pw.print("B/");
+ pw.print(getTotalTxPackets());
+ pw.print("Pkts Rx=");
+ pw.print(getTotalRxBytes());
+ pw.print("B/");
+ pw.print(getTotalRxPackets());
+ pw.println("Pkts");
}
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
new file mode 100644
index 0000000..552bed4
--- /dev/null
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -0,0 +1,608 @@
+/*
+ * 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.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.net.InterfaceConfiguration;
+import android.net.INetworkManagementEventObserver;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.INetworkManagementService;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import android.provider.Settings;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+
+import java.io.File;
+import java.io.FileReader;
+import java.lang.IllegalStateException;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @hide
+ */
+class NetworkManagementService extends INetworkManagementService.Stub {
+
+ private static final String TAG = "NetworkManagmentService";
+
+ class NetdResponseCode {
+ public static final int InterfaceListResult = 110;
+ public static final int TetherInterfaceListResult = 111;
+ public static final int TetherDnsFwdTgtListResult = 112;
+ public static final int TtyListResult = 113;
+
+ public static final int TetherStatusResult = 210;
+ public static final int IpFwdStatusResult = 211;
+ public static final int InterfaceGetCfgResult = 213;
+ public static final int SoftapStatusResult = 214;
+ public static final int UsbRNDISStatusResult = 215;
+ public static final int InterfaceRxCounterResult = 216;
+ public static final int InterfaceTxCounterResult = 217;
+ public static final int InterfaceRxThrottleResult = 218;
+ public static final int InterfaceTxThrottleResult = 219;
+
+ public static final int InterfaceChange = 600;
+ }
+
+ /**
+ * Binder context for this service
+ */
+ private Context mContext;
+
+ /**
+ * connector object for communicating with netd
+ */
+ private NativeDaemonConnector mConnector;
+
+ private ArrayList<INetworkManagementEventObserver> mObservers;
+
+ /**
+ * Constructs a new NetworkManagementService instance
+ *
+ * @param context Binder context for this service
+ */
+ public NetworkManagementService(Context context) {
+ mContext = context;
+
+ mObservers = new ArrayList<INetworkManagementEventObserver>();
+
+ if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ return;
+ }
+
+ mConnector = new NativeDaemonConnector(
+ new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
+ Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+ thread.start();
+ }
+
+ public void registerObserver(INetworkManagementEventObserver obs) {
+ Slog.d(TAG, "Registering observer");
+ mObservers.add(obs);
+ }
+
+ public void unregisterObserver(INetworkManagementEventObserver obs) {
+ Slog.d(TAG, "Unregistering observer");
+ mObservers.remove(mObservers.indexOf(obs));
+ }
+
+ /**
+ * Notify our observers of an interface link status change
+ */
+ private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
+ for (INetworkManagementEventObserver obs : mObservers) {
+ try {
+ obs.interfaceLinkStatusChanged(iface, link);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Observer notifier failed", ex);
+ }
+ }
+ }
+
+ /**
+ * Notify our observers of an interface addition.
+ */
+ private void notifyInterfaceAdded(String iface) {
+ for (INetworkManagementEventObserver obs : mObservers) {
+ try {
+ obs.interfaceAdded(iface);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Observer notifier failed", ex);
+ }
+ }
+ }
+
+ /**
+ * Notify our observers of an interface removal.
+ */
+ private void notifyInterfaceRemoved(String iface) {
+ for (INetworkManagementEventObserver obs : mObservers) {
+ try {
+ obs.interfaceRemoved(iface);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Observer notifier failed", ex);
+ }
+ }
+ }
+
+
+ //
+ // Netd Callback handling
+ //
+
+ class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
+ public void onDaemonConnected() {
+ new Thread() {
+ public void run() {
+ }
+ }.start();
+ }
+ public boolean onEvent(int code, String raw, String[] cooked) {
+ if (code == NetdResponseCode.InterfaceChange) {
+ /*
+ * a network interface change occured
+ * Format: "NNN Iface added <name>"
+ * "NNN Iface removed <name>"
+ * "NNN Iface changed <name> <up/down>"
+ */
+ if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+ throw new IllegalStateException(
+ String.format("Invalid event from daemon (%s)", raw));
+ }
+ if (cooked[2].equals("added")) {
+ notifyInterfaceAdded(cooked[3]);
+ return true;
+ } else if (cooked[2].equals("removed")) {
+ notifyInterfaceRemoved(cooked[3]);
+ return true;
+ } else if (cooked[2].equals("changed") && cooked.length == 5) {
+ notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
+ return true;
+ }
+ throw new IllegalStateException(
+ String.format("Invalid event from daemon (%s)", raw));
+ }
+ return false;
+ }
+ }
+
+ private static int stringToIpAddr(String addrString) throws UnknownHostException {
+ try {
+ String[] parts = addrString.split("\\.");
+ if (parts.length != 4) {
+ throw new UnknownHostException(addrString);
+ }
+
+ int a = Integer.parseInt(parts[0]) ;
+ int b = Integer.parseInt(parts[1]) << 8;
+ int c = Integer.parseInt(parts[2]) << 16;
+ int d = Integer.parseInt(parts[3]) << 24;
+
+ return a | b | c | d;
+ } catch (NumberFormatException ex) {
+ throw new UnknownHostException(addrString);
+ }
+ }
+
+ public static String intToIpString(int i) {
+ return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >> 8 ) & 0xFF) + "." +
+ (i & 0xFF);
+ }
+
+ //
+ // INetworkManagementService members
+ //
+
+ public String[] listInterfaces() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
+ }
+
+ public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
+ String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
+ Slog.d(TAG, String.format("rsp <%s>", rsp));
+
+ // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
+ StringTokenizer st = new StringTokenizer(rsp);
+
+ try {
+ int code = Integer.parseInt(st.nextToken(" "));
+ if (code != NetdResponseCode.InterfaceGetCfgResult) {
+ throw new IllegalStateException(
+ String.format("Expected code %d, but got %d",
+ NetdResponseCode.InterfaceGetCfgResult, code));
+ }
+ } catch (NumberFormatException nfe) {
+ throw new IllegalStateException(
+ String.format("Invalid response from daemon (%s)", rsp));
+ }
+
+ InterfaceConfiguration cfg = new InterfaceConfiguration();
+ cfg.hwAddr = st.nextToken(" ");
+ try {
+ cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
+ } catch (UnknownHostException uhe) {
+ Slog.e(TAG, "Failed to parse ipaddr", uhe);
+ cfg.ipAddr = 0;
+ }
+
+ try {
+ cfg.netmask = stringToIpAddr(st.nextToken(" "));
+ } catch (UnknownHostException uhe) {
+ Slog.e(TAG, "Failed to parse netmask", uhe);
+ cfg.netmask = 0;
+ }
+ cfg.interfaceFlags = st.nextToken("]").trim() +"]";
+ Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
+ return cfg;
+ }
+
+ public void setInterfaceConfig(
+ String iface, InterfaceConfiguration cfg) throws IllegalStateException {
+ String cmd = String.format("interface setcfg %s %s %s %s", iface,
+ intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
+ mConnector.doCommand(cmd);
+ }
+
+ public void shutdown() {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SHUTDOWN)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires SHUTDOWN permission");
+ }
+
+ Slog.d(TAG, "Shutting down");
+ }
+
+ public boolean getIpForwardingEnabled() throws IllegalStateException{
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.IpFwdStatusResult) {
+ // 211 Forwarding <enabled/disabled>
+ if (tok.length !=2) {
+ throw new IllegalStateException(
+ String.format("Malformatted list entry '%s'", line));
+ }
+ if (tok[2].equals("enabled"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
+ }
+
+ public void startTethering(String[] dhcpRange)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ // cmd is "tether start first_start first_stop second_start second_stop ..."
+ // an odd number of addrs will fail
+ String cmd = "tether start";
+ for (String d : dhcpRange) {
+ cmd += " " + d;
+ }
+ mConnector.doCommand(cmd);
+ }
+
+ public void stopTethering() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether stop");
+ }
+
+ public boolean isTetheringStarted() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ ArrayList<String> rsp = mConnector.doCommand("tether status");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.TetherStatusResult) {
+ // XXX: Tethering services <started/stopped> <TBD>...
+ if (tok[2].equals("started"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void tetherInterface(String iface) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether interface add " + iface);
+ }
+
+ public void untetherInterface(String iface) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("tether interface remove " + iface);
+ }
+
+ public String[] listTetheredInterfaces() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ return mConnector.doListCommand(
+ "tether interface list", NetdResponseCode.TetherInterfaceListResult);
+ }
+
+ public void setDnsForwarders(String[] dns) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String cmd = "tether dns set";
+ for (String s : dns) {
+ cmd += " " + InetAddress.getByName(s).getHostAddress();
+ }
+ mConnector.doCommand(cmd);
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException("Error resolving dns name", e);
+ }
+ }
+
+ public String[] getDnsForwarders() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ return mConnector.doListCommand(
+ "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
+ }
+
+ public void enableNat(String internalInterface, String externalInterface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(
+ String.format("nat enable %s %s", internalInterface, externalInterface));
+ }
+
+ public void disableNat(String internalInterface, String externalInterface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(
+ String.format("nat disable %s %s", internalInterface, externalInterface));
+ }
+
+ public String[] listTtys() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
+ }
+
+ public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
+ String dns2Addr) throws IllegalStateException {
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
+ InetAddress.getByName(localAddr).getHostAddress(),
+ InetAddress.getByName(remoteAddr).getHostAddress(),
+ InetAddress.getByName(dns1Addr).getHostAddress(),
+ InetAddress.getByName(dns2Addr).getHostAddress()));
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException("Error resolving addr", e);
+ }
+ }
+
+ public void detachPppd(String tty) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("pppd detach %s", tty));
+ }
+
+ public void startUsbRNDIS() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("usb startrndis");
+ }
+
+ public void stopUsbRNDIS() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand("usb stoprndis");
+ }
+
+ public boolean isUsbRNDISStarted() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == NetdResponseCode.UsbRNDISStatusResult) {
+ if (tok[3].equals("started"))
+ return true;
+ return false;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format("softap stop " + wlanIface));
+ mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
+ mConnector.doCommand(String.format("softap start " + wlanIface));
+ if (wifiConfig == null) {
+ mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+ } else {
+ /**
+ * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
+ * argv1 - wlan interface
+ * argv2 - softap interface
+ * argv3 - SSID
+ * argv4 - Security
+ * argv5 - Key
+ * argv6 - Channel
+ * argv7 - Preamble
+ * argv8 - Max SCB
+ */
+ String str = String.format("softap set " + wlanIface + " " + softapIface +
+ " \"%s\" %s %s", wifiConfig.SSID,
+ wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+ "wpa2-psk" : "open",
+ wifiConfig.preSharedKey);
+ mConnector.doCommand(str);
+ }
+ mConnector.doCommand(String.format("softap startap"));
+ }
+
+ public void stopAccessPoint() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
+ mConnector.doCommand("softap stopap");
+ }
+
+ public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
+ if (wifiConfig == null) {
+ mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+ } else {
+ String str = String.format("softap set " + wlanIface + " " + softapIface +
+ " \"%s\" %s %s", wifiConfig.SSID,
+ wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+ "wpa2-psk" : "open",
+ wifiConfig.preSharedKey);
+ mConnector.doCommand(str);
+ }
+ }
+
+ private long getInterfaceCounter(String iface, boolean rx) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String rsp = mConnector.doCommand(
+ String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
+ String []tok = rsp.split(" ");
+ int code;
+ try {
+ code = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
+ return -1;
+ }
+ if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
+ !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
+ Slog.e(TAG, String.format("Unexpected response code %d", code));
+ return -1;
+ }
+ return Long.parseLong(tok[1]);
+ } catch (Exception e) {
+ Slog.e(TAG, String.format(
+ "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
+ }
+ return -1;
+ }
+
+ public long getInterfaceRxCounter(String iface) {
+ return getInterfaceCounter(iface, true);
+ }
+
+ public long getInterfaceTxCounter(String iface) {
+ return getInterfaceCounter(iface, false);
+ }
+
+ public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ mConnector.doCommand(String.format(
+ "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
+ }
+
+ private int getInterfaceThrottle(String iface, boolean rx) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String rsp = mConnector.doCommand(
+ String.format("interface getthrottle %s %s", iface,(rx ? "rx" : "tx"))).get(0);
+ String []tok = rsp.split(" ");
+ int code;
+ try {
+ code = Integer.parseInt(tok[0]);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
+ return -1;
+ }
+ if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
+ !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
+ Slog.e(TAG, String.format("Unexpected response code %d", code));
+ return -1;
+ }
+ return Integer.parseInt(tok[1]);
+ } catch (Exception e) {
+ Slog.e(TAG, String.format(
+ "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
+ }
+ return -1;
+ }
+
+ public int getInterfaceRxThrottle(String iface) {
+ return getInterfaceThrottle(iface, true);
+ }
+
+ public int getInterfaceTxThrottle(String iface) {
+ return getInterfaceThrottle(iface, false);
+ }
+}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index d7e1d25..73d17ea 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -39,7 +39,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.media.AsyncPlayer;
import android.media.AudioManager;
import android.net.Uri;
import android.os.BatteryManager;
@@ -53,8 +52,10 @@ import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.EventLog;
+import android.util.Slog;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -75,8 +76,8 @@ class NotificationManagerService extends INotificationManager.Stub
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 long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
@@ -86,10 +87,17 @@ class NotificationManagerService extends INotificationManager.Stub
private WorkerHandler mHandler;
private StatusBarService mStatusBarService;
- private HardwareService mHardware;
+ private LightsService mLightsService;
+ private LightsService.Light mBatteryLight;
+ private LightsService.Light mNotificationLight;
+ private LightsService.Light mAttentionLight;
+
+ private int mDefaultNotificationColor;
+ private int mDefaultNotificationLedOn;
+ private int mDefaultNotificationLedOff;
private NotificationRecord mSoundNotification;
- private AsyncPlayer mSound;
+ private NotificationPlayer mSound;
private boolean mSystemReady;
private int mDisabledNotifications;
@@ -98,6 +106,7 @@ class NotificationManagerService extends INotificationManager.Stub
// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
+ private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
// for adb connected notifications
@@ -105,7 +114,7 @@ class NotificationManagerService extends INotificationManager.Stub
private boolean mAdbEnabled = false;
private boolean mAdbNotificationShown = false;
private Notification mAdbNotification;
-
+
private final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
@@ -124,11 +133,6 @@ class NotificationManagerService extends INotificationManager.Stub
private static final int BATTERY_BLINK_ON = 125;
private static final int BATTERY_BLINK_OFF = 2875;
- // 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;
@@ -188,7 +192,7 @@ class NotificationManagerService extends INotificationManager.Stub
+ " ledOnMS=" + notification.ledOnMS
+ " ledOffMS=" + notification.ledOffMS);
}
-
+
@Override
public final String toString()
{
@@ -218,11 +222,11 @@ class NotificationManagerService extends INotificationManager.Stub
void update(int duration) {
this.duration = duration;
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + this);
}
-
+
@Override
public final String toString()
{
@@ -305,6 +309,8 @@ class NotificationManagerService extends INotificationManager.Stub
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ boolean queryRestart = false;
+
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
int level = intent.getIntExtra("level", -1);
@@ -327,22 +333,39 @@ class NotificationManagerService extends INotificationManager.Stub
mUsbConnected = false;
updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
- || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
- Uri uri = intent.getData();
- if (uri == null) {
- return;
+ || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+ || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
+ || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+ String pkgList[] = null;
+ if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else if (queryRestart) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ } else {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ if (pkgName == null) {
+ return;
+ }
+ pkgList = new String[]{pkgName};
}
- String pkgName = uri.getSchemeSpecificPart();
- if (pkgName == null) {
- return;
+ if (pkgList != null && (pkgList.length > 0)) {
+ for (String pkgName : pkgList) {
+ cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
+ }
}
- cancelAllNotificationsInt(pkgName, 0, 0);
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
mScreenOn = true;
updateNotificationPulse();
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
updateNotificationPulse();
+ } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
+ mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
+ updateNotificationPulse();
}
}
};
@@ -351,7 +374,7 @@ class NotificationManagerService extends INotificationManager.Stub
SettingsObserver(Handler handler) {
super(handler);
}
-
+
void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -383,19 +406,32 @@ class NotificationManagerService extends INotificationManager.Stub
}
NotificationManagerService(Context context, StatusBarService statusBar,
- HardwareService hardware)
+ LightsService lights)
{
super();
mContext = context;
- mHardware = hardware;
+ mLightsService = lights;
mAm = ActivityManagerNative.getDefault();
- mSound = new AsyncPlayer(TAG);
+ mSound = new NotificationPlayer(TAG);
mSound.setUsesWakeLock(context);
mToastQueue = new ArrayList<ToastRecord>();
mHandler = new WorkerHandler();
+
mStatusBarService = statusBar;
statusBar.setNotificationCallbacks(mNotificationCallbacks);
+ mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
+ mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
+ mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+
+ Resources resources = mContext.getResources();
+ mDefaultNotificationColor = resources.getColor(
+ com.android.internal.R.color.config_defaultNotificationColor);
+ mDefaultNotificationLedOn = resources.getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOn);
+ mDefaultNotificationLedOff = resources.getInteger(
+ com.android.internal.R.integer.config_defaultNotificationLedOff);
+
// Don't start allowing notifications until the setup wizard has run once.
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
@@ -410,12 +446,19 @@ class NotificationManagerService extends INotificationManager.Stub
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_UMS_CONNECTED);
filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
mContext.registerReceiver(mIntentReceiver, filter);
-
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ pkgFilter.addDataScheme("package");
+ mContext.registerReceiver(mIntentReceiver, pkgFilter);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mIntentReceiver, sdFilter);
+
SettingsObserver observer = new SettingsObserver(mHandler);
observer.observe();
}
@@ -429,10 +472,10 @@ class NotificationManagerService extends INotificationManager.Stub
// ============================================================================
public void enqueueToast(String pkg, ITransientNotification callback, int duration)
{
- Log.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
+ if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
if (pkg == null || callback == null) {
- Log.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
+ Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
return ;
}
@@ -467,10 +510,10 @@ class NotificationManagerService extends INotificationManager.Stub
}
public void cancelToast(String pkg, ITransientNotification callback) {
- Log.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+ Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
if (pkg == null || callback == null) {
- Log.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
+ Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
return ;
}
@@ -481,7 +524,7 @@ class NotificationManagerService extends INotificationManager.Stub
if (index >= 0) {
cancelToastLocked(index);
} else {
- Log.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
+ Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -492,13 +535,13 @@ class NotificationManagerService extends INotificationManager.Stub
private void showNextToastLocked() {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
- if (DBG) Log.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+ if (DBG) Slog.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
+ Slog.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);
@@ -520,7 +563,7 @@ class NotificationManagerService extends INotificationManager.Stub
try {
record.callback.hide();
} catch (RemoteException e) {
- Log.w(TAG, "Object died trying to hide notification " + record.callback
+ Slog.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
@@ -545,7 +588,7 @@ class NotificationManagerService extends INotificationManager.Stub
private void handleTimeout(ToastRecord record)
{
- if (DBG) Log.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
+ if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
synchronized (mToastQueue) {
int index = indexOfToastLocked(record.pkg, record.callback);
if (index >= 0) {
@@ -614,12 +657,12 @@ class NotificationManagerService extends INotificationManager.Stub
Notification notification, int[] idOut)
{
checkIncomingCall(pkg);
-
+
// 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());
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
}
if (pkg == null || notification == null) {
@@ -653,20 +696,20 @@ class NotificationManagerService extends INotificationManager.Stub
old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
}
}
-
+
// Ensure if this is a foreground service that the proper additional
// flags are set.
if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
notification.flags |= Notification.FLAG_ONGOING_EVENT
| Notification.FLAG_NO_CLEAR;
}
-
+
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;
@@ -700,7 +743,7 @@ class NotificationManagerService extends INotificationManager.Stub
long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBarService.addIcon(icon, n);
- mHardware.pulseBreathingLight();
+ mAttentionLight.pulse();
}
finally {
Binder.restoreCallingIdentity(identity);
@@ -731,7 +774,7 @@ class NotificationManagerService extends INotificationManager.Stub
.getSystemService(Context.AUDIO_SERVICE);
// sound
final boolean useDefaultSound =
- (notification.defaults & Notification.DEFAULT_SOUND) != 0;
+ (notification.defaults & Notification.DEFAULT_SOUND) != 0;
if (useDefaultSound || notification.sound != null) {
Uri uri;
if (useDefaultSound) {
@@ -762,12 +805,12 @@ class NotificationManagerService extends INotificationManager.Stub
// vibrate
final boolean useDefaultVibrate =
- (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
+ (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
+ mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
: notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
}
@@ -781,7 +824,7 @@ class NotificationManagerService extends INotificationManager.Stub
if (mLedNotification == old) {
mLedNotification = null;
}
- //Log.i(TAG, "notification.lights="
+ //Slog.i(TAG, "notification.lights="
// + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
mLights.add(r);
@@ -862,24 +905,24 @@ class NotificationManagerService extends INotificationManager.Stub
/**
* Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
- * and none of the {@code mustNotHaveFlags}.
+ * and none of the {@code mustNotHaveFlags}.
*/
private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
int mustNotHaveFlags) {
- EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
synchronized (mNotificationList) {
int index = indexOfNotificationLocked(pkg, tag, id);
if (index >= 0) {
NotificationRecord r = mNotificationList.get(index);
-
+
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
return;
}
if ((r.notification.flags & mustNotHaveFlags) != 0) {
return;
}
-
+
mNotificationList.remove(index);
cancelNotificationLocked(r);
@@ -892,9 +935,9 @@ class NotificationManagerService extends INotificationManager.Stub
* Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
- void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
- int mustNotHaveFlags) {
- EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
+ boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
+ int mustNotHaveFlags, boolean doit) {
+ EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
synchronized (mNotificationList) {
final int N = mNotificationList.size();
@@ -910,17 +953,21 @@ class NotificationManagerService extends INotificationManager.Stub
if (!r.pkg.equals(pkg)) {
continue;
}
+ canceledSomething = true;
+ if (!doit) {
+ return true;
+ }
mNotificationList.remove(i);
cancelNotificationLocked(r);
- canceledSomething = true;
}
if (canceledSomething) {
updateLightsLocked();
}
+ return canceledSomething;
}
}
-
+
public void cancelNotification(String pkg, int id) {
cancelNotificationWithTag(pkg, null /* tag */, id);
}
@@ -935,10 +982,10 @@ class NotificationManagerService extends INotificationManager.Stub
public void cancelAllNotifications(String pkg) {
checkIncomingCall(pkg);
-
+
// Calling from user space, don't allow the canceling of actively
// running foreground services.
- cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
}
void checkIncomingCall(String pkg) {
@@ -957,7 +1004,7 @@ class NotificationManagerService extends INotificationManager.Stub
throw new SecurityException("Unknown package " + pkg);
}
}
-
+
void cancelAll() {
synchronized (mNotificationList) {
final int N = mNotificationList.size();
@@ -972,7 +1019,7 @@ class NotificationManagerService extends INotificationManager.Stub
} 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);
+ Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
}
}
mNotificationList.remove(i);
@@ -996,24 +1043,20 @@ class NotificationManagerService extends INotificationManager.Stub
// Battery low always shows, other states only show if charging.
if (mBatteryLow) {
if (mBatteryCharging) {
- mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
- BATTERY_LOW_ARGB);
+ mBatteryLight.setColor(BATTERY_LOW_ARGB);
} else {
// Flash when battery is low and not charging
- mHardware.setLightFlashing_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
- BATTERY_LOW_ARGB, HardwareService.LIGHT_FLASH_TIMED,
- BATTERY_BLINK_ON, BATTERY_BLINK_OFF);
+ mBatteryLight.setFlashing(BATTERY_LOW_ARGB, LightsService.LIGHT_FLASH_TIMED,
+ BATTERY_BLINK_ON, BATTERY_BLINK_OFF);
}
} else if (mBatteryCharging) {
if (mBatteryFull) {
- mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
- BATTERY_FULL_ARGB);
+ mBatteryLight.setColor(BATTERY_FULL_ARGB);
} else {
- mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
- BATTERY_MEDIUM_ARGB);
+ mBatteryLight.setColor(BATTERY_MEDIUM_ARGB);
}
} else {
- mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_BATTERY);
+ mBatteryLight.turnOff();
}
// handle notification lights
@@ -1026,15 +1069,26 @@ class NotificationManagerService extends INotificationManager.Stub
}
// we only flash if screen is off and persistent pulsing is enabled
- if (mLedNotification == null || mScreenOn || !mNotificationPulseEnabled) {
- mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_NOTIFICATIONS);
+ // and we are not currently in a call
+ if (mLedNotification == null || mScreenOn || mInCall) {
+ mNotificationLight.turnOff();
} else {
- mHardware.setLightFlashing_UNCHECKED(
- HardwareService.LIGHT_ID_NOTIFICATIONS,
- mLedNotification.notification.ledARGB,
- HardwareService.LIGHT_FLASH_TIMED,
- mLedNotification.notification.ledOnMS,
- mLedNotification.notification.ledOffMS);
+ int ledARGB = mLedNotification.notification.ledARGB;
+ int ledOnMS = mLedNotification.notification.ledOnMS;
+ int ledOffMS = mLedNotification.notification.ledOffMS;
+ if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ ledARGB = mDefaultNotificationColor;
+ ledOnMS = mDefaultNotificationLedOn;
+ ledOffMS = mDefaultNotificationLedOff;
+ }
+ if (mNotificationPulseEnabled) {
+ // pulse repeatedly
+ mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+ ledOnMS, ledOffMS);
+ } else {
+ // pulse only once
+ mNotificationLight.pulse(ledARGB, ledOnMS);
+ }
}
}
@@ -1081,11 +1135,13 @@ class NotificationManagerService extends INotificationManager.Stub
if (mAdbNotification == null) {
mAdbNotification = new Notification();
- mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
+ mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
mAdbNotification.when = 0;
mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
mAdbNotification.tickerText = title;
- mAdbNotification.defaults |= Notification.DEFAULT_SOUND;
+ mAdbNotification.defaults = 0; // please be quiet
+ mAdbNotification.sound = null;
+ mAdbNotification.vibrate = null;
}
Intent intent = new Intent(
@@ -1101,14 +1157,14 @@ class NotificationManagerService extends INotificationManager.Stub
intent, 0);
mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
-
+
mAdbNotificationShown = true;
notificationManager.notify(
com.android.internal.R.string.adb_active_notification_title,
mAdbNotification);
}
}
-
+
} else if (mAdbNotificationShown) {
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1136,7 +1192,7 @@ class NotificationManagerService extends INotificationManager.Stub
+ ", uid=" + Binder.getCallingUid());
return;
}
-
+
pw.println("Current Notification Manager state:");
int N;
@@ -1150,7 +1206,7 @@ class NotificationManagerService extends INotificationManager.Stub
}
pw.println(" ");
}
-
+
}
synchronized (mNotificationList) {
@@ -1162,7 +1218,7 @@ class NotificationManagerService extends INotificationManager.Stub
}
pw.println(" ");
}
-
+
N = mLights.size();
if (N > 0) {
pw.println(" Lights List:");
@@ -1171,7 +1227,7 @@ class NotificationManagerService extends INotificationManager.Stub
}
pw.println(" ");
}
-
+
pw.println(" mSoundNotification=" + mSoundNotification);
pw.println(" mSound=" + mSound);
pw.println(" mVibrateNotification=" + mVibrateNotification);
diff --git a/services/java/com/android/server/NotificationPlayer.java b/services/java/com/android/server/NotificationPlayer.java
new file mode 100644
index 0000000..0b1a03b
--- /dev/null
+++ b/services/java/com/android/server/NotificationPlayer.java
@@ -0,0 +1,338 @@
+/*
+ * 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.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.IOException;
+import java.lang.IllegalStateException;
+import java.lang.Thread;
+import java.util.LinkedList;
+
+/**
+ * @hide
+ * This class is provides the same interface and functionality as android.media.AsyncPlayer
+ * with the following differences:
+ * - whenever audio is played, audio focus is requested,
+ * - whenever audio playback is stopped or the playback completed, audio focus is abandoned.
+ */
+public class NotificationPlayer implements OnCompletionListener {
+ private static final int PLAY = 1;
+ private static final int STOP = 2;
+ private static final boolean mDebug = false;
+
+ private static final class Command {
+ int code;
+ Context context;
+ Uri uri;
+ boolean looping;
+ int stream;
+ long requestTime;
+
+ public String toString() {
+ return "{ code=" + code + " looping=" + looping + " stream=" + stream
+ + " uri=" + uri + " }";
+ }
+ }
+
+ private LinkedList<Command> mCmdQueue = new LinkedList();
+
+ private Looper mLooper;
+
+ /*
+ * Besides the use of audio focus, the only implementation difference between AsyncPlayer and
+ * NotificationPlayer resides in the creation of the MediaPlayer. For the completion callback,
+ * OnCompletionListener, to be called at the end of the playback, the MediaPlayer needs to
+ * be created with a looper running so its event handler is not null.
+ */
+ private final class CreationAndCompletionThread extends Thread {
+ public Command mCmd;
+ public CreationAndCompletionThread(Command cmd) {
+ super();
+ mCmd = cmd;
+ }
+
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ synchronized(this) {
+ AudioManager audioManager =
+ (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
+ try {
+ MediaPlayer player = new MediaPlayer();
+ player.setAudioStreamType(mCmd.stream);
+ player.setDataSource(mCmd.context, mCmd.uri);
+ player.setLooping(mCmd.looping);
+ player.prepare();
+ if (mCmd.looping) {
+ audioManager.requestAudioFocus(null, mCmd.stream,
+ AudioManager.AUDIOFOCUS_GAIN);
+ } else {
+ audioManager.requestAudioFocus(null, mCmd.stream,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+ }
+ player.setOnCompletionListener(NotificationPlayer.this);
+ player.start();
+ if (mPlayer != null) {
+ mPlayer.release();
+ }
+ mPlayer = player;
+ }
+ catch (Exception e) {
+ Log.w(mTag, "error loading sound for " + mCmd.uri, e);
+ }
+ mAudioManager = audioManager;
+ this.notify();
+ }
+ Looper.loop();
+ }
+ };
+
+ private void startSound(Command cmd) {
+ // Preparing can be slow, so if there is something else
+ // is playing, let it continue until we're done, so there
+ // is less of a glitch.
+ try {
+ if (mDebug) Log.d(mTag, "Starting playback");
+ //-----------------------------------
+ // This is were we deviate from the AsyncPlayer implementation and create the
+ // MediaPlayer in a new thread with which we're synchronized
+ synchronized(mCompletionHandlingLock) {
+ // if another sound was already playing, it doesn't matter we won't get notified
+ // of the completion, since only the completion notification of the last sound
+ // matters
+ if((mLooper != null)
+ && (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
+ mLooper.quit();
+ }
+ mCompletionThread = new CreationAndCompletionThread(cmd);
+ synchronized(mCompletionThread) {
+ mCompletionThread.start();
+ mCompletionThread.wait();
+ }
+ }
+ //-----------------------------------
+
+ long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+ if (delay > 1000) {
+ Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
+ }
+ }
+ catch (Exception e) {
+ Log.w(mTag, "error loading sound for " + cmd.uri, e);
+ }
+ }
+
+ private final class CmdThread extends java.lang.Thread {
+ CmdThread() {
+ super("NotificationPlayer-" + mTag);
+ }
+
+ public void run() {
+ while (true) {
+ Command cmd = null;
+
+ synchronized (mCmdQueue) {
+ if (mDebug) Log.d(mTag, "RemoveFirst");
+ cmd = mCmdQueue.removeFirst();
+ }
+
+ switch (cmd.code) {
+ case PLAY:
+ if (mDebug) Log.d(mTag, "PLAY");
+ startSound(cmd);
+ break;
+ case STOP:
+ if (mDebug) Log.d(mTag, "STOP");
+ if (mPlayer != null) {
+ long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+ if (delay > 1000) {
+ Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
+ }
+ mPlayer.stop();
+ mPlayer.release();
+ mPlayer = null;
+ mAudioManager.abandonAudioFocus(null);
+ mAudioManager = null;
+ if((mLooper != null)
+ && (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
+ mLooper.quit();
+ }
+ } else {
+ Log.w(mTag, "STOP command without a player");
+ }
+ break;
+ }
+
+ synchronized (mCmdQueue) {
+ if (mCmdQueue.size() == 0) {
+ // nothing left to do, quit
+ // doing this check after we're done prevents the case where they
+ // added it during the operation from spawning two threads and
+ // trying to do them in parallel.
+ mThread = null;
+ releaseWakeLock();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public void onCompletion(MediaPlayer mp) {
+ if (mAudioManager != null) {
+ mAudioManager.abandonAudioFocus(null);
+ }
+ // if there are no more sounds to play, end the Looper to listen for media completion
+ synchronized (mCmdQueue) {
+ if (mCmdQueue.size() == 0) {
+ synchronized(mCompletionHandlingLock) {
+ if(mLooper != null) {
+ mLooper.quit();
+ }
+ mCompletionThread = null;
+ }
+ }
+ }
+ }
+
+ private String mTag;
+ private CmdThread mThread;
+ private CreationAndCompletionThread mCompletionThread;
+ private final Object mCompletionHandlingLock = new Object();
+ private MediaPlayer mPlayer;
+ private PowerManager.WakeLock mWakeLock;
+ private AudioManager mAudioManager;
+
+ // The current state according to the caller. Reality lags behind
+ // because of the asynchronous nature of this class.
+ private int mState = STOP;
+
+ /**
+ * Construct a NotificationPlayer object.
+ *
+ * @param tag a string to use for debugging
+ */
+ public NotificationPlayer(String tag) {
+ if (tag != null) {
+ mTag = tag;
+ } else {
+ mTag = "NotificationPlayer";
+ }
+ }
+
+ /**
+ * Start playing the sound. It will actually start playing at some
+ * point in the future. There are no guarantees about latency here.
+ * Calling this before another audio file is done playing will stop
+ * that one and start the new one.
+ *
+ * @param context Your application's context.
+ * @param uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)})
+ * @param looping Whether the audio should loop forever.
+ * (see {@link MediaPlayer#setLooping(boolean)})
+ * @param stream the AudioStream to use.
+ * (see {@link MediaPlayer#setAudioStreamType(int)})
+ */
+ public void play(Context context, Uri uri, boolean looping, int stream) {
+ Command cmd = new Command();
+ cmd.requestTime = SystemClock.uptimeMillis();
+ cmd.code = PLAY;
+ cmd.context = context;
+ cmd.uri = uri;
+ cmd.looping = looping;
+ cmd.stream = stream;
+ synchronized (mCmdQueue) {
+ enqueueLocked(cmd);
+ mState = PLAY;
+ }
+ }
+
+ /**
+ * Stop a previously played sound. It can't be played again or unpaused
+ * at this point. Calling this multiple times has no ill effects.
+ */
+ public void stop() {
+ synchronized (mCmdQueue) {
+ // This check allows stop to be called multiple times without starting
+ // a thread that ends up doing nothing.
+ if (mState != STOP) {
+ Command cmd = new Command();
+ cmd.requestTime = SystemClock.uptimeMillis();
+ cmd.code = STOP;
+ enqueueLocked(cmd);
+ mState = STOP;
+ }
+ }
+ }
+
+ private void enqueueLocked(Command cmd) {
+ mCmdQueue.add(cmd);
+ if (mThread == null) {
+ acquireWakeLock();
+ mThread = new CmdThread();
+ mThread.start();
+ }
+ }
+
+ /**
+ * We want to hold a wake lock while we do the prepare and play. The stop probably is
+ * optional, but it won't hurt to have it too. The problem is that if you start a sound
+ * while you're holding a wake lock (e.g. an alarm starting a notification), you want the
+ * sound to play, but if the CPU turns off before mThread gets to work, it won't. The
+ * simplest way to deal with this is to make it so there is a wake lock held while the
+ * thread is starting or running. You're going to need the WAKE_LOCK permission if you're
+ * going to call this.
+ *
+ * This must be called before the first time play is called.
+ *
+ * @hide
+ */
+ public void setUsesWakeLock(Context context) {
+ if (mWakeLock != null || mThread != null) {
+ // if either of these has happened, we've already played something.
+ // and our releases will be out of sync.
+ throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
+ + " mThread=" + mThread);
+ }
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
+ }
+
+ private void acquireWakeLock() {
+ if (mWakeLock != null) {
+ mWakeLock.acquire();
+ }
+ }
+
+ private void releaseWakeLock() {
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ }
+ }
+}
+
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index dbd1826..77bddb0 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -16,9 +16,9 @@
package com.android.server;
-import android.app.BackupAgent;
-import android.backup.BackupDataInput;
-import android.backup.BackupDataOutput;
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -26,7 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.os.Build;
import android.os.ParcelFileDescriptor;
-import android.util.Log;
+import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* We back up the signatures of each package so that during a system restore,
@@ -94,21 +95,35 @@ public class PackageManagerBackupAgent extends BackupAgent {
public Metadata getRestoredMetadata(String packageName) {
if (mRestoredSignatures == null) {
- Log.w(TAG, "getRestoredMetadata() before metadata read!");
+ Slog.w(TAG, "getRestoredMetadata() before metadata read!");
return null;
}
return mRestoredSignatures.get(packageName);
}
+
+ public Set<String> getRestoredPackages() {
+ if (mRestoredSignatures == null) {
+ Slog.w(TAG, "getRestoredPackages() before metadata read!");
+ return null;
+ }
+
+ // This is technically the set of packages on the originating handset
+ // that had backup agents at all, not limited to the set of packages
+ // that had actually contributed a restore dataset, but it's a
+ // close enough approximation for our purposes and does not require any
+ // additional involvement by the transport to obtain.
+ return mRestoredSignatures.keySet();
+ }
// The backed up data is the signature block for each app, keyed by
// the package name.
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
- if (DEBUG) Log.v(TAG, "onBackup()");
+ if (DEBUG) Slog.v(TAG, "onBackup()");
- ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
- DataOutputStream outWriter = new DataOutputStream(bufStream);
+ ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these
+ DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer);
parseStateFile(oldState);
// If the stored version string differs, we need to re-backup all
@@ -116,7 +131,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
// "already backed up" map built by parseStateFile().
if (mStoredIncrementalVersion == null
|| !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) {
- Log.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
+ Slog.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
+ Build.VERSION.INCREMENTAL + " - rewriting");
mExisting.clear();
}
@@ -132,14 +147,12 @@ public class PackageManagerBackupAgent extends BackupAgent {
* the backup set.
*/
if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
- if (DEBUG) Log.v(TAG, "Storing global metadata key");
- outWriter.writeInt(Build.VERSION.SDK_INT);
- outWriter.writeUTF(Build.VERSION.INCREMENTAL);
- byte[] metadata = bufStream.toByteArray();
- data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
- data.writeEntityData(metadata, metadata.length);
+ if (DEBUG) Slog.v(TAG, "Storing global metadata key");
+ outputBufferStream.writeInt(Build.VERSION.SDK_INT);
+ outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL);
+ writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray());
} else {
- if (DEBUG) Log.v(TAG, "Global metadata key already stored");
+ if (DEBUG) Slog.v(TAG, "Global metadata key already stored");
// don't consider it to have been skipped/deleted
mExisting.remove(GLOBAL_METADATA_KEY);
}
@@ -163,49 +176,46 @@ public class PackageManagerBackupAgent extends BackupAgent {
continue;
}
- boolean doBackup = false;
- if (!mExisting.contains(packName)) {
- // We haven't backed up this app before
- doBackup = true;
- } else {
- // We *have* backed this one up before. Check whether the version
+ if (mExisting.contains(packName)) {
+ // We have backed up this app before. Check whether the version
// of the backup matches the version of the current app; if they
// don't match, the app has been updated and we need to store its
// metadata again. In either case, take it out of mExisting so that
// we don't consider it deleted later.
- if (info.versionCode != mStateVersions.get(packName).versionCode) {
- doBackup = true;
- }
mExisting.remove(packName);
+ if (info.versionCode == mStateVersions.get(packName).versionCode) {
+ continue;
+ }
+ }
+
+ if (info.signatures == null || info.signatures.length == 0)
+ {
+ Slog.w(TAG, "Not backing up package " + packName
+ + " since it appears to have no signatures.");
+ continue;
}
- if (doBackup) {
- // We need to store this app's metadata
- /*
- * Metadata for each package:
- *
- * int version -- [4] the package's versionCode
- * byte[] signatures -- [len] flattened Signature[] of the package
- */
-
- // marshal the version code in a canonical form
- bufStream.reset();
- outWriter.writeInt(info.versionCode);
- byte[] versionBuf = bufStream.toByteArray();
-
- byte[] sigs = flattenSignatureArray(info.signatures);
-
- if (DEBUG) {
- Log.v(TAG, "+ metadata for " + packName
- + " version=" + info.versionCode
- + " versionLen=" + versionBuf.length
- + " sigsLen=" + sigs.length);
- }
- // Now we can write the backup entity for this package
- data.writeEntityHeader(packName, versionBuf.length + sigs.length);
- data.writeEntityData(versionBuf, versionBuf.length);
- data.writeEntityData(sigs, sigs.length);
+ // We need to store this app's metadata
+ /*
+ * Metadata for each package:
+ *
+ * int version -- [4] the package's versionCode
+ * byte[] signatures -- [len] flattened Signature[] of the package
+ */
+
+ // marshal the version code in a canonical form
+ outputBuffer.reset();
+ outputBufferStream.writeInt(info.versionCode);
+ writeSignatureArray(outputBufferStream, info.signatures);
+
+ if (DEBUG) {
+ Slog.v(TAG, "+ writing metadata for " + packName
+ + " version=" + info.versionCode
+ + " entityLen=" + outputBuffer.size());
}
+
+ // Now we can write the backup entity for this package
+ writeEntity(data, packName, outputBuffer.toByteArray());
}
}
@@ -213,23 +223,29 @@ public class PackageManagerBackupAgent extends BackupAgent {
// mentioned in the saved state file, but appear to no longer be present
// on the device. Write a deletion entity for them.
for (String app : mExisting) {
- if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
+ if (DEBUG) Slog.v(TAG, "- removing metadata for deleted pkg " + app);
try {
data.writeEntityHeader(app, -1);
} catch (IOException e) {
- Log.e(TAG, "Unable to write package deletions!");
+ Slog.e(TAG, "Unable to write package deletions!");
return;
}
}
} catch (IOException e) {
// Real error writing data
- Log.e(TAG, "Unable to write package backup data file!");
+ Slog.e(TAG, "Unable to write package backup data file!");
return;
}
// Finally, write the new state blob -- just the list of all apps we handled
writeStateFile(mAllPackages, newState);
}
+
+ private static void writeEntity(BackupDataOutput data, String key, byte[] bytes)
+ throws IOException {
+ data.writeEntityHeader(key, bytes.length);
+ data.writeEntityData(bytes, bytes.length);
+ }
// "Restore" here is a misnomer. What we're really doing is reading back the
// set of app signatures associated with each backed-up app in this restore
@@ -238,47 +254,53 @@ public class PackageManagerBackupAgent extends BackupAgent {
throws IOException {
List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
- if (DEBUG) Log.v(TAG, "onRestore()");
+ if (DEBUG) Slog.v(TAG, "onRestore()");
int storedSystemVersion = -1;
while (data.readNextHeader()) {
String key = data.getKey();
int dataSize = data.getDataSize();
- if (DEBUG) Log.v(TAG, " got key=" + key + " dataSize=" + dataSize);
+ if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize);
// generic setup to parse any entity data
- byte[] dataBuf = new byte[dataSize];
- data.readEntityData(dataBuf, 0, dataSize);
- ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
- DataInputStream in = new DataInputStream(baStream);
+ byte[] inputBytes = new byte[dataSize];
+ data.readEntityData(inputBytes, 0, dataSize);
+ ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes);
+ DataInputStream inputBufferStream = new DataInputStream(inputBuffer);
if (key.equals(GLOBAL_METADATA_KEY)) {
- int storedSdkVersion = in.readInt();
- if (DEBUG) Log.v(TAG, " storedSystemVersion = " + storedSystemVersion);
+ int storedSdkVersion = inputBufferStream.readInt();
+ if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion);
if (storedSystemVersion > Build.VERSION.SDK_INT) {
// returning before setting the sig map means we rejected the restore set
- Log.w(TAG, "Restore set was from a later version of Android; not restoring");
+ Slog.w(TAG, "Restore set was from a later version of Android; not restoring");
return;
}
mStoredSdkVersion = storedSdkVersion;
- mStoredIncrementalVersion = in.readUTF();
+ mStoredIncrementalVersion = inputBufferStream.readUTF();
mHasMetadata = true;
if (DEBUG) {
- Log.i(TAG, "Restore set version " + storedSystemVersion
+ Slog.i(TAG, "Restore set version " + storedSystemVersion
+ " is compatible with OS version " + Build.VERSION.SDK_INT
+ " (" + mStoredIncrementalVersion + " vs "
+ Build.VERSION.INCREMENTAL + ")");
}
} else {
// it's a file metadata record
- int versionCode = in.readInt();
- Signature[] sigs = unflattenSignatureArray(in);
+ int versionCode = inputBufferStream.readInt();
+ Signature[] sigs = readSignatureArray(inputBufferStream);
if (DEBUG) {
- Log.i(TAG, " restored metadata for " + key
+ Slog.i(TAG, " read metadata for " + key
+ " dataSize=" + dataSize
+ " versionCode=" + versionCode + " sigs=" + sigs);
}
+
+ if (sigs == null || sigs.length == 0) {
+ Slog.w(TAG, "Not restoring package " + key
+ + " since it appears to have no signatures.");
+ continue;
+ }
ApplicationInfo app = new ApplicationInfo();
app.packageName = key;
@@ -291,63 +313,50 @@ public class PackageManagerBackupAgent extends BackupAgent {
mRestoredSignatures = sigMap;
}
-
- // Util: convert an array of Signatures into a flattened byte buffer. The
- // flattened format contains enough info to reconstruct the signature array.
- private byte[] flattenSignatureArray(Signature[] allSigs) {
- ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
- DataOutputStream out = new DataOutputStream(outBuf);
-
- // build the set of subsidiary buffers
- try {
- // first the # of signatures in the array
- out.writeInt(allSigs.length);
-
- // then the signatures themselves, length + flattened buffer
- for (Signature sig : allSigs) {
- byte[] flat = sig.toByteArray();
- out.writeInt(flat.length);
- out.write(flat);
- }
- } catch (IOException e) {
- // very strange; we're writing to memory here. abort.
- return null;
+ private static void writeSignatureArray(DataOutputStream out, Signature[] sigs)
+ throws IOException {
+ // write the number of signatures in the array
+ out.writeInt(sigs.length);
+
+ // write the signatures themselves, length + flattened buffer
+ for (Signature sig : sigs) {
+ byte[] flat = sig.toByteArray();
+ out.writeInt(flat.length);
+ out.write(flat);
}
-
- return outBuf.toByteArray();
}
- private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
- Signature[] sigs = null;
-
+ private static Signature[] readSignatureArray(DataInputStream in) {
try {
- int num = in.readInt();
- if (DEBUG) Log.v(TAG, " ... unflatten read " + num);
-
+ int num;
+ try {
+ num = in.readInt();
+ } catch (EOFException e) {
+ // clean termination
+ Slog.w(TAG, "Read empty signature block");
+ return null;
+ }
+
+ if (DEBUG) Slog.v(TAG, " ... unflatten read " + num);
+
// Sensical?
if (num > 20) {
- Log.e(TAG, "Suspiciously large sig count in restore data; aborting");
+ Slog.e(TAG, "Suspiciously large sig count in restore data; aborting");
throw new IllegalStateException("Bad restore state");
}
-
- sigs = new Signature[num];
+
+ Signature[] sigs = new Signature[num];
for (int i = 0; i < num; i++) {
int len = in.readInt();
byte[] flatSig = new byte[len];
in.read(flatSig);
sigs[i] = new Signature(flatSig);
}
- } catch (EOFException e) {
- // clean termination
- if (sigs == null) {
- Log.w(TAG, "Empty signature block found");
- }
+ return sigs;
} catch (IOException e) {
- Log.e(TAG, "Unable to unflatten sigs");
+ Slog.e(TAG, "Unable to read signatures");
return null;
}
-
- return sigs;
}
// Util: parse out an existing state file into a usable structure
@@ -373,7 +382,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
mStoredIncrementalVersion = in.readUTF();
mExisting.add(GLOBAL_METADATA_KEY);
} else {
- Log.e(TAG, "No global metadata in state file!");
+ Slog.e(TAG, "No global metadata in state file!");
return;
}
@@ -388,7 +397,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
// safe; we're done
} catch (IOException e) {
// whoops, bad state file. abort.
- Log.e(TAG, "Unable to read Package Manager state file: " + e);
+ Slog.e(TAG, "Unable to read Package Manager state file: " + e);
}
}
@@ -409,7 +418,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
out.writeInt(pkg.versionCode);
}
} catch (IOException e) {
- Log.e(TAG, "Unable to write package manager state file!");
+ Slog.e(TAG, "Unable to write package manager state file!");
return;
}
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cc78300..6aa1cbf 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -16,8 +16,11 @@
package com.android.server;
+import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.PackageHelper;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -26,11 +29,15 @@ import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.content.ComponentName;
+import android.app.admin.IDevicePolicyManager;
+import android.app.backup.IBackupManager;
import android.content.Context;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.ServiceConnection;
import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -40,16 +47,16 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInfoLite;
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;
@@ -61,7 +68,9 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -75,6 +84,8 @@ import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.provider.Settings;
+import android.security.SystemKeyStore;
import android.util.*;
import android.view.Display;
import android.view.WindowManager;
@@ -89,11 +100,14 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -106,10 +120,24 @@ import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
+/**
+ * Keep track of all those .apks everywhere.
+ *
+ * This is very central to the platform's security; please run the unit
+ * tests whenever making modifications here:
+ *
+mmm frameworks/base/tests/AndroidTests
+adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
+adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
+ *
+ */
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 DEBUG_UPGRADE = false;
+ private static final boolean DEBUG_INSTALL = false;
+ private static final boolean DEBUG_NATIVE = false;
private static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
@@ -128,20 +156,36 @@ class PackageManagerService extends IPackageManager.Stub {
FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
+ // Suffix used during package installation when copying/moving
+ // package apks to install directory.
+ private static final String INSTALL_PACKAGE_SUFFIX = "-";
+
+ /**
+ * Indicates the state of installation. Used by PackageManager to
+ * figure out incomplete installations. Say a package is being installed
+ * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till
+ * the package installation is successful or unsuccesful lin which case
+ * the PackageManager will no longer maintain state information associated
+ * with the package. If some exception(like device freeze or battery being
+ * pulled out) occurs during installation of a package, the PackageManager
+ * needs this information to clean up the previously failed installation.
+ */
+ private static final int PKG_INSTALL_INCOMPLETE = 0;
+ private static final int PKG_INSTALL_COMPLETE = 1;
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 SCAN_NEW_INSTALL = 1<<5;
-
- 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;
+ static final int SCAN_NEW_INSTALL = 1<<4;
+ static final int SCAN_NO_PATHS = 1<<5;
+ static final int REMOVE_CHATTY = 1<<16;
+
+ static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ "com.android.defcontainer",
+ "com.android.defcontainer.DefaultContainerService");
+
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
Process.THREAD_PRIORITY_BACKGROUND);
final PackageHandler mHandler;
@@ -149,7 +193,7 @@ class PackageManagerService extends IPackageManager.Stub {
final int mSdkVersion = Build.VERSION.SDK_INT;
final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
? null : Build.VERSION.CODENAME;
-
+
final Context mContext;
final boolean mFactoryTest;
final boolean mNoDexOpt;
@@ -175,7 +219,7 @@ class PackageManagerService extends IPackageManager.Stub {
// 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;
@@ -184,14 +228,14 @@ class PackageManagerService extends IPackageManager.Stub {
// 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.
@@ -205,7 +249,7 @@ class PackageManagerService extends IPackageManager.Stub {
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".
@@ -214,7 +258,6 @@ class PackageManagerService extends IPackageManager.Stub {
final Settings mSettings;
boolean mRestoredSettings;
- boolean mReportedUidError;
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids;
@@ -223,19 +266,19 @@ class PackageManagerService extends IPackageManager.Stub {
// 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>();
-
+
// Temporary for building the final shared libraries for an .apk.
String[] mTmpSharedLibraries = null;
-
+
// These are the features this devices supports that were read from the
// etc/permissions.xml file.
final HashMap<String, FeatureInfo> mAvailableFeatures =
new HashMap<String, FeatureInfo>();
-
+
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
@@ -264,9 +307,13 @@ class PackageManagerService extends IPackageManager.Stub {
final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
new HashMap<String, PackageParser.PermissionGroup>();
+ // Packages whose data we have transfered into another package, thus
+ // should no longer exist.
+ final HashSet<String> mTransferedPackages = new HashSet<String>();
+
// Broadcast actions that are only available to the system.
final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
-
+
boolean mSystemReady;
boolean mSafeMode;
boolean mHasSystemUidErrors;
@@ -280,21 +327,201 @@ class PackageManagerService extends IPackageManager.Stub {
// Set of pending broadcasts for aggregating enable/disable of components.
final HashMap<String, ArrayList<String>> mPendingBroadcasts
= new HashMap<String, ArrayList<String>>();
+ // Service Connection to remote media container service to copy
+ // package uri's from external media onto secure containers
+ // or internal storage.
+ private IMediaContainerService mContainerService = null;
+
static final int SEND_PENDING_BROADCAST = 1;
+ static final int MCS_BOUND = 3;
+ static final int END_COPY = 4;
+ static final int INIT_COPY = 5;
+ static final int MCS_UNBIND = 6;
+ static final int START_CLEANING_PACKAGE = 7;
+ static final int FIND_INSTALL_LOC = 8;
+ static final int POST_INSTALL = 9;
+ static final int MCS_RECONNECT = 10;
+ static final int MCS_GIVE_UP = 11;
+ static final int UPDATED_MEDIA_STATUS = 12;
+ static final int WRITE_SETTINGS = 13;
+
+ static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
+
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
+ final private DefaultContainerConnection mDefContainerConn =
+ new DefaultContainerConnection();
+ class DefaultContainerConnection implements ServiceConnection {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
+ IMediaContainerService imcs =
+ IMediaContainerService.Stub.asInterface(service);
+ mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
+ }
+ };
+
+ // Recordkeeping of restore-after-install operations that are currently in flight
+ // between the Package Manager and the Backup Manager
+ class PostInstallData {
+ public InstallArgs args;
+ public PackageInstalledInfo res;
+
+ PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
+ args = _a;
+ res = _r;
+ }
+ };
+ final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
+ int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
class PackageHandler extends Handler {
+ private boolean mBound = false;
+ final ArrayList<HandlerParams> mPendingInstalls =
+ new ArrayList<HandlerParams>();
+
+ private boolean connectToService() {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +
+ " DefaultContainerService");
+ Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ if (mContext.bindService(service, mDefContainerConn,
+ Context.BIND_AUTO_CREATE)) {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ mBound = true;
+ return true;
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ return false;
+ }
+
+ private void disconnectService() {
+ mContainerService = null;
+ mBound = false;
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ mContext.unbindService(mDefContainerConn);
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
+
PackageHandler(Looper looper) {
super(looper);
}
+
public void handleMessage(Message msg) {
+ try {
+ doHandleMessage(msg);
+ } finally {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
+ }
+
+ void doHandleMessage(Message msg) {
switch (msg.what) {
+ case INIT_COPY: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
+ HandlerParams params = (HandlerParams) msg.obj;
+ int idx = mPendingInstalls.size();
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);
+ // If a bind was already initiated we dont really
+ // need to do anything. The pending install
+ // will be processed later on.
+ if (!mBound) {
+ // If this is the only one pending we might
+ // have to bind to the service again.
+ if (!connectToService()) {
+ Slog.e(TAG, "Failed to bind to media container service");
+ params.serviceError();
+ return;
+ } else {
+ // Once we bind to the service, the first
+ // pending request will be processed.
+ mPendingInstalls.add(idx, params);
+ }
+ } else {
+ mPendingInstalls.add(idx, params);
+ // Already bound to the service. Just make
+ // sure we trigger off processing the first request.
+ if (idx == 0) {
+ mHandler.sendEmptyMessage(MCS_BOUND);
+ }
+ }
+ break;
+ }
+ case MCS_BOUND: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");
+ if (msg.obj != null) {
+ mContainerService = (IMediaContainerService) msg.obj;
+ }
+ if (mContainerService == null) {
+ // Something seriously wrong. Bail out
+ Slog.e(TAG, "Cannot bind to media container service");
+ for (HandlerParams params : mPendingInstalls) {
+ mPendingInstalls.remove(0);
+ // Indicate service bind error
+ params.serviceError();
+ }
+ mPendingInstalls.clear();
+ } else if (mPendingInstalls.size() > 0) {
+ HandlerParams params = mPendingInstalls.get(0);
+ if (params != null) {
+ params.startCopy();
+ }
+ } else {
+ // Should never happen ideally.
+ Slog.w(TAG, "Empty queue");
+ }
+ break;
+ }
+ case MCS_RECONNECT : {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_reconnect");
+ if (mPendingInstalls.size() > 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ if (!connectToService()) {
+ Slog.e(TAG, "Failed to bind to media container service");
+ for (HandlerParams params : mPendingInstalls) {
+ mPendingInstalls.remove(0);
+ // Indicate service bind error
+ params.serviceError();
+ }
+ mPendingInstalls.clear();
+ }
+ }
+ break;
+ }
+ case MCS_UNBIND : {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_unbind");
+ // Delete pending install
+ if (mPendingInstalls.size() > 0) {
+ mPendingInstalls.remove(0);
+ }
+ if (mPendingInstalls.size() == 0) {
+ if (mBound) {
+ disconnectService();
+ }
+ } else {
+ // There are more pending requests in queue.
+ // Just post MCS_BOUND message to trigger processing
+ // of next pending install.
+ mHandler.sendEmptyMessage(MCS_BOUND);
+ }
+ break;
+ }
+ case MCS_GIVE_UP: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries");
+ HandlerParams params = mPendingInstalls.remove(0);
+ break;
+ }
case SEND_PENDING_BROADCAST : {
String packages[];
ArrayList components[];
int size = 0;
int uids[];
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
if (mPendingBroadcasts == null) {
return;
@@ -326,11 +553,130 @@ class PackageManagerService extends IPackageManager.Stub {
sendPackageChangedBroadcast(packages[i], true,
(ArrayList<String>)components[i], uids[i]);
}
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
}
+ case START_CLEANING_PACKAGE: {
+ String packageName = (String)msg.obj;
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPackages) {
+ if (!mSettings.mPackagesToBeCleaned.contains(packageName)) {
+ mSettings.mPackagesToBeCleaned.add(packageName);
+ }
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ startCleaningPackages();
+ } break;
+ case POST_INSTALL: {
+ if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
+ PostInstallData data = mRunningInstalls.get(msg.arg1);
+ mRunningInstalls.delete(msg.arg1);
+ boolean deleteOld = false;
+
+ if (data != null) {
+ InstallArgs args = data.args;
+ PackageInstalledInfo res = data.res;
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ res.removedInfo.sendBroadcast(false, true);
+ Bundle extras = new Bundle(1);
+ extras.putInt(Intent.EXTRA_UID, res.uid);
+ final boolean update = res.removedInfo.removedPackage != null;
+ if (update) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ res.pkg.applicationInfo.packageName,
+ extras, null);
+ if (update) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ res.pkg.applicationInfo.packageName,
+ extras, null);
+ }
+ if (res.removedInfo.args != null) {
+ // Remove the replaced package's older resources safely now
+ deleteOld = true;
+ }
+ }
+ // Force a gc to clear up things
+ Runtime.getRuntime().gc();
+ // We delete after a gc for applications on sdcard.
+ if (deleteOld) {
+ synchronized (mInstallLock) {
+ res.removedInfo.args.doPostDeleteLI(true);
+ }
+ }
+ if (args.observer != null) {
+ try {
+ args.observer.packageInstalled(res.name, res.returnCode);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ } else {
+ Slog.e(TAG, "Bogus post-install token " + msg.arg1);
+ }
+ } break;
+ case UPDATED_MEDIA_STATUS: {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
+ boolean reportStatus = msg.arg1 == 1;
+ boolean doGc = msg.arg2 == 1;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
+ if (doGc) {
+ // Force a gc to clear up stale containers.
+ Runtime.getRuntime().gc();
+ }
+ if (msg.obj != null) {
+ Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
+ // Unload containers
+ unloadAllContainers(args);
+ }
+ if (reportStatus) {
+ try {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
+ PackageHelper.getMountService().finishMediaUpdate();
+ } catch (RemoteException e) {
+ Log.e(TAG, "MountService not running?");
+ }
+ }
+ } break;
+ case WRITE_SETTINGS: {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ synchronized (mPackages) {
+ removeMessages(WRITE_SETTINGS);
+ mSettings.writeLP();
+ }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ } break;
}
}
}
+
+ void scheduleWriteSettingsLocked() {
+ if (!mHandler.hasMessages(WRITE_SETTINGS)) {
+ mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
+ }
+ }
+
+ static boolean installOnSd(int flags) {
+ if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) ||
+ ((flags & PackageManager.INSTALL_INTERNAL) != 0)) {
+ return false;
+ }
+ if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ static boolean isFwdLocked(int flags) {
+ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
+ return true;
+ }
+ return false;
+ }
+
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
ServiceManager.addService("package", m);
@@ -344,7 +690,7 @@ class PackageManagerService extends IPackageManager.Stub {
count++;
i++;
}
-
+
String[] res = new String[count];
i=0;
count = 0;
@@ -358,15 +704,15 @@ class PackageManagerService extends IPackageManager.Stub {
res[count] = str.substring(lastI, str.length());
return res;
}
-
+
public PackageManagerService(Context context, boolean factoryTest) {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_START,
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
-
+
if (mSdkVersion <= 0) {
- Log.w(TAG, "**** ro.build.version.sdk not set!");
+ Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
-
+
mContext = context;
mFactoryTest = factoryTest;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
@@ -388,18 +734,18 @@ class PackageManagerService extends IPackageManager.Stub {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
- Log.w(TAG, "Running with debug.separate_processes: * (ALL)");
+ Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
- Log.w(TAG, "Running with debug.separate_processes: "
+ Slog.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
@@ -419,7 +765,7 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
-
+
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
@@ -438,24 +784,26 @@ class PackageManagerService extends IPackageManager.Stub {
mRestoredSettings = mSettings.readLP();
long startTime = SystemClock.uptimeMillis();
-
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
+
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
-
- int scanMode = SCAN_MONITOR;
+
+ // Set flag to monitor and not change apk file paths when
+ // scanning install directories.
+ int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
if (mNoDexOpt) {
- Log.w(TAG, "Running ENG build: no pre-dexopt!");
- scanMode |= SCAN_NO_DEX;
+ Slog.w(TAG, "Running ENG build: no pre-dexopt!");
+ scanMode |= SCAN_NO_DEX;
}
-
+
final HashSet<String> libFiles = new HashSet<String>();
-
+
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
mDalvikCacheDir = new File(dataDir, "dalvik-cache");
-
+
if (mInstaller != null) {
boolean didDexOpt = false;
-
+
/**
* Out of paranoia, ensure that everything in the boot class
* path has been dexed.
@@ -471,15 +819,15 @@ class PackageManagerService extends IPackageManager.Stub {
didDexOpt = true;
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "Boot class path not found: " + paths[i]);
+ Slog.w(TAG, "Boot class path not found: " + paths[i]);
} catch (IOException e) {
- Log.w(TAG, "Exception reading boot class path: " + paths[i], e);
+ Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
}
}
} else {
- Log.w(TAG, "No BOOTCLASSPATH found!");
+ Slog.w(TAG, "No BOOTCLASSPATH found!");
}
-
+
/**
* Also ensure all external libraries have had dexopt run on them.
*/
@@ -494,17 +842,17 @@ class PackageManagerService extends IPackageManager.Stub {
didDexOpt = true;
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "Library not found: " + lib);
+ Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
- Log.w(TAG, "Exception reading library: " + lib, e);
+ Slog.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
@@ -529,13 +877,13 @@ class PackageManagerService extends IPackageManager.Stub {
didDexOpt = true;
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "Jar not found: " + path);
+ Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
- Log.w(TAG, "Exception reading jar: " + path, e);
+ Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
-
+
if (didDexOpt) {
// If we had to do a dexopt of one of the previous
// things, then something on the system has changed.
@@ -548,24 +896,52 @@ class PackageManagerService extends IPackageManager.Stub {
String fn = files[i];
if (fn.startsWith("data@app@")
|| fn.startsWith("data@app-private@")) {
- Log.i(TAG, "Pruning dalvik file: " + fn);
+ Slog.i(TAG, "Pruning dalvik file: " + fn);
(new File(mDalvikCacheDir, fn)).delete();
}
}
}
}
}
-
+
+ // Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
- scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
+ scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
scanMode | SCAN_NO_DEX);
+
+ // Collect all system packages.
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
- scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
+ scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);
+
+ if (mInstaller != null) {
+ if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
+ mInstaller.moveFiles();
+ }
+
+ // Prune any system packages that no longer exist.
+ Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+ while (psit.hasNext()) {
+ PackageSetting ps = psit.next();
+ if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
+ && !mPackages.containsKey(ps.name)
+ && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
+ psit.remove();
+ String msg = "System package " + ps.name
+ + " no longer exists; wiping its data";
+ reportSettingsProblem(Log.WARN, msg);
+ if (mInstaller != null) {
+ mInstaller.remove(ps.name);
+ }
+ }
+ }
+
mAppInstallDir = new File(dataDir, "app");
if (mInstaller == null) {
// Make sure these dirs exist, when we are running in
@@ -581,8 +957,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
//delete tmp files
deleteTempPackageFiles();
-
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_DATA_SCAN_START,
+
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
@@ -592,21 +968,34 @@ class PackageManagerService extends IPackageManager.Stub {
mDrmAppInstallObserver = new AppDirObserver(
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
mDrmAppInstallObserver.startWatching();
- scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode | SCAN_FORWARD_LOCKED);
+ scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SCAN_END,
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
- Log.i(TAG, "Time to scan packages: "
+ Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
- updatePermissionsLP();
+ // If the platform SDK has changed since the last time we booted,
+ // we need to re-grant app permission to catch any new ones that
+ // appear. This is really a hack, and means that apps can in some
+ // cases get permissions that the user didn't initially explicitly
+ // allow... it would be nice to have some better way to handle
+ // this situation.
+ final boolean regrantPermissions = mSettings.mInternalSdkPlatform
+ != mSdkVersion;
+ if (regrantPermissions) Slog.i(TAG, "Platform changed from "
+ + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ + "; regranting permissions for internal storage");
+ mSettings.mInternalSdkPlatform = mSdkVersion;
+
+ updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
mSettings.writeLP();
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_READY,
+ EventLog.writeEvent(EventLogTags.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.
@@ -622,18 +1011,18 @@ class PackageManagerService extends IPackageManager.Stub {
return super.onTransact(code, data, reply, flags);
} catch (RuntimeException e) {
if (!(e instanceof SecurityException) && !(e instanceof IllegalArgumentException)) {
- Log.e(TAG, "Package Manager Crash", e);
+ Slog.e(TAG, "Package Manager Crash", e);
}
throw e;
}
}
void cleanupInstallFailedPackage(PackageSetting ps) {
- Log.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
+ Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
if (mInstaller != null) {
int retCode = mInstaller.remove(ps.name);
if (retCode < 0) {
- Log.w(TAG, "Couldn't remove app data directory for package: "
+ Slog.w(TAG, "Couldn't remove app data directory for package: "
+ ps.name + ", retcode=" + retCode);
}
} else {
@@ -644,12 +1033,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
- Log.w(TAG, "Unable to remove old code file: " + ps.codePath);
+ Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
}
}
if (ps.resourcePath != null) {
if (!ps.resourcePath.delete() && !ps.resourcePath.equals(ps.codePath)) {
- Log.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
+ Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
}
}
mSettings.removePackageLP(ps.name);
@@ -659,11 +1048,11 @@ class PackageManagerService extends IPackageManager.Stub {
// 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");
+ Slog.w(TAG, "No directory " + libraryDir + ", skipping");
return;
}
if (!libraryDir.canRead()) {
- Log.w(TAG, "Directory " + libraryDir + " cannot be read");
+ Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
@@ -673,24 +1062,24 @@ class PackageManagerService extends IPackageManager.Stub {
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");
+ Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
- Log.w(TAG, "Permissions library file " + f + " cannot be read");
+ Slog.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);
-
+
StringBuilder sb = new StringBuilder(128);
sb.append("Libs:");
Iterator<String> it = mSharedLibraries.keySet().iterator();
@@ -702,7 +1091,7 @@ class PackageManagerService extends IPackageManager.Stub {
sb.append(mSharedLibraries.get(name));
}
Log.i(TAG, sb.toString());
-
+
sb.setLength(0);
sb.append("Features:");
it = mAvailableFeatures.keySet().iterator();
@@ -712,13 +1101,13 @@ class PackageManagerService extends IPackageManager.Stub {
}
Log.i(TAG, sb.toString());
}
-
- private void readPermissionsFromXml(File 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);
+ Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
@@ -741,7 +1130,7 @@ class PackageManagerService extends IPackageManager.Stub {
int gid = Integer.parseInt(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);
} else {
- Log.w(TAG, "<group> without gid at "
+ Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
@@ -750,32 +1139,32 @@ class PackageManagerService extends IPackageManager.Stub {
} else if ("permission".equals(name)) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
- Log.w(TAG, "<permission> without name at "
+ Slog.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 "
+ Slog.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 "
+ Slog.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 \""
+ Slog.w(TAG, "<assign-permission> with unknown uid \""
+ uidStr + "\" at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
@@ -789,15 +1178,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
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 "
+ Slog.w(TAG, "<library> without name at "
+ parser.getPositionDescription());
} else if (lfile == null) {
- Log.w(TAG, "<library> without file at "
+ Slog.w(TAG, "<library> without file at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
@@ -805,11 +1194,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
XmlUtils.skipCurrentTag(parser);
continue;
-
+
} else if ("feature".equals(name)) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
- Log.w(TAG, "<feature> without name at "
+ Slog.w(TAG, "<feature> without name at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got feature " + fname);
@@ -819,7 +1208,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
XmlUtils.skipCurrentTag(parser);
continue;
-
+
} else {
XmlUtils.skipCurrentTag(parser);
continue;
@@ -827,9 +1216,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
} catch (XmlPullParserException e) {
- Log.w(TAG, "Got execption parsing permissions.", e);
+ Slog.w(TAG, "Got execption parsing permissions.", e);
} catch (IOException e) {
- Log.w(TAG, "Got execption parsing permissions.", e);
+ Slog.w(TAG, "Got execption parsing permissions.", e);
}
}
@@ -860,7 +1249,7 @@ class PackageManagerService extends IPackageManager.Stub {
int gid = Process.getGidForName(gidStr);
bp.gids = appendInt(bp.gids, gid);
} else {
- Log.w(TAG, "<group> without gid at "
+ Slog.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
}
@@ -894,6 +1283,36 @@ class PackageManagerService extends IPackageManager.Stub {
return cur;
}
+ static int[] removeInt(int[] cur, int val) {
+ if (cur == null) {
+ return null;
+ }
+ final int N = cur.length;
+ for (int i=0; i<N; i++) {
+ if (cur[i] == val) {
+ int[] ret = new int[N-1];
+ if (i > 0) {
+ System.arraycopy(cur, 0, ret, 0, i);
+ }
+ if (i < (N-1)) {
+ System.arraycopy(cur, i + 1, ret, i, N - i - 1);
+ }
+ return ret;
+ }
+ }
+ return cur;
+ }
+
+ static int[] removeInts(int[] cur, int[] rem) {
+ if (rem == null) return cur;
+ if (cur == null) return cur;
+ final int N = rem.length;
+ for (int i=0; i<N; i++) {
+ cur = removeInt(cur, rem[i]);
+ }
+ return cur;
+ }
+
PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
// The package has been uninstalled but has retained data and resources.
@@ -923,6 +1342,28 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
+ public String[] currentToCanonicalPackageNames(String[] names) {
+ String[] out = new String[names.length];
+ synchronized (mPackages) {
+ for (int i=names.length-1; i>=0; i--) {
+ PackageSetting ps = mSettings.mPackages.get(names[i]);
+ out[i] = ps != null && ps.realName != null ? ps.realName : names[i];
+ }
+ }
+ return out;
+ }
+
+ public String[] canonicalToCurrentPackageNames(String[] names) {
+ String[] out = new String[names.length];
+ synchronized (mPackages) {
+ for (int i=names.length-1; i>=0; i--) {
+ String cur = mSettings.mRenamedPackages.get(names[i]);
+ out[i] = cur != null ? cur : names[i];
+ }
+ }
+ return out;
+ }
+
public int getPackageUid(String packageName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -954,11 +1395,24 @@ class PackageManagerService extends IPackageManager.Stub {
return new int[0];
}
+ static final PermissionInfo generatePermissionInfo(
+ BasePermission bp, int flags) {
+ if (bp.perm != null) {
+ return PackageParser.generatePermissionInfo(bp.perm, flags);
+ }
+ PermissionInfo pi = new PermissionInfo();
+ pi.name = bp.name;
+ pi.packageName = bp.sourcePackage;
+ pi.nonLocalizedLabel = bp.name;
+ pi.protectionLevel = bp.protectionLevel;
+ return pi;
+ }
+
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);
+ if (p != null) {
+ return generatePermissionInfo(p, flags);
}
return null;
}
@@ -969,23 +1423,23 @@ class PackageManagerService extends IPackageManager.Stub {
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));
+ if (p.perm == null || p.perm.info.group == null) {
+ out.add(generatePermissionInfo(p, flags));
}
} else {
- if (group.equals(p.perm.info.group)) {
+ if (p.perm != null && 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(
@@ -1004,7 +1458,7 @@ class PackageManagerService extends IPackageManager.Stub {
return out;
}
}
-
+
private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if(ps != null) {
@@ -1019,19 +1473,23 @@ class PackageManagerService extends IPackageManager.Stub {
}
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;
+ ps.pkg.applicationInfo.flags = ps.pkgFlags;
+ ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+ ps.pkg.applicationInfo.sourceDir = ps.codePathString;
+ ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath();
}
return generatePackageInfo(ps.pkg, flags);
}
return null;
}
-
+
public ApplicationInfo getApplicationInfo(String packageName, int flags) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -1051,8 +1509,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
return null;
}
-
-
+
+
public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -1064,14 +1522,14 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller != null) {
retCode = mInstaller.freeCache(freeStorageSize);
if (retCode < 0) {
- Log.w(TAG, "Couldn't clear application caches");
+ Slog.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");
+ Slog.w(TAG, "RemoveException when invoking call back");
}
}
}
@@ -1089,7 +1547,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller != null) {
retCode = mInstaller.freeCache(freeStorageSize);
if (retCode < 0) {
- Log.w(TAG, "Couldn't clear application caches");
+ Slog.w(TAG, "Couldn't clear application caches");
}
}
if(pi != null) {
@@ -1099,13 +1557,13 @@ class PackageManagerService extends IPackageManager.Stub {
pi.sendIntent(null, code, null,
null, null);
} catch (SendIntentException e1) {
- Log.i(TAG, "Failed to send pending intent");
+ Slog.i(TAG, "Failed to send pending intent");
}
}
}
});
}
-
+
public ActivityInfo getActivityInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -1144,7 +1602,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return null;
}
-
+
public String[] getSystemSharedLibraryNames() {
Set<String> libSet;
synchronized (mPackages) {
@@ -1182,7 +1640,7 @@ class PackageManagerService extends IPackageManager.Stub {
return mAvailableFeatures.containsKey(name);
}
}
-
+
public int checkPermission(String permName, String pkgName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(pkgName);
@@ -1204,16 +1662,9 @@ class PackageManagerService extends IPackageManager.Stub {
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;
- }
+ GrantedPermissions gp = (GrantedPermissions)obj;
+ if (gp.grantedPermissions.contains(permName)) {
+ return PackageManager.PERMISSION_GRANTED;
}
} else {
HashSet<String> perms = mSystemPermissions.get(uid);
@@ -1252,31 +1703,84 @@ class PackageManagerService extends IPackageManager.Stub {
throw new SecurityException("No permission tree found for " + permName);
}
+ static boolean compareStrings(CharSequence s1, CharSequence s2) {
+ if (s1 == null) {
+ return s2 == null;
+ }
+ if (s2 == null) {
+ return false;
+ }
+ if (s1.getClass() != s2.getClass()) {
+ return false;
+ }
+ return s1.equals(s2);
+ }
+
+ static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+ if (pi1.icon != pi2.icon) return false;
+ if (pi1.protectionLevel != pi2.protectionLevel) return false;
+ if (!compareStrings(pi1.name, pi2.name)) return false;
+ if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
+ // We'll take care of setting this one.
+ if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+ // These are not currently stored in settings.
+ //if (!compareStrings(pi1.group, pi2.group)) return false;
+ //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
+ //if (pi1.labelRes != pi2.labelRes) return false;
+ //if (pi1.descriptionRes != pi2.descriptionRes) return false;
+ return true;
+ }
+
+ boolean addPermissionLocked(PermissionInfo info, boolean async) {
+ 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;
+ boolean changed = true;
+ 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);
+ } else {
+ if (bp.protectionLevel == info.protectionLevel
+ && bp.perm.owner.equals(tree.perm.owner)
+ && bp.uid == tree.uid
+ && comparePermissionInfos(bp.perm.info, info)) {
+ changed = false;
+ }
+ }
+ bp.protectionLevel = info.protectionLevel;
+ 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);
+ }
+ if (changed) {
+ if (!async) {
+ mSettings.writeLP();
+ } else {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ return added;
+ }
+
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;
+ return addPermissionLocked(info, false);
+ }
+ }
+
+ public boolean addPermissionAsync(PermissionInfo info) {
+ synchronized (mPackages) {
+ return addPermissionLocked(info, true);
}
}
@@ -1301,7 +1805,7 @@ class PackageManagerService extends IPackageManager.Stub {
return mProtectedBroadcasts.contains(actionName);
}
}
-
+
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
PackageParser.Package p1 = mPackages.get(pkg1);
@@ -1355,21 +1859,19 @@ class PackageManagerService extends IPackageManager.Stub {
if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
- final int N1 = s1.length;
- final int N2 = s2.length;
- for (int i=0; i<N1; i++) {
- boolean match = false;
- for (int j=0; j<N2; j++) {
- if (s1[i].equals(s2[j])) {
- match = true;
- break;
- }
- }
- if (!match) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
+ HashSet<Signature> set1 = new HashSet<Signature>();
+ for (Signature sig : s1) {
+ set1.add(sig);
+ }
+ HashSet<Signature> set2 = new HashSet<Signature>();
+ for (Signature sig : s2) {
+ set2.add(sig);
}
- return PackageManager.SIGNATURE_MATCH;
+ // Make sure s2 contains all signatures in s1.
+ if (set1.equals(set2)) {
+ return PackageManager.SIGNATURE_MATCH;
+ }
+ return PackageManager.SIGNATURE_NO_MATCH;
}
public String[] getPackagesForUid(int uid) {
@@ -1406,7 +1908,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return null;
}
-
+
public int getUidForSharedUser(String sharedUserName) {
if(sharedUserName == null) {
return -1;
@@ -1513,7 +2015,7 @@ class PackageManagerService extends IPackageManager.Stub {
// 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 "
+ Slog.i(TAG, "Result set changed, dropping preferred activity for "
+ intent + " type " + resolvedType);
mSettings.mPreferredActivities.removeFilter(pa);
return null;
@@ -1732,7 +2234,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return list;
}
-
+
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
@@ -1790,7 +2292,7 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
}
-
+
public List<PackageInfo> getInstalledPackages(int flags) {
ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
@@ -1970,24 +2472,37 @@ class PackageManagerService extends IPackageManager.Stub {
int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);
- File resFile = file;
- // Pick up the resource path from settings for fwd locked apps
- if ((scanMode & SCAN_FORWARD_LOCKED) != 0) {
- resFile = null;
+ if (!isPackageFilename(files[i])) {
+ // Ignore entries which are not apk's
+ continue;
}
- PackageParser.Package pkg = scanPackageLI(file, file, resFile,
+ PackageParser.Package pkg = scanPackageLI(file,
flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
+ // Don't mess around with apps in system partition.
+ if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
+ mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
+ // Delete the apk
+ Slog.w(TAG, "Cleaning up failed install of " + file);
+ file.delete();
+ }
}
}
+ private static File getSettingsProblemFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "uiderrors.txt");
+ return fname;
+ }
+
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");
+ File fname = getSettingsProblemFile();
FileOutputStream out = new FileOutputStream(fname, true);
PrintWriter pw = new PrintWriter(out);
- pw.println(msg);
+ SimpleDateFormat formatter = new SimpleDateFormat();
+ String dateString = formatter.format(new Date(System.currentTimeMillis()));
+ pw.println(dateString + ": " + msg);
pw.close();
FileUtils.setPermissions(
fname.toString(),
@@ -1995,68 +2510,91 @@ class PackageManagerService extends IPackageManager.Stub {
-1, -1);
} catch (java.io.IOException e) {
}
- Log.println(priority, TAG, msg);
+ Slog.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;
+ if (ps != null
+ && ps.codePath.equals(srcFile)
+ && ps.getTimeStamp() == srcFile.lastModified()) {
+ if (ps.signatures.mSignatures != null
+ && ps.signatures.mSignatures.length != 0) {
+ // Optimization: reuse the existing cached certificates
+ // if the package appears to be unchanged.
+ pkg.mSignatures = ps.signatures.mSignatures;
+ return true;
}
+
+ Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
+ } else {
+ 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) {
+ int parseFlags, int scanMode) {
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+ String scanPath = scanFile.getPath();
parseFlags |= mDefParseFlags;
- PackageParser pp = new PackageParser(scanFile.getPath());
+ PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
- destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
+ scanPath, mMetrics, parseFlags);
if (pkg == null) {
mLastScanError = pp.getParseError();
return null;
}
- PackageSetting ps;
+ PackageSetting ps = null;
PackageSetting updatedPkg;
synchronized (mPackages) {
- ps = mSettings.peekPackageLP(pkg.packageName);
- updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
- }
- // Verify certificates first
- if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
- Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
- return null;
- }
- 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 ((ps != null) && (!ps.codePath.equals(scanFile))) {
+ // Look to see if we already know about this package.
+ String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
+ if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
+ // This package has been renamed to its original name. Let's
+ // use that.
+ ps = mSettings.peekPackageLP(oldName);
+ }
+ // If there was no original package, see one for the real package name.
+ if (ps == null) {
+ ps = mSettings.peekPackageLP(pkg.packageName);
+ }
+ // Check to see if this package could be hiding/updating a system
+ // package. Must look for it either under the original or real
+ // package name depending on our state.
+ updatedPkg = mSettings.mDisabledSysPackages.get(
+ ps != null ? ps.name : pkg.packageName);
+ }
+ // First check if this is a system package that may involve an update
+ if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+ if (!ps.codePath.equals(scanFile)) {
+ // The path has changed from what was last scanned... check the
+ // version of the new path against what we have stored to determine
+ // what to do.
if (pkg.mVersionCode < ps.versionCode) {
// 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);
+ // Ignore entry. Skip it.
+ Log.i(TAG, "Package " + ps.name + " at " + scanFile
+ + "ignored: updated version " + ps.versionCode
+ + " better than this " + pkg.mVersionCode);
mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
return null;
} else {
- // Delete the older apk pointed to by ps
+ // The current app on the system partion is better than
+ // what we have updated to on the data partition; switch
+ // back to the system partition version.
// At this point, its safely assumed that package installation for
// apps in system partition will go through. If not there won't be a working
// version of the app
@@ -2064,23 +2602,57 @@ class PackageManagerService extends IPackageManager.Stub {
// Just remove the loaded entries from package lists.
mPackages.remove(ps.name);
}
- deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
+ Slog.w(TAG, "Package " + ps.name + " at " + scanFile
+ + "reverting from " + ps.codePathString
+ + ": new version " + pkg.mVersionCode
+ + " better than installed " + ps.versionCode);
+ InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString);
+ args.cleanUpResourcesLI();
+ removeNativeBinariesLI(pkg);
mSettings.enableSystemPackageLP(ps.name);
}
}
}
+ if (updatedPkg != null) {
+ // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
+ parseFlags |= PackageParser.PARSE_IS_SYSTEM;
+ }
+ // Verify certificates against what was last scanned
+ if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
+ Slog.w(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.
+ // TODO grab this value from PackageSettings
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
- scanMode |= SCAN_FORWARD_LOCKED;
+ parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
}
- File resFile = destResourceFile;
- if (ps != null && ((scanMode & SCAN_FORWARD_LOCKED) != 0)) {
- resFile = getFwdLockedResource(ps.name);
+
+ String codePath = null;
+ String resPath = null;
+ if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {
+ if (ps != null && ps.resourcePathString != null) {
+ resPath = ps.resourcePathString;
+ } else {
+ // Should not happen at all. Just log an error.
+ Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
+ }
+ } else {
+ resPath = pkg.mScanPath;
}
+ codePath = pkg.mScanPath;
+ // Set application objects path explicitly.
+ setApplicationInfoPaths(pkg, codePath, resPath);
// Note that we invoke the following method only if we are about to unpack an application
- return scanPackageLI(scanFile, destCodeFile, resFile,
- pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
+ return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
+ }
+
+ private static void setApplicationInfoPaths(PackageParser.Package pkg,
+ String destCodePath, String destResPath) {
+ pkg.mPath = pkg.mScanPath = destCodePath;
+ pkg.applicationInfo.sourceDir = destCodePath;
+ pkg.applicationInfo.publicSourceDir = destResPath;
}
private static String fixProcessName(String defProcessName,
@@ -2091,38 +2663,37 @@ class PackageManagerService extends IPackageManager.Stub {
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;
+ private boolean verifySignaturesLP(PackageSetting pkgSetting,
+ PackageParser.Package pkg) {
+ if (pkgSetting.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
+ PackageManager.SIGNATURE_MATCH) {
+ Slog.e(TAG, "Package " + pkg.packageName
+ + " signatures do not match the previously installed version; ignoring!");
+ mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
return false;
}
+ }
+ // Check for shared user signatures
+ if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
+ if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ Slog.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;
}
-
+
public boolean performDexOpt(String packageName) {
if (!mNoDexOpt) {
return false;
}
-
+
PackageParser.Package p;
synchronized (mPackages) {
p = mPackages.get(packageName);
@@ -2134,11 +2705,11 @@ class PackageManagerService extends IPackageManager.Stub {
return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
}
}
-
+
static final int DEX_OPT_SKIPPED = 0;
static final int DEX_OPT_PERFORMED = 1;
static final int DEX_OPT_FAILED = -1;
-
+
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 && mInstaller != null) {
@@ -2146,16 +2717,22 @@ class PackageManagerService extends IPackageManager.Stub {
int ret = 0;
try {
if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
- ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
- !pkg.mForwardLocked);
+ ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
+ !isForwardLocked(pkg));
pkg.mDidDexOpt = true;
performed = true;
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "Apk not found for dexopt: " + path);
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
ret = -1;
} catch (IOException e) {
- Log.w(TAG, "Exception reading apk: " + path, e);
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ ret = -1;
+ } catch (dalvik.system.StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ ret = -1;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
ret = -1;
}
if (ret < 0) {
@@ -2163,36 +2740,60 @@ class PackageManagerService extends IPackageManager.Stub {
return DEX_OPT_FAILED;
}
}
-
+
return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
}
- private PackageParser.Package scanPackageLI(
- File scanFile, File destCodeFile, File destResourceFile,
- PackageParser.Package pkg, int parseFlags, int scanMode) {
+ private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) {
+ if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Slog.w(TAG, "Unable to update from " + oldPkg.name
+ + " to " + newPkg.packageName
+ + ": old package not in system partition");
+ return false;
+ } else if (mPackages.get(oldPkg.name) != null) {
+ Slog.w(TAG, "Unable to update from " + oldPkg.name
+ + " to " + newPkg.packageName
+ + ": old package still exists");
+ return false;
+ }
+ return true;
+ }
+ private File getDataPathForPackage(PackageParser.Package pkg) {
+ return new File(mAppDataDir, pkg.packageName);
+ }
+
+ private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
+ int parseFlags, int scanMode) {
+ File scanFile = new File(pkg.mScanPath);
+ if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
+ pkg.applicationInfo.publicSourceDir == null) {
+ // Bail out. The resource and code paths haven't been set.
+ Slog.w(TAG, " Code and resource paths haven't been set correctly");
+ mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK;
+ return null;
+ }
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")) {
+ if (pkg.packageName.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, "*************************************************");
+ Slog.w(TAG, "*************************************************");
+ Slog.w(TAG, "Core android package being redefined. Skipping.");
+ Slog.w(TAG, " file=" + mScanningPath);
+ Slog.w(TAG, "*************************************************");
mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
return null;
}
-
+
// Set up information for our fall-back user intent resolution
// activity.
mPlatformPackage = pkg;
@@ -2217,20 +2818,30 @@ class PackageManagerService extends IPackageManager.Stub {
}
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
+ TAG, "Scanning package " + pkg.packageName);
+ if (mPackages.containsKey(pkg.packageName)
+ || mSharedLibraries.containsKey(pkg.packageName)) {
+ Slog.w(TAG, "*************************************************");
+ Slog.w(TAG, "Application package " + pkg.packageName
+ " already installed. Skipping duplicate.");
- Log.w(TAG, "*************************************************");
+ Slog.w(TAG, "*************************************************");
mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
return null;
}
+ // Initialize package source and resource directories
+ File destCodeFile = new File(pkg.applicationInfo.sourceDir);
+ File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);
+
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
-
- boolean removeExisting = false;
+
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ // Only system apps can use these features.
+ pkg.mOriginalPackages = null;
+ pkg.mRealPackage = null;
+ pkg.mAdoptPermissions = null;
+ }
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
@@ -2244,7 +2855,7 @@ class PackageManagerService extends IPackageManager.Stub {
for (int i=0; i<N; i++) {
String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
if (file == null) {
- Log.e(TAG, "Package " + pkg.packageName
+ Slog.e(TAG, "Package " + pkg.packageName
+ " requires unavailable shared library "
+ pkg.usesLibraries.get(i) + "; failing!");
mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
@@ -2257,7 +2868,7 @@ class PackageManagerService extends IPackageManager.Stub {
for (int i=0; i<N; i++) {
String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
if (file == null) {
- Log.w(TAG, "Package " + pkg.packageName
+ Slog.w(TAG, "Package " + pkg.packageName
+ " desires unavailable shared library "
+ pkg.usesOptionalLibraries.get(i) + "; ignoring!");
} else {
@@ -2270,7 +2881,7 @@ class PackageManagerService extends IPackageManager.Stub {
System.arraycopy(mTmpSharedLibraries, 0,
pkg.usesLibraryFiles, 0, num);
}
-
+
if (pkg.reqFeatures != null) {
N = pkg.reqFeatures.size();
for (int i=0; i<N; i++) {
@@ -2279,10 +2890,10 @@ class PackageManagerService extends IPackageManager.Stub {
// Don't care.
continue;
}
-
+
if (fi.name != null) {
if (mAvailableFeatures.get(fi.name) == null) {
- Log.e(TAG, "Package " + pkg.packageName
+ Slog.e(TAG, "Package " + pkg.packageName
+ " requires unavailable feature "
+ fi.name + "; failing!");
mLastScanError = PackageManager.INSTALL_FAILED_MISSING_FEATURE;
@@ -2292,12 +2903,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
-
+
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
pkg.applicationInfo.flags, true);
if (suid == null) {
- Log.w(TAG, "Creating application package " + pkgName
+ Slog.w(TAG, "Creating application package " + pkg.packageName
+ " for shared user failed");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
@@ -2308,26 +2919,113 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ if (false) {
+ if (pkg.mOriginalPackages != null) {
+ Log.w(TAG, "WAITING FOR DEBUGGER");
+ Debug.waitForDebugger();
+ Log.i(TAG, "Package " + pkg.packageName + " from original packages"
+ + pkg.mOriginalPackages);
+ }
+ }
+
+ // Check if we are renaming from an original package name.
+ PackageSetting origPackage = null;
+ String realName = null;
+ if (pkg.mOriginalPackages != null) {
+ // This package may need to be renamed to a previously
+ // installed name. Let's check on that...
+ String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
+ if (pkg.mOriginalPackages.contains(renamed)) {
+ // This package had originally been installed as the
+ // original name, and we have already taken care of
+ // transitioning to the new one. Just update the new
+ // one to continue using the old name.
+ realName = pkg.mRealPackage;
+ if (!pkg.packageName.equals(renamed)) {
+ // Callers into this function may have already taken
+ // care of renaming the package; only do it here if
+ // it is not already done.
+ pkg.setPackageName(renamed);
+ }
+
+ } else {
+ for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
+ if ((origPackage=mSettings.peekPackageLP(
+ pkg.mOriginalPackages.get(i))) != null) {
+ // We do have the package already installed under its
+ // original name... should we use it?
+ if (!verifyPackageUpdate(origPackage, pkg)) {
+ // New package is not compatible with original.
+ origPackage = null;
+ continue;
+ } else if (origPackage.sharedUser != null) {
+ // Make sure uid is compatible between packages.
+ if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
+ Slog.w(TAG, "Unable to migrate data from " + origPackage.name
+ + " to " + pkg.packageName + ": old uid "
+ + origPackage.sharedUser.name
+ + " differs from " + pkg.mSharedUserId);
+ origPackage = null;
+ continue;
+ }
+ } else {
+ if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ + pkg.packageName + " to old name " + origPackage.name);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (mTransferedPackages.contains(pkg.packageName)) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " was transferred to another, but its .apk remains");
+ }
+
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
- pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
+ pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.flags, true, false);
if (pkgSetting == null) {
- Log.w(TAG, "Creating application package " + pkgName + " failed");
+ Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
+
+ if (pkgSetting.origPackage != null) {
+ // If we are first transitioning from an original package,
+ // fix up the new package's name now. We need to do this after
+ // looking up the package under its new name, so getPackageLP
+ // can take care of fiddling things correctly.
+ pkg.setPackageName(origPackage.name);
+
+ // File a report about this.
+ String msg = "New package " + pkgSetting.realName
+ + " renamed to replace old package " + pkgSetting.name;
+ reportSettingsProblem(Log.WARN, msg);
+
+ // Make a note of it.
+ mTransferedPackages.add(origPackage.name);
+
+ // No longer need to retain this.
+ pkgSetting.origPackage = null;
+ }
+
+ if (realName != null) {
+ // Make a note of it.
+ mTransferedPackages.add(pkg.packageName);
+ }
+
+ 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;
+
+ if (!verifySignaturesLP(pkgSetting, pkg)) {
+ if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
return null;
}
// The signature has changed, but this package is in the system
@@ -2339,15 +3037,19 @@ class PackageManagerService extends IPackageManager.Stub {
// 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)) {
+ if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return null;
}
}
- removeExisting = true;
+ // File a report about this.
+ String msg = "System package " + pkg.packageName
+ + " signature changed; retaining data.";
+ reportSettingsProblem(Log.WARN, msg);
}
-
+
// Verify that this new package doesn't have any content providers
// that conflict with existing packages. Only do this if the
// package isn't already installed, since we don't want to break
@@ -2357,37 +3059,41 @@ class PackageManagerService extends IPackageManager.Stub {
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProviders.containsKey(names[j])) {
- PackageParser.Provider other = mProviders.get(names[j]);
- Log.w(TAG, "Can't install because provider name " + names[j] +
- " (in package " + pkg.applicationInfo.packageName +
- ") is already used by "
- + ((other != null && other.component != null)
- ? other.component.getPackageName() : "?"));
- mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
- return null;
+ if (p.info.authority != null) {
+ String names[] = p.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ if (mProviders.containsKey(names[j])) {
+ PackageParser.Provider other = mProviders.get(names[j]);
+ Slog.w(TAG, "Can't install because provider name " + names[j] +
+ " (in package " + pkg.applicationInfo.packageName +
+ ") is already used by "
+ + ((other != null && other.getComponentName() != null)
+ ? other.getComponentName().getPackageName() : "?"));
+ mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
+ return null;
+ }
}
}
}
}
}
- 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;
+ final String pkgName = pkg.packageName;
+
+ if (pkg.mAdoptPermissions != null) {
+ // This package wants to adopt ownership of permissions from
+ // another package.
+ for (int i=pkg.mAdoptPermissions.size()-1; i>=0; i--) {
+ String origName = pkg.mAdoptPermissions.get(i);
+ PackageSetting orig = mSettings.peekPackageLP(origName);
+ if (orig != null) {
+ if (verifyPackageUpdate(orig, pkg)) {
+ Slog.i(TAG, "Adopting permissions from "
+ + origName + " to " + pkg.packageName);
+ mSettings.transferPermissions(origName, pkg.packageName);
+ }
}
}
- Log.w(TAG, "System package " + pkg.packageName
- + " signature changed: existing data removed.");
- mLastScanError = PackageManager.INSTALL_SUCCEEDED;
}
long scanFileTime = scanFile.lastModified();
@@ -2397,7 +3103,6 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
- pkg.applicationInfo.publicSourceDir = destResourceFile.toString();
File dataPath;
if (mPlatformPackage == pkg) {
@@ -2406,7 +3111,10 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
// This is a normal package, need to make its data directory.
- dataPath = new File(mAppDataDir, pkgName);
+ dataPath = getDataPathForPackage(pkg);
+
+ boolean uidError = false;
+
if (dataPath.exists()) {
mOutPermissions[1] = 0;
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
@@ -2420,7 +3128,7 @@ class PackageManagerService extends IPackageManager.Stub {
// current data so the application will still work.
if (mInstaller != null) {
int ret = mInstaller.remove(pkgName);
- if(ret >= 0) {
+ if (ret >= 0) {
// Old data gone!
String msg = "System package " + pkg.packageName
+ " has changed from uid: "
@@ -2428,7 +3136,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ 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);
@@ -2441,7 +3149,7 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
}
- }
+ }
if (!recovered) {
mHasSystemUidErrors = true;
}
@@ -2455,12 +3163,12 @@ class PackageManagerService extends IPackageManager.Stub {
+ mOutPermissions[1] + " on disk, "
+ pkg.applicationInfo.uid + " in settings";
synchronized (mPackages) {
- if (!mReportedUidError) {
- mReportedUidError = true;
- msg = msg + "; read messages:\n"
- + mSettings.getReadMessagesLP();
+ mSettings.mReadMessages.append(msg);
+ mSettings.mReadMessages.append('\n');
+ uidError = true;
+ if (!pkgSetting.uidError) {
+ reportSettingsProblem(Log.ERROR, msg);
}
- reportSettingsProblem(Log.ERROR, msg);
}
}
}
@@ -2489,10 +3197,12 @@ class PackageManagerService extends IPackageManager.Stub {
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
- Log.w(TAG, "Unable to create data directory: " + dataPath);
+ Slog.w(TAG, "Unable to create data directory: " + dataPath);
pkg.applicationInfo.dataDir = null;
}
}
+
+ pkgSetting.uidError = uidError;
}
// Perform shared library installation and dex validation and
@@ -2500,17 +3210,26 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller != null) {
String path = scanFile.getPath();
if (scanFileNewer) {
- Log.i(TAG, path + " changed; unpacking");
- int err = cachePackageSharedLibsLI(pkg, dataPath, scanFile);
- if (err != PackageManager.INSTALL_SUCCEEDED) {
- mLastScanError = err;
- return null;
+ // Note: We don't want to unpack the native binaries for
+ // system applications, unless they have been updated
+ // (the binaries are already under /system/lib).
+ //
+ // In other words, we're going to unpack the binaries
+ // only for non-system apps and system app upgrades.
+ //
+ int flags = pkg.applicationInfo.flags;
+ if ((flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
+ (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ Log.i(TAG, path + " changed; unpacking");
+ int err = cachePackageSharedLibsLI(pkg, scanFile);
+ if (err != PackageManager.INSTALL_SUCCEEDED) {
+ mLastScanError = err;
+ return null;
+ }
}
}
-
- pkg.mForwardLocked = (scanMode&SCAN_FORWARD_LOCKED) != 0;
pkg.mScanPath = path;
-
+
if ((scanMode&SCAN_NO_DEX) == 0) {
if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
@@ -2518,34 +3237,32 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
-
+
if (mFactoryTest && pkg.requestedPermissions.contains(
android.Manifest.permission.FACTORY_TEST)) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
- // We don't expect installation to fail beyond this point,
- if ((scanMode&SCAN_MONITOR) != 0) {
- pkg.mPath = destCodeFile.getAbsolutePath();
- mAppDirs.put(pkg.mPath, pkg);
- }
-
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
- IActivityManager am = ActivityManagerNative.getDefault();
- if ((am != null) && ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0)) {
- try {
- am.killApplicationWithUid(pkg.applicationInfo.packageName,
+ if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid);
- } catch (RemoteException e) {
- }
}
+
synchronized (mPackages) {
+ // We don't expect installation to fail beyond this point,
+ if ((scanMode&SCAN_MONITOR) != 0) {
+ mAppDirs.put(pkg.mPath, pkg);
+ }
// Add the new setting to mSettings
- mSettings.insertPackageSettingLP(pkgSetting, pkg, destCodeFile, destResourceFile);
+ mSettings.insertPackageSettingLP(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
+ // Make sure we don't accidentally delete its data.
+ mSettings.mPackagesToBeCleaned.remove(pkgName);
+
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -2556,38 +3273,40 @@ class PackageManagerService extends IPackageManager.Stub {
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];
+ if (p.info.authority != null) {
+ 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 {
- p.info.authority = p.info.authority + ";" + names[j];
+ PackageParser.Provider other = mProviders.get(names[j]);
+ Slog.w(TAG, "Skipping provider name " + names[j] +
+ " (in package " + pkg.applicationInfo.packageName +
+ "): name already used by "
+ + ((other != null && other.getComponentName() != null)
+ ? other.getComponentName().getPackageName() : "?"));
}
- 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 {
- PackageParser.Provider other = mProviders.get(names[j]);
- Log.w(TAG, "Skipping provider name " + names[j] +
- " (in package " + pkg.applicationInfo.packageName +
- "): name already used by "
- + ((other != null && other.component != null)
- ? other.component.getPackageName() : "?"));
}
}
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
@@ -2602,7 +3321,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Providers: " + r);
}
-
+
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
@@ -2622,7 +3341,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Services: " + r);
}
-
+
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
@@ -2642,7 +3361,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
}
-
+
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
@@ -2662,7 +3381,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Activities: " + r);
}
-
+
N = pkg.permissionGroups.size();
r = null;
for (i=0; i<N; i++) {
@@ -2679,7 +3398,7 @@ class PackageManagerService extends IPackageManager.Stub {
r.append(pg.info.name);
}
} else {
- Log.w(TAG, "Permission group " + pg.info.name + " from package "
+ Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName + " ignored: original from "
+ cur.info.packageName);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
@@ -2696,7 +3415,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r);
}
-
+
N = pkg.permissions.size();
r = null;
for (i=0; i<N; i++) {
@@ -2718,6 +3437,7 @@ class PackageManagerService extends IPackageManager.Stub {
BasePermission tree = findPermissionTreeLP(p.info.name);
if (tree == null
|| tree.sourcePackage.equals(p.info.packageName)) {
+ bp.packageSetting = pkgSetting;
bp.perm = p;
bp.uid = pkg.applicationInfo.uid;
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
@@ -2729,13 +3449,13 @@ class PackageManagerService extends IPackageManager.Stub {
r.append(p.info.name);
}
} else {
- Log.w(TAG, "Permission " + p.info.name + " from package "
+ Slog.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 "
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName + " ignored: original from "
+ bp.sourcePackage);
}
@@ -2748,8 +3468,11 @@ class PackageManagerService extends IPackageManager.Stub {
r.append("DUP:");
r.append(p.info.name);
}
+ if (bp.perm == p) {
+ bp.protectionLevel = p.info.protectionLevel;
+ }
} else {
- Log.w(TAG, "Permission " + p.info.name + " from package "
+ Slog.w(TAG, "Permission " + p.info.name + " from package "
+ p.info.packageName + " ignored: no group "
+ p.group);
}
@@ -2757,7 +3480,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
}
-
+
N = pkg.instrumentation.size();
r = null;
for (i=0; i<N; i++) {
@@ -2766,7 +3489,7 @@ class PackageManagerService extends IPackageManager.Stub {
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
a.info.dataDir = pkg.applicationInfo.dataDir;
- mInstrumentation.put(a.component, a);
+ mInstrumentation.put(a.getComponentName(), a);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
@@ -2779,20 +3502,33 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
}
-
+
if (pkg.protectedBroadcasts != null) {
N = pkg.protectedBroadcasts.size();
for (i=0; i<N; i++) {
mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}
}
-
+
pkgSetting.setTimeStamp(scanFileTime);
}
-
+
return pkg;
}
+ private void killApplication(String pkgName, int uid) {
+ // Request the ActivityManager to kill the process(only for existing packages)
+ // so that we do not end up in a confused state while the user is still using the older
+ // version of the application while the new one gets installed.
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ try {
+ am.killApplicationWithUid(pkgName, uid);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
// The following constants are returned by cachePackageSharedLibsForAbiLI
// to indicate if native shared libraries were found in the package.
// Values are:
@@ -2805,6 +3541,13 @@ class PackageManagerService extends IPackageManager.Stub {
private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1;
private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2;
+ // Return the path of the directory that will contain the native binaries
+ // of a given installed package. This is relative to the data path.
+ //
+ private static File getNativeBinaryDirForPackage(PackageParser.Package pkg) {
+ return new File(pkg.applicationInfo.dataDir + "/lib");
+ }
+
// Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk
// and automatically copy them to /data/data/<appname>/lib if present.
//
@@ -2813,10 +3556,9 @@ class PackageManagerService extends IPackageManager.Stub {
// room left on the data partition, or a ZipException if the package
// file is malformed.
//
- private int cachePackageSharedLibsForAbiLI( PackageParser.Package pkg,
- File dataPath, File scanFile, String cpuAbi)
- throws IOException, ZipException {
- File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
+ private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
+ File scanFile, String cpuAbi) throws IOException, ZipException {
+ File sharedLibraryDir = getNativeBinaryDirForPackage(pkg);
final String apkLib = "lib/";
final int apkLibLen = apkLib.length();
final int cpuAbiLen = cpuAbi.length();
@@ -2858,7 +3600,7 @@ class PackageManagerService extends IPackageManager.Stub {
// file name must start with libPrefix, i.e. "lib"
int lastSlash = entryName.lastIndexOf('/');
- if (lastSlash < 0 ||
+ if (lastSlash < 0 ||
!entryName.regionMatches(lastSlash+1, libPrefix, 0, libPrefixLen) ) {
continue;
}
@@ -2893,7 +3635,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller == null) {
sharedLibraryDir.mkdir();
}
- cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
+ cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
sharedLibraryFile);
}
}
@@ -2906,6 +3648,54 @@ class PackageManagerService extends IPackageManager.Stub {
return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
}
+ // Find the gdbserver executable program in a package at
+ // lib/<cpuAbi>/gdbserver and copy it to /data/data/<name>/lib/gdbserver
+ //
+ // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
+ // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
+ //
+ private int cachePackageGdbServerLI(PackageParser.Package pkg,
+ File scanFile, String cpuAbi) throws IOException, ZipException {
+ File installGdbServerDir = getNativeBinaryDirForPackage(pkg);
+ final String GDBSERVER = "gdbserver";
+ final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
+
+ ZipFile zipFile = new ZipFile(scanFile);
+ Enumeration<ZipEntry> entries =
+ (Enumeration<ZipEntry>) zipFile.entries();
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ // skip directories
+ if (entry.isDirectory()) {
+ continue;
+ }
+ String entryName = entry.getName();
+
+ if (!entryName.equals(apkGdbServerPath)) {
+ continue;
+ }
+
+ String installGdbServerPath = installGdbServerDir.getPath() +
+ "/" + GDBSERVER;
+ File installGdbServerFile = new File(installGdbServerPath);
+ if (! installGdbServerFile.exists() ||
+ installGdbServerFile.length() != entry.getSize() ||
+ installGdbServerFile.lastModified() != entry.getTime()) {
+ if (Config.LOGD) {
+ Log.d(TAG, "Caching gdbserver " + entry.getName());
+ }
+ if (mInstaller == null) {
+ installGdbServerDir.mkdir();
+ }
+ cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
+ installGdbServerFile);
+ }
+ return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
+ }
+ return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
+ }
+
// extract shared libraries stored in the APK as lib/<cpuAbi>/lib<name>.so
// and copy them to /data/data/<appname>/lib.
//
@@ -2913,11 +3703,10 @@ class PackageManagerService extends IPackageManager.Stub {
// (which corresponds to ro.product.cpu.abi), and also try an alternate
// one if ro.product.cpu.abi2 is defined.
//
- private int cachePackageSharedLibsLI(PackageParser.Package pkg,
- File dataPath, File scanFile) {
- final String cpuAbi = Build.CPU_ABI;
+ private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) {
+ String cpuAbi = Build.CPU_ABI;
try {
- int result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi);
+ int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi);
// some architectures are capable of supporting several CPU ABIs
// for example, 'armeabi-v7a' also supports 'armeabi' native code
@@ -2926,64 +3715,110 @@ class PackageManagerService extends IPackageManager.Stub {
//
// only scan the package twice in case of ABI mismatch
if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
+ final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
if (cpuAbi2 != null) {
- result = cachePackageSharedLibsForAbiLI(pkg, dataPath, scanFile, cpuAbi2);
+ result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi2);
}
if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- Log.w(TAG,"Native ABI mismatch from package file");
+ Slog.w(TAG,"Native ABI mismatch from package file");
return PackageManager.INSTALL_FAILED_INVALID_APK;
}
+
+ if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+ cpuAbi = cpuAbi2;
+ }
+ }
+
+ // for debuggable packages, also extract gdbserver from lib/<abi>
+ // into /data/data/<appname>/lib too.
+ if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES &&
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ int result2 = cachePackageGdbServerLI(pkg, scanFile, cpuAbi);
+ if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE;
+ }
}
} catch (ZipException e) {
- Log.w(TAG, "Failed to extract data from package file", e);
+ Slog.w(TAG, "Failed to extract data from package file", e);
return PackageManager.INSTALL_FAILED_INVALID_APK;
} catch (IOException e) {
- Log.w(TAG, "Failed to cache package shared libs", e);
+ Slog.w(TAG, "Failed to cache package shared libs", e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
return PackageManager.INSTALL_SUCCEEDED;
}
- private void cacheSharedLibLI(PackageParser.Package pkg,
+ private void cacheNativeBinaryLI(PackageParser.Package pkg,
ZipFile zipFile, ZipEntry entry,
- File sharedLibraryDir,
- File sharedLibraryFile) throws IOException {
+ File binaryDir,
+ File binaryFile) throws IOException {
InputStream inputStream = zipFile.getInputStream(entry);
try {
- File tempFile = File.createTempFile("tmp", "tmp", sharedLibraryDir);
+ File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
String tempFilePath = tempFile.getPath();
- // XXX package manager can't change owner, so the lib files for
+ // XXX package manager can't change owner, so the executable 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_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH
|FileUtils.S_IROTH, -1, -1) != 0 ||
- ! tempFile.renameTo(sharedLibraryFile)) {
+ ! tempFile.renameTo(binaryFile)) {
// Failed to properly write file.
tempFile.delete();
- throw new IOException("Couldn't create cached shared lib "
- + sharedLibraryFile + " in " + sharedLibraryDir);
+ throw new IOException("Couldn't create cached binary "
+ + binaryFile + " in " + binaryDir);
}
} finally {
inputStream.close();
}
}
+ // Remove the native binaries of a given package. This simply
+ // gets rid of the files in the 'lib' sub-directory.
+ private void removeNativeBinariesLI(PackageParser.Package pkg) {
+ File binaryDir = getNativeBinaryDirForPackage(pkg);
+
+ if (DEBUG_NATIVE) {
+ Slog.w(TAG,"Deleting native binaries from: " + binaryDir.getPath());
+ }
+
+ // Just remove any file in the directory. Since the directory
+ // is owned by the 'system' UID, the application is not supposed
+ // to have written anything there.
+ //
+ if (binaryDir.exists()) {
+ File[] binaries = binaryDir.listFiles();
+ if (binaries != null) {
+ for (int nn=0; nn < binaries.length; nn++) {
+ if (DEBUG_NATIVE) {
+ Slog.d(TAG," Deleting " + binaries[nn].getName());
+ }
+ if (!binaries[nn].delete()) {
+ Slog.w(TAG,"Could not delete native binary: " +
+ binaries[nn].getPath());
+ }
+ }
+ }
+ // Do not delete 'lib' directory itself, or this will prevent
+ // installation of future updates.
+ }
+ }
+
void removePackageLI(PackageParser.Package pkg, boolean chatty) {
if (chatty && Config.LOGD) Log.d(
TAG, "Removing package " + pkg.applicationInfo.packageName );
synchronized (mPackages) {
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.
@@ -2994,7 +3829,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
-
+
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -3003,7 +3838,7 @@ class PackageManagerService extends IPackageManager.Stub {
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.
@@ -3032,7 +3867,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Providers: " + r);
}
-
+
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
@@ -3050,7 +3885,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Services: " + r);
}
-
+
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
@@ -3068,7 +3903,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
}
-
+
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
@@ -3086,7 +3921,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (r != null) {
if (Config.LOGD) Log.d(TAG, " Activities: " + r);
}
-
+
N = pkg.permissions.size();
r = null;
for (i=0; i<N; i++) {
@@ -3098,15 +3933,7 @@ class PackageManagerService extends IPackageManager.Stub {
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;
- }
+ bp.perm = null;
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -3120,12 +3947,12 @@ class PackageManagerService extends IPackageManager.Stub {
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);
+ mInstrumentation.remove(a.getComponentName());
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -3145,16 +3972,39 @@ class PackageManagerService extends IPackageManager.Stub {
return name != null && name.endsWith(".apk");
}
- private void updatePermissionsLP() {
+ private static boolean hasPermission(PackageParser.Package pkgInfo, String perm) {
+ for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
+ if (pkgInfo.permissions.get(i).info.name.equals(perm)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void updatePermissionsLP(String changingPkg,
+ PackageParser.Package pkgInfo, boolean grantPermissions,
+ boolean replace, boolean replaceAll) {
// 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
+ if (bp.packageSetting == null) {
+ // We may not yet have parsed the package, so just see if
+ // we still know about its settings.
+ bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ }
+ if (bp.packageSetting == null) {
+ Slog.w(TAG, "Removing dangling permission tree: " + bp.name
+ " from package " + bp.sourcePackage);
it.remove();
+ } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
+ Slog.i(TAG, "Removing old permission tree: " + bp.name
+ + " from package " + bp.sourcePackage);
+ grantPermissions = true;
+ it.remove();
+ }
}
}
@@ -3167,9 +4017,10 @@ class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ bp.name + " pkg=" + bp.sourcePackage
+ " info=" + bp.pendingInfo);
- if (bp.perm == null && bp.pendingInfo != null) {
+ if (bp.packageSetting == null && bp.pendingInfo != null) {
BasePermission tree = findPermissionTreeLP(bp.name);
if (tree != null) {
+ bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(bp.pendingInfo));
bp.perm.info.packageName = tree.perm.info.packageName;
@@ -3178,28 +4029,48 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
- if (bp.perm == null) {
- Log.w(TAG, "Removing dangling permission: " + bp.name
+ if (bp.packageSetting == null) {
+ // We may not yet have parsed the package, so just see if
+ // we still know about its settings.
+ bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
+ }
+ if (bp.packageSetting == null) {
+ Slog.w(TAG, "Removing dangling permission: " + bp.name
+ " from package " + bp.sourcePackage);
it.remove();
+ } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
+ if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
+ Slog.i(TAG, "Removing old permission: " + bp.name
+ + " from package " + bp.sourcePackage);
+ grantPermissions = true;
+ 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);
+ if (grantPermissions) {
+ for (PackageParser.Package pkg : mPackages.values()) {
+ if (pkg != pkgInfo) {
+ grantPermissionsLP(pkg, replaceAll);
+ }
+ }
+ }
+
+ if (pkgInfo != null) {
+ grantPermissionsLP(pkgInfo, replace);
}
}
-
+
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;
-
+ boolean changedPermission = false;
+
if (replace) {
ps.permissionsFixed = false;
if (gp == ps) {
@@ -3207,39 +4078,42 @@ class PackageManagerService extends IPackageManager.Stub {
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);
+ + ": " + bp);
}
}
- if (p != null) {
- final String perm = p.info.name;
+ if (bp != null && bp.packageSetting != null) {
+ final String perm = bp.name;
boolean allowed;
- if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL
- || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
+ boolean allowedSig = false;
+ if (bp.protectionLevel == PermissionInfo.PROTECTION_NORMAL
+ || bp.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.mSignatures, pkg.mSignatures)
+ } else if (bp.packageSetting == null) {
+ // This permission is invalid; skip it.
+ allowed = false;
+ } else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
+ || bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
+ allowed = (checkSignaturesLP(bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
- if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
+ if (bp.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
+ if ((pkg.applicationInfo.flags
& ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
if(sysPs.grantedPermissions.contains(perm)) {
@@ -3252,6 +4126,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
+ if (allowed) {
+ allowedSig = true;
+ }
} else {
allowed = false;
}
@@ -3265,7 +4142,7 @@ class PackageManagerService extends IPackageManager.Stub {
&& 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)) {
+ if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
allowed = false;
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
@@ -3277,7 +4154,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (npi.name.equals(perm)
&& pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
allowed = true;
- Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
+ Log.i(TAG, "Auto-granting " + perm + " to old pkg "
+ pkg.packageName);
break;
}
@@ -3286,39 +4163,51 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
- addedPermission = true;
+ changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
+ } else if (!ps.haveGids) {
+ gp.gids = appendInts(gp.gids, bp.gids);
}
} else {
- Log.w(TAG, "Not granting permission " + perm
+ Slog.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)
- + ")");
+ if (gp.grantedPermissions.remove(perm)) {
+ changedPermission = true;
+ gp.gids = removeInts(gp.gids, bp.gids);
+ Slog.i(TAG, "Un-granting permission " + perm
+ + " from package " + pkg.packageName
+ + " (protectionLevel=" + bp.protectionLevel
+ + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ + ")");
+ } else {
+ Slog.w(TAG, "Not granting permission " + perm
+ + " to package " + pkg.packageName
+ + " (protectionLevel=" + bp.protectionLevel
+ + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ + ")");
+ }
}
} else {
- Log.w(TAG, "Unknown permission " + name
+ Slog.w(TAG, "Unknown permission " + name
+ " in package " + pkg.packageName);
}
}
-
- if ((addedPermission || replace) && !ps.permissionsFixed &&
+
+ if ((changedPermission || replace) && !ps.permissionsFixed &&
((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) ||
((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 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);
}
+ ps.haveGids = true;
}
-
+
private final class ActivityIntentResolver
extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
@@ -3354,7 +4243,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public final void addActivity(PackageParser.Activity a, String type) {
- mActivities.put(a.component, a);
+ mActivities.put(a.getComponentName(), a);
if (SHOW_INFO || Config.LOGV) Log.v(
TAG, " " + type + " " +
(a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
@@ -3374,7 +4263,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public final void removeActivity(PackageParser.Activity a, String type) {
- mActivities.remove(a.component);
+ mActivities.remove(a.getComponentName());
if (SHOW_INFO || Config.LOGV) Log.v(
TAG, " " + type + " " +
(a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
@@ -3403,6 +4292,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
return true;
}
+
+ @Override
+ protected String packageForFilter(PackageParser.ActivityIntentInfo info) {
+ return info.activity.owner.packageName;
+ }
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
@@ -3444,7 +4338,9 @@ class PackageManagerService extends IPackageManager.Stub {
out.print(prefix); out.print(
Integer.toHexString(System.identityHashCode(filter.activity)));
out.print(' ');
- out.println(filter.activity.componentShortName);
+ out.print(filter.activity.getComponentShortName());
+ out.print(" filter ");
+ out.println(Integer.toHexString(System.identityHashCode(filter)));
}
// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
@@ -3500,7 +4396,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public final void addService(PackageParser.Service s) {
- mServices.put(s.component, s);
+ mServices.put(s.getComponentName(), s);
if (SHOW_INFO || Config.LOGV) Log.v(
TAG, " " + (s.info.nonLocalizedLabel != null
? s.info.nonLocalizedLabel : s.info.name) + ":");
@@ -3522,7 +4418,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public final void removeService(PackageParser.Service s) {
- mServices.remove(s.component);
+ mServices.remove(s.getComponentName());
if (SHOW_INFO || Config.LOGV) Log.v(
TAG, " " + (s.info.nonLocalizedLabel != null
? s.info.nonLocalizedLabel : s.info.name) + ":");
@@ -3553,6 +4449,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
return true;
}
+
+ @Override
+ protected String packageForFilter(PackageParser.ServiceIntentInfo info) {
+ return info.service.owner.packageName;
+ }
@Override
protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
@@ -3595,7 +4496,9 @@ class PackageManagerService extends IPackageManager.Stub {
out.print(prefix); out.print(
Integer.toHexString(System.identityHashCode(filter.service)));
out.print(' ');
- out.println(filter.service.componentShortName);
+ out.print(filter.service.getComponentShortName());
+ out.print(" filter ");
+ out.println(Integer.toHexString(System.identityHashCode(filter)));
}
// List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) {
@@ -3649,7 +4552,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
};
- private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
+ private static final void sendPackageBroadcast(String action, String pkg,
+ Bundle extras, IIntentReceiver finishedReceiver) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
@@ -3659,14 +4563,53 @@ class PackageManagerService extends IPackageManager.Stub {
intent.putExtras(extras);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- am.broadcastIntent(
- null, intent,
- null, null, 0, null, null, null, false, false);
+ am.broadcastIntent(null, intent, null, finishedReceiver,
+ 0, null, null, null, finishedReceiver != null, false);
} catch (RemoteException ex) {
}
}
}
+
+ public String nextPackageToClean(String lastPackage) {
+ synchronized (mPackages) {
+ if (!mMediaMounted) {
+ // If the external storage is no longer mounted at this point,
+ // the caller may not have been able to delete all of this
+ // packages files and can not delete any more. Bail.
+ return null;
+ }
+ if (lastPackage != null) {
+ mSettings.mPackagesToBeCleaned.remove(lastPackage);
+ }
+ return mSettings.mPackagesToBeCleaned.size() > 0
+ ? mSettings.mPackagesToBeCleaned.get(0) : null;
+ }
+ }
+ void schedulePackageCleaning(String packageName) {
+ mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, packageName));
+ }
+
+ void startCleaningPackages() {
+ synchronized (mPackages) {
+ if (!mMediaMounted) {
+ return;
+ }
+ if (mSettings.mPackagesToBeCleaned.size() <= 0) {
+ return;
+ }
+ }
+ Intent intent = new Intent(PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE);
+ intent.setComponent(DEFAULT_CONTAINER_COMPONENT);
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ try {
+ am.startService(null, intent, null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
private final class AppDirObserver extends FileObserver {
public AppDirObserver(String path, int mask, boolean isrom) {
super(path, mask);
@@ -3698,28 +4641,35 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
+ // Ignore packages that are being installed or
+ // have just been installed.
+ if (ignoreCodePath(fullPathStr)) {
+ return;
+ }
+ PackageParser.Package p = null;
+ synchronized (mPackages) {
+ p = mAppDirs.get(fullPathStr);
+ }
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 (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) |
+ p = scanPackageLI(fullPath,
+ (mIsRom ? PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
PackageParser.PARSE_CHATTY |
PackageParser.PARSE_MUST_BE_APK,
- SCAN_MONITOR);
+ SCAN_MONITOR | SCAN_NO_PATHS);
if (p != null) {
synchronized (mPackages) {
- grantPermissionsLP(p, false);
+ updatePermissionsLP(p.packageName, p,
+ p.permissions.size() > 0, false, false);
}
addedPackage = p.applicationInfo.packageName;
addedUid = p.applicationInfo.uid;
@@ -3736,12 +4686,14 @@ class PackageManagerService extends IPackageManager.Stub {
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);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
+ extras, null);
}
if (addedPackage != null) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, addedUid);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
+ extras, null);
}
}
@@ -3754,60 +4706,845 @@ class PackageManagerService extends IPackageManager.Stub {
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
installPackage(packageURI, observer, flags, null);
}
-
+
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags,
final String installerPackageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INSTALL_PACKAGES, null);
-
+
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ msg.obj = new InstallParams(packageURI, observer, flags,
+ installerPackageName);
+ mHandler.sendMessage(msg);
+ }
+
+ public void finishPackageInstall(int token) {
+ if (DEBUG_INSTALL) Log.v(TAG, "BM finishing package install for " + token);
+ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ private void processPendingInstall(final InstallArgs args, final int currentStatus) {
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.returnCode = currentStatus;
res.uid = -1;
res.pkg = null;
res.removedInfo = new PackageRemovedInfo();
- // Make a temporary copy of file from given packageURI
- File tmpPackageFile = copyTempInstallFile(packageURI, res);
- if (tmpPackageFile != null) {
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
- installPackageLI(packageURI, flags, true, installerPackageName, tmpPackageFile, res);
+ installPackageLI(args, true, res);
+ }
+ args.doPostInstall(res.returnCode);
+ }
+
+ // A restore should be performed at this point if (a) the install
+ // succeeded, (b) the operation is not an update, and (c) the new
+ // package has a backupAgent defined.
+ final boolean update = res.removedInfo.removedPackage != null;
+ boolean doRestore = (!update
+ && res.pkg != null
+ && res.pkg.applicationInfo.backupAgentName != null);
+
+ // Set up the post-install work request bookkeeping. This will be used
+ // and cleaned up by the post-install event handling regardless of whether
+ // there's a restore pass performed. Token values are >= 1.
+ int token;
+ if (mNextInstallToken < 0) mNextInstallToken = 1;
+ token = mNextInstallToken++;
+
+ PostInstallData data = new PostInstallData(args, res);
+ mRunningInstalls.put(token, data);
+ if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+ // Pass responsibility to the Backup Manager. It will perform a
+ // restore if appropriate, then pass responsibility back to the
+ // Package Manager to run the post-install observer callbacks
+ // and broadcasts.
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (bm != null) {
+ if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ + " to BM for possible restore");
+ try {
+ bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+ } catch (RemoteException e) {
+ // can't happen; the backup manager is local
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception trying to enqueue restore", e);
+ doRestore = false;
+ }
+ } else {
+ Slog.e(TAG, "Backup Manager not found!");
+ doRestore = false;
}
}
- if (observer != null) {
- try {
- observer.packageInstalled(res.name, res.returnCode);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
+
+ if (!doRestore) {
+ // No restore possible, or the Backup Manager was mysteriously not
+ // available -- just fire the post-install work request directly.
+ if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+ Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+ mHandler.sendMessage(msg);
+ }
+ }
+ });
+ }
+
+ abstract class HandlerParams {
+ final static int MAX_RETRIES = 4;
+ int retry = 0;
+ final void startCopy() {
+ try {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
+ retry++;
+ if (retry > MAX_RETRIES) {
+ Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
+ mHandler.sendEmptyMessage(MCS_GIVE_UP);
+ handleServiceError();
+ return;
+ } else {
+ handleStartCopy();
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
+ mHandler.sendEmptyMessage(MCS_UNBIND);
+ }
+ } catch (RemoteException e) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
+ mHandler.sendEmptyMessage(MCS_RECONNECT);
+ }
+ handleReturnCode();
+ }
+
+ final void serviceError() {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "serviceError");
+ handleServiceError();
+ handleReturnCode();
+ }
+ abstract void handleStartCopy() throws RemoteException;
+ abstract void handleServiceError();
+ abstract void handleReturnCode();
+ }
+
+ class InstallParams extends HandlerParams {
+ final IPackageInstallObserver observer;
+ int flags;
+ final Uri packageURI;
+ final String installerPackageName;
+ private InstallArgs mArgs;
+ private int mRet;
+ InstallParams(Uri packageURI,
+ IPackageInstallObserver observer, int flags,
+ String installerPackageName) {
+ this.packageURI = packageURI;
+ this.flags = flags;
+ this.observer = observer;
+ this.installerPackageName = installerPackageName;
+ }
+
+ private int installLocationPolicy(PackageInfoLite pkgLite, int flags) {
+ String packageName = pkgLite.packageName;
+ int installLocation = pkgLite.installLocation;
+ boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null) {
+ if ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ // Check for updated system application.
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (onSd) {
+ Slog.w(TAG, "Cannot install update to system app on sdcard");
+ return PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION;
+ }
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ } else {
+ if (onSd) {
+ // Install flag overrides everything.
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ // If current upgrade specifies particular preference
+ if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ // Application explicitly specified internal.
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+ // App explictly prefers external. Let policy decide
+ } else {
+ // Prefer previous location
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+ }
+ }
+ } else {
+ // Invalid install. Return error code
+ return PackageHelper.RECOMMEND_FAILED_ALREADY_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);
- final boolean update = res.removedInfo.removedPackage != null;
- if (update) {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
+ // All the special cases have been taken care of.
+ // Return result based on recommended install location.
+ if (onSd) {
+ return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+ }
+ return pkgLite.recommendedInstallLocation;
+ }
+
+ /*
+ * Invoke remote method to get package information and install
+ * location values. Override install location based on default
+ * policy if needed and then create install arguments based
+ * on the install location.
+ */
+ public void handleStartCopy() throws RemoteException {
+ int ret = PackageManager.INSTALL_SUCCEEDED;
+ boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
+ boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
+ boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0;
+ if (onInt && onSd) {
+ // Check if both bits are set.
+ Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
+ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ } else if (fwdLocked && onSd) {
+ // Check for forward locked apps
+ Slog.w(TAG, "Cannot install fwd locked apps on sdcard");
+ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ } else {
+ // Remote call to find out default install location
+ PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags);
+ int loc = pkgLite.recommendedInstallLocation;
+ if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){
+ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){
+ ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+ ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+ } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
+ ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+ } else {
+ // Override with defaults if needed.
+ loc = installLocationPolicy(pkgLite, flags);
+ if (!onSd && !onInt) {
+ // Override install location with flags
+ if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+ // Set the flag to install on external media.
+ flags |= PackageManager.INSTALL_EXTERNAL;
+ flags &= ~PackageManager.INSTALL_INTERNAL;
+ } else {
+ // Make sure the flag for installing on external
+ // media is unset
+ flags |= PackageManager.INSTALL_INTERNAL;
+ flags &= ~PackageManager.INSTALL_EXTERNAL;
+ }
}
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
- res.pkg.applicationInfo.packageName,
- extras);
- if (update) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- res.pkg.applicationInfo.packageName,
- extras);
+ }
+ }
+ // Create the file args now.
+ mArgs = createInstallArgs(this);
+ if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ // Create copy only if we are not in an erroneous state.
+ // Remote call to initiate copy using temporary file
+ ret = mArgs.copyApk(mContainerService, true);
+ }
+ mRet = ret;
+ }
+
+ @Override
+ void handleReturnCode() {
+ processPendingInstall(mArgs, mRet);
+ }
+
+ @Override
+ void handleServiceError() {
+ mArgs = createInstallArgs(this);
+ mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+
+ /*
+ * Utility class used in movePackage api.
+ * srcArgs and targetArgs are not set for invalid flags and make
+ * sure to do null checks when invoking methods on them.
+ * We probably want to return ErrorPrams for both failed installs
+ * and moves.
+ */
+ class MoveParams extends HandlerParams {
+ final IPackageMoveObserver observer;
+ final int flags;
+ final String packageName;
+ final InstallArgs srcArgs;
+ final InstallArgs targetArgs;
+ int mRet;
+ MoveParams(InstallArgs srcArgs,
+ IPackageMoveObserver observer,
+ int flags, String packageName) {
+ this.srcArgs = srcArgs;
+ this.observer = observer;
+ this.flags = flags;
+ this.packageName = packageName;
+ if (srcArgs != null) {
+ Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath()));
+ targetArgs = createInstallArgs(packageUri, flags, packageName);
+ } else {
+ targetArgs = null;
+ }
+ }
+
+ public void handleStartCopy() throws RemoteException {
+ mRet = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ // Check for storage space on target medium
+ if (!targetArgs.checkFreeStorage(mContainerService)) {
+ Log.w(TAG, "Insufficient storage to install");
+ return;
+ }
+ // Create the file args now.
+ mRet = targetArgs.copyApk(mContainerService, false);
+ targetArgs.doPreInstall(mRet);
+ if (DEBUG_SD_INSTALL) {
+ StringBuilder builder = new StringBuilder();
+ if (srcArgs != null) {
+ builder.append("src: ");
+ builder.append(srcArgs.getCodePath());
+ }
+ if (targetArgs != null) {
+ builder.append(" target : ");
+ builder.append(targetArgs.getCodePath());
+ }
+ Log.i(TAG, builder.toString());
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ targetArgs.doPostInstall(mRet);
+ int currentStatus = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ currentStatus = PackageManager.MOVE_SUCCEEDED;
+ } else if (mRet == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){
+ currentStatus = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ processPendingMove(this, currentStatus);
+ }
+
+ @Override
+ void handleServiceError() {
+ mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+
+ private InstallArgs createInstallArgs(InstallParams params) {
+ if (installOnSd(params.flags)) {
+ return new SdInstallArgs(params);
+ } else {
+ return new FileInstallArgs(params);
+ }
+ }
+
+ private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
+ if (installOnSd(flags)) {
+ return new SdInstallArgs(fullCodePath, fullResourcePath);
+ } else {
+ return new FileInstallArgs(fullCodePath, fullResourcePath);
+ }
+ }
+
+ private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName) {
+ if (installOnSd(flags)) {
+ String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME);
+ return new SdInstallArgs(packageURI, cid);
+ } else {
+ return new FileInstallArgs(packageURI, pkgName);
+ }
+ }
+
+ static abstract class InstallArgs {
+ final IPackageInstallObserver observer;
+ // Always refers to PackageManager flags only
+ final int flags;
+ final Uri packageURI;
+ final String installerPackageName;
+
+ InstallArgs(Uri packageURI,
+ IPackageInstallObserver observer, int flags,
+ String installerPackageName) {
+ this.packageURI = packageURI;
+ this.flags = flags;
+ this.observer = observer;
+ this.installerPackageName = installerPackageName;
+ }
+
+ abstract void createCopyFile();
+ abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
+ abstract int doPreInstall(int status);
+ abstract boolean doRename(int status, String pkgName, String oldCodePath);
+ abstract int doPostInstall(int status);
+ abstract String getCodePath();
+ abstract String getResourcePath();
+ // Need installer lock especially for dex file removal.
+ abstract void cleanUpResourcesLI();
+ abstract boolean doPostDeleteLI(boolean delete);
+ abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
+ }
+
+ class FileInstallArgs extends InstallArgs {
+ File installDir;
+ String codeFileName;
+ String resourceFileName;
+ boolean created = false;
+
+ FileInstallArgs(InstallParams params) {
+ super(params.packageURI, params.observer,
+ params.flags, params.installerPackageName);
+ }
+
+ FileInstallArgs(String fullCodePath, String fullResourcePath) {
+ super(null, null, 0, null);
+ File codeFile = new File(fullCodePath);
+ installDir = codeFile.getParentFile();
+ codeFileName = fullCodePath;
+ resourceFileName = fullResourcePath;
+ }
+
+ FileInstallArgs(Uri packageURI, String pkgName) {
+ super(packageURI, null, 0, null);
+ boolean fwdLocked = isFwdLocked(flags);
+ installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+ String apkName = getNextCodePath(null, pkgName, ".apk");
+ codeFileName = new File(installDir, apkName + ".apk").getPath();
+ resourceFileName = getResourcePathFromCodePath();
+ }
+
+ boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+ return imcs.checkFreeStorage(false, packageURI);
+ }
+
+ String getCodePath() {
+ return codeFileName;
+ }
+
+ void createCopyFile() {
+ boolean fwdLocked = isFwdLocked(flags);
+ installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+ codeFileName = createTempPackageFile(installDir).getPath();
+ resourceFileName = getResourcePathFromCodePath();
+ created = true;
+ }
+
+ int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ if (temp) {
+ // Generate temp file name
+ createCopyFile();
+ }
+ // Get a ParcelFileDescriptor to write to the output file
+ File codeFile = new File(codeFileName);
+ if (!created) {
+ try {
+ codeFile.createNewFile();
+ // Set permissions
+ if (!setPermissions()) {
+ // Failed setting permissions.
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to create file " + codeFile);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
- Runtime.getRuntime().gc();
}
- });
+ ParcelFileDescriptor out = null;
+ try {
+ out = ParcelFileDescriptor.open(codeFile,
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "Failed to create file descritpor for : " + codeFileName);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ // Copy the resource now
+ int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ try {
+ if (imcs.copyResource(packageURI, out)) {
+ ret = PackageManager.INSTALL_SUCCEEDED;
+ }
+ } finally {
+ try { if (out != null) out.close(); } catch (IOException e) {}
+ }
+ return ret;
+ }
+
+ int doPreInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ boolean doRename(int status, final String pkgName, String oldCodePath) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ return false;
+ } else {
+ // Rename based on packageName
+ File codeFile = new File(getCodePath());
+ String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
+ File desFile = new File(installDir, apkName + ".apk");
+ if (!codeFile.renameTo(desFile)) {
+ return false;
+ }
+ // Reset paths since the file has been renamed.
+ codeFileName = desFile.getPath();
+ resourceFileName = getResourcePathFromCodePath();
+ // Set permissions
+ if (!setPermissions()) {
+ // Failed setting permissions.
+ return false;
+ }
+ return true;
+ }
+ }
+
+ int doPostInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ String getResourcePath() {
+ return resourceFileName;
+ }
+
+ String getResourcePathFromCodePath() {
+ String codePath = getCodePath();
+ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
+ String apkNameOnly = getApkName(codePath);
+ return mAppInstallDir.getPath() + "/" + apkNameOnly + ".zip";
+ } else {
+ return codePath;
+ }
+ }
+
+ private boolean cleanUp() {
+ boolean ret = true;
+ String sourceDir = getCodePath();
+ String publicSourceDir = getResourcePath();
+ if (sourceDir != null) {
+ File sourceFile = new File(sourceDir);
+ if (!sourceFile.exists()) {
+ Slog.w(TAG, "Package source " + sourceDir + " does not exist.");
+ ret = false;
+ }
+ // Delete application's code and resources
+ sourceFile.delete();
+ }
+ if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
+ final File publicSourceFile = new File(publicSourceDir);
+ if (!publicSourceFile.exists()) {
+ Slog.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
+ }
+ if (publicSourceFile.exists()) {
+ publicSourceFile.delete();
+ }
+ }
+ return ret;
+ }
+
+ void cleanUpResourcesLI() {
+ String sourceDir = getCodePath();
+ if (cleanUp() && mInstaller != null) {
+ int retCode = mInstaller.rmdex(sourceDir);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceDir + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ }
+ }
+
+ private boolean setPermissions() {
+ // TODO Do this in a more elegant way later on. for now just a hack
+ if (!isFwdLocked(flags)) {
+ final int filePermissions =
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
+ |FileUtils.S_IROTH;
+ int retCode = FileUtils.setPermissions(getCodePath(), filePermissions, -1, -1);
+ if (retCode != 0) {
+ Slog.e(TAG, "Couldn't set new package file permissions for " +
+ getCodePath()
+ + ". The return code was: " + retCode);
+ // TODO Define new internal error
+ return false;
+ }
+ return true;
+ }
+ return true;
+ }
+
+ boolean doPostDeleteLI(boolean delete) {
+ cleanUpResourcesLI();
+ return true;
+ }
+ }
+
+ class SdInstallArgs extends InstallArgs {
+ String cid;
+ String cachePath;
+ static final String RES_FILE_NAME = "pkg.apk";
+
+ SdInstallArgs(InstallParams params) {
+ super(params.packageURI, params.observer,
+ params.flags, params.installerPackageName);
+ }
+
+ SdInstallArgs(String fullCodePath, String fullResourcePath) {
+ super(null, null, PackageManager.INSTALL_EXTERNAL, null);
+ // Extract cid from fullCodePath
+ int eidx = fullCodePath.lastIndexOf("/");
+ String subStr1 = fullCodePath.substring(0, eidx);
+ int sidx = subStr1.lastIndexOf("/");
+ cid = subStr1.substring(sidx+1, eidx);
+ cachePath = subStr1;
+ }
+
+ SdInstallArgs(String cid) {
+ super(null, null, PackageManager.INSTALL_EXTERNAL, null);
+ this.cid = cid;
+ }
+
+ SdInstallArgs(Uri packageURI, String cid) {
+ super(packageURI, null, PackageManager.INSTALL_EXTERNAL, null);
+ this.cid = cid;
+ }
+
+ void createCopyFile() {
+ cid = getTempContainerId();
+ }
+
+ boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+ return imcs.checkFreeStorage(true, packageURI);
+ }
+
+ int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ if (temp) {
+ createCopyFile();
+ }
+ cachePath = imcs.copyResourceToContainer(
+ packageURI, cid,
+ getEncryptKey(), RES_FILE_NAME);
+ return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR :
+ PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ @Override
+ String getCodePath() {
+ return cachePath + "/" + RES_FILE_NAME;
+ }
+
+ @Override
+ String getResourcePath() {
+ return cachePath + "/" + RES_FILE_NAME;
+ }
+
+ int doPreInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ // Destroy container
+ PackageHelper.destroySdDir(cid);
+ } else {
+ boolean mounted = PackageHelper.isContainerMounted(cid);
+ if (!mounted) {
+ cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID);
+ if (cachePath == null) {
+ return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+ }
+ }
+ }
+ return status;
+ }
+
+ boolean doRename(int status, final String pkgName,
+ String oldCodePath) {
+ String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
+ String newCachePath = null;
+ if (PackageHelper.isContainerMounted(cid)) {
+ // Unmount the container
+ if (!PackageHelper.unMountSdDir(cid)) {
+ Slog.i(TAG, "Failed to unmount " + cid + " before renaming");
+ return false;
+ }
+ }
+ if (!PackageHelper.renameSdDir(cid, newCacheId)) {
+ Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId +
+ " which might be stale. Will try to clean up.");
+ // Clean up the stale container and proceed to recreate.
+ if (!PackageHelper.destroySdDir(newCacheId)) {
+ Slog.e(TAG, "Very strange. Cannot clean up stale container " + newCacheId);
+ return false;
+ }
+ // Successfully cleaned up stale container. Try to rename again.
+ if (!PackageHelper.renameSdDir(cid, newCacheId)) {
+ Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId
+ + " inspite of cleaning it up.");
+ return false;
+ }
+ }
+ if (!PackageHelper.isContainerMounted(newCacheId)) {
+ Slog.w(TAG, "Mounting container " + newCacheId);
+ newCachePath = PackageHelper.mountSdDir(newCacheId,
+ getEncryptKey(), Process.SYSTEM_UID);
+ } else {
+ newCachePath = PackageHelper.getSdDir(newCacheId);
+ }
+ if (newCachePath == null) {
+ Slog.w(TAG, "Failed to get cache path for " + newCacheId);
+ return false;
+ }
+ Log.i(TAG, "Succesfully renamed " + cid +
+ " at path: " + cachePath + " to " + newCacheId +
+ " at new path: " + newCachePath);
+ cid = newCacheId;
+ cachePath = newCachePath;
+ return true;
+ }
+
+ int doPostInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ } else {
+ boolean mounted = PackageHelper.isContainerMounted(cid);
+ if (!mounted) {
+ PackageHelper.mountSdDir(cid,
+ getEncryptKey(), Process.myUid());
+ }
+ }
+ return status;
+ }
+
+ private void cleanUp() {
+ // Destroy secure container
+ PackageHelper.destroySdDir(cid);
+ }
+
+ void cleanUpResourcesLI() {
+ String sourceFile = getCodePath();
+ // Remove dex file
+ if (mInstaller != null) {
+ int retCode = mInstaller.rmdex(sourceFile);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ }
+ cleanUp();
+ }
+
+ boolean matchContainer(String app) {
+ if (cid.startsWith(app)) {
+ return true;
+ }
+ return false;
+ }
+
+ String getPackageName() {
+ int idx = cid.lastIndexOf("-");
+ if (idx == -1) {
+ return cid;
+ }
+ return cid.substring(0, idx);
+ }
+
+ boolean doPostDeleteLI(boolean delete) {
+ boolean ret = false;
+ boolean mounted = PackageHelper.isContainerMounted(cid);
+ if (mounted) {
+ // Unmount first
+ ret = PackageHelper.unMountSdDir(cid);
+ }
+ if (ret && delete) {
+ cleanUpResourcesLI();
+ }
+ return ret;
+ }
+ };
+
+ // Utility method used to create code paths based on package name and available index.
+ private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
+ String idxStr = "";
+ int idx = 1;
+ // Fall back to default value of idx=1 if prefix is not
+ // part of oldCodePath
+ if (oldCodePath != null) {
+ String subStr = oldCodePath;
+ // Drop the suffix right away
+ if (subStr.endsWith(suffix)) {
+ subStr = subStr.substring(0, subStr.length() - suffix.length());
+ }
+ // If oldCodePath already contains prefix find out the
+ // ending index to either increment or decrement.
+ int sidx = subStr.lastIndexOf(prefix);
+ if (sidx != -1) {
+ subStr = subStr.substring(sidx + prefix.length());
+ if (subStr != null) {
+ if (subStr.startsWith(INSTALL_PACKAGE_SUFFIX)) {
+ subStr = subStr.substring(INSTALL_PACKAGE_SUFFIX.length());
+ }
+ try {
+ idx = Integer.parseInt(subStr);
+ if (idx <= 1) {
+ idx++;
+ } else {
+ idx--;
+ }
+ } catch(NumberFormatException e) {
+ }
+ }
+ }
+ }
+ idxStr = INSTALL_PACKAGE_SUFFIX + Integer.toString(idx);
+ return prefix + idxStr;
+ }
+
+ // Utility method used to ignore ADD/REMOVE events
+ // by directory observer.
+ private static boolean ignoreCodePath(String fullPathStr) {
+ String apkName = getApkName(fullPathStr);
+ int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX);
+ if (idx != -1 && ((idx+1) < apkName.length())) {
+ // Make sure the package ends with a numeral
+ String version = apkName.substring(idx+1);
+ try {
+ Integer.parseInt(version);
+ return true;
+ } catch (NumberFormatException e) {}
+ }
+ return false;
+ }
+
+ // Utility method that returns the relative package path with respect
+ // to the installation directory. Like say for /data/data/com.test-1.apk
+ // string com.test-1 is returned.
+ static String getApkName(String codePath) {
+ if (codePath == null) {
+ return null;
+ }
+ int sidx = codePath.lastIndexOf("/");
+ int eidx = codePath.lastIndexOf(".");
+ if (eidx == -1) {
+ eidx = codePath.length();
+ } else if (eidx == 0) {
+ Slog.w(TAG, " Invalid code path, "+ codePath + " Not a valid apk name");
+ return null;
+ }
+ return codePath.substring(sidx+1, eidx);
}
class PackageInstalledInfo {
@@ -3817,51 +5554,48 @@ class PackageManagerService extends IPackageManager.Stub {
int returnCode;
PackageRemovedInfo removedInfo;
}
-
+
/*
* Install a non-existing package.
*/
- private void installNewPackageLI(String pkgName,
- File tmpPackageFile,
- String destFilePath, File destPackageFile, File destResourceFile,
- PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+ private void installNewPackageLI(PackageParser.Package pkg,
+ int parseFlags,
+ int scanMode,
String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
- boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
+ String pkgName = pkg.packageName;
+
+ boolean dataDirExists = getDataPathForPackage(pkg).exists();
res.name = pkgName;
synchronized(mPackages) {
- if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
+ if (mSettings.mRenamedPackages.containsKey(pkgName)) {
+ // A package with the same name is already installed, though
+ // it has been renamed to an older name. The package we
+ // are trying to install should be installed as an update to
+ // the existing one, but that has not been requested, so bail.
+ Slog.w(TAG, "Attempt to re-install " + pkgName
+ + " without first uninstalling package running as "
+ + mSettings.mRenamedPackages.get(pkgName));
+ res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+ return;
+ }
+ if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
// Don't allow installation over an existing package with the same name.
- Log.w(TAG, "Attempt to re-install " + pkgName
+ Slog.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, 0,
- SCAN_MONITOR | SCAN_FORCE_DEX
- | SCAN_UPDATE_SIGNATURE
- | (forwardLocked ? SCAN_FORWARD_LOCKED : 0)
- | (newInstall ? SCAN_NEW_INSTALL : 0));
+ PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode);
if (newPackage == null) {
- Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
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,
+ updateSettingsLI(newPackage,
installerPackageName,
res);
// delete the partially installed application. the data directory will have to be
@@ -3872,60 +5606,53 @@ class PackageManagerService extends IPackageManager.Stub {
// scanPackageLocked, unless those directories existed before we even tried to
// install.
deletePackageLI(
- pkgName, true,
+ pkgName, false,
dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
res.removedInfo);
}
}
}
-
- private void replacePackageLI(String pkgName,
- File tmpPackageFile,
- String destFilePath, File destPackageFile, File destResourceFile,
- PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+
+ private void replacePackageLI(PackageParser.Package pkg,
+ int parseFlags,
+ int scanMode,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package oldPackage;
+ String pkgName = pkg.packageName;
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if(checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
+ if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
}
}
boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
- if(sysPkg) {
- replaceSystemPackageLI(oldPackage,
- tmpPackageFile, destFilePath,
- destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, installerPackageName, res);
+ if (sysPkg) {
+ replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
} else {
- replaceNonSystemPackageLI(oldPackage, tmpPackageFile, destFilePath,
- destPackageFile, destResourceFile, pkg, forwardLocked,
- newInstall, installerPackageName, res);
+ replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
}
}
-
+
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
- File tmpPackageFile,
- String destFilePath, File destPackageFile, File destResourceFile,
- PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+ PackageParser.Package pkg,
+ int parseFlags, int scanMode,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean updatedSettings = false;
-
+
String oldInstallerPackageName = null;
synchronized (mPackages) {
oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
}
-
- int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
+ if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
res.removedInfo)) {
// If the existing package was'nt successfully deleted
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -3933,51 +5660,21 @@ class PackageManagerService extends IPackageManager.Stub {
} 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)
- | (newInstall ? SCAN_NEW_INSTALL : 0));
+ newPackage = scanPackageLI(pkg, parseFlags, scanMode);
if (newPackage == null) {
- Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
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,
+ updateSettingsLI(newPackage,
installerPackageName,
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;
- deletePackageResourcesLI(pkgName,
- !deletedPackageAppInfo.sourceDir
- .equals(installedPackageAppInfo.sourceDir)
- ? deletedPackageAppInfo.sourceDir : null,
- !deletedPackageAppInfo.publicSourceDir
- .equals(installedPackageAppInfo.publicSourceDir)
- ? deletedPackageAppInfo.publicSourceDir : null);
- //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 {
+ 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
@@ -3993,55 +5690,52 @@ class PackageManagerService extends IPackageManager.Stub {
if(deletedPkg) {
File restoreFile = new File(deletedPackage.mPath);
if (restoreFile == null) {
- Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
- return;
- }
- File restoreTmpFile = createTempPackageFile();
- if (restoreTmpFile == null) {
- Log.e(TAG, "Failed creating temp file when restoring pkg : " + pkgName);
+ Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
return;
}
- if (!FileUtils.copyFile(restoreFile, restoreTmpFile)) {
- Log.e(TAG, "Failed copying temp file when restoring pkg : " + pkgName);
+ // Parse old package
+ boolean oldOnSd = isExternal(deletedPackage);
+ int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
+ (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE;
+ if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode) == null) {
+ Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
return;
}
- PackageInstalledInfo restoreRes = new PackageInstalledInfo();
- restoreRes.removedInfo = new PackageRemovedInfo();
- installPackageLI(
- Uri.fromFile(restoreFile),
- isForwardLocked(deletedPackage)
- ? PackageManager.INSTALL_FORWARD_LOCK
- : 0, false, oldInstallerPackageName, restoreTmpFile, restoreRes);
- if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
+ // Restore of old package succeeded. Update permissions.
+ synchronized (mPackages) {
+ updatePermissionsLP(deletedPackage.packageName, deletedPackage,
+ true, false, false);
+ mSettings.writeLP();
}
+ Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
}
}
-
+
private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
- File tmpPackageFile,
- String destFilePath, File destPackageFile, File destResourceFile,
- PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
+ PackageParser.Package pkg,
+ int parseFlags, int scanMode,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
boolean updatedSettings = false;
- int parseFlags = PackageManager.INSTALL_REPLACE_EXISTING |
+ parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING |
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.");
+ Slog.w(TAG, "Attempt to delete null packageName.");
return;
}
PackageParser.Package oldPkg;
PackageSetting oldPkgSetting;
synchronized (mPackages) {
oldPkg = mPackages.get(packageName);
- oldPkgSetting = mSettings.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");
+ Slog.w(TAG, "Couldn't find package:"+packageName+" information");
return;
}
}
@@ -4056,47 +5750,25 @@ class PackageManagerService extends IPackageManager.Stub {
// 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)
- | (newInstall ? SCAN_NEW_INSTALL : 0));
+ newPackage = scanPackageLI(pkg, parseFlags, scanMode);
if (newPackage == null) {
- Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
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,
- installerPackageName,
- res);
+ updateSettingsLI(newPackage, installerPackageName, 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 {
+ if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// Re installation failed. Restore old information
// Remove new pkg information
if (newPackage != null) {
removePackageLI(newPackage, true);
}
// Add back the old system package
- scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
- oldPkgSetting.resourcePath,
- oldPkg, parseFlags,
+ scanPackageLI(oldPkg, parseFlags,
SCAN_MONITOR
| SCAN_UPDATE_SIGNATURE);
// Restore the old system information in Settings
@@ -4110,15 +5782,23 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
-
- private void updateSettingsLI(String pkgName, File tmpPackageFile,
- String destFilePath, File destPackageFile,
- File destResourceFile,
- PackageParser.Package pkg,
- PackageParser.Package newPackage,
- boolean replacingExistingPackage,
- boolean forwardLocked,
+
+ // Utility method used to move dex files during install.
+ private int moveDexFilesLI(PackageParser.Package newPackage) {
+ int retCode;
+ if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
+ if (retCode != 0) {
+ Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ private void updateSettingsLI(PackageParser.Package newPackage,
String installerPackageName, PackageInstalledInfo res) {
+ String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
@@ -4127,40 +5807,23 @@ class PackageManagerService extends IPackageManager.Stub {
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 = moveDexFilesLI(newPackage))
+ != PackageManager.INSTALL_SUCCEEDED) {
+ // Discontinue if moving dex files failed.
+ return;
}
- if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ if((res.returnCode = setPermissionsLI(newPackage))
+ != PackageManager.INSTALL_SUCCEEDED) {
if (mInstaller != null) {
- mInstaller.rmdex(tmpPackageFile.getPath());
+ mInstaller.rmdex(newPackage.mScanPath);
}
+ return;
+ } else {
+ Log.d(TAG, "New package installed in " + newPackage.mPath);
}
-
synchronized (mPackages) {
- grantPermissionsLP(newPackage, true);
+ updatePermissionsLP(newPackage.packageName, newPackage,
+ newPackage.permissions.size() > 0, true, false);
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
@@ -4171,193 +5834,147 @@ class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLP();
}
}
-
- private File getFwdLockedResource(String pkgName) {
- final String publicZipFileName = pkgName + ".zip";
- return new File(mAppInstallDir, publicZipFileName);
- }
- private File copyTempInstallFile(Uri pPackageURI,
- PackageInstalledInfo res) {
- File tmpPackageFile = createTempPackageFile();
- int retCode = PackageManager.INSTALL_SUCCEEDED;
- if (tmpPackageFile == null) {
- res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
+ private void installPackageLI(InstallArgs args,
+ boolean newInstall, PackageInstalledInfo res) {
+ int pFlags = args.flags;
+ String installerPackageName = args.installerPackageName;
+ File tmpPackageFile = new File(args.getCodePath());
+ boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+ boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
+ boolean replace = false;
+ int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
+ | (newInstall ? SCAN_NEW_INSTALL : 0);
+ // Result object to be returned
+ res.returnCode = PackageManager.INSTALL_SUCCEEDED;
- 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.");
- retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
- } else if (pPackageURI.getScheme().equals("content")) {
- ParcelFileDescriptor fd = null;
- try {
- fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
- retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
- if (fd == null) {
- Log.e(TAG, "Couldn't open file descriptor from download service (null).");
- retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- } else {
- 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.");
- retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
- }
- } else {
- Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
- retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
+ // Retrieve PackageSettings and parse package
+ int parseFlags = PackageParser.PARSE_CHATTY |
+ (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
+ parseFlags |= mDefParseFlags;
+ PackageParser pp = new PackageParser(tmpPackageFile.getPath());
+ pp.setSeparateProcesses(mSeparateProcesses);
+ final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
+ null, mMetrics, parseFlags);
+ if (pkg == null) {
+ res.returnCode = pp.getParseError();
+ return;
}
-
- res.returnCode = retCode;
- if (retCode != PackageManager.INSTALL_SUCCEEDED) {
- if (tmpPackageFile != null && tmpPackageFile.exists()) {
- tmpPackageFile.delete();
+ String pkgName = res.name = pkg.packageName;
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+ if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
+ res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
+ return;
}
- return null;
}
- return tmpPackageFile;
- }
-
- private void installPackageLI(Uri pPackageURI,
- int pFlags, boolean newInstall, String installerPackageName,
- File tmpPackageFile, PackageInstalledInfo res) {
- String pkgName = null;
- boolean forwardLocked = false;
- boolean replacingExistingPackage = false;
- // Result object to be returned
- res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
+ res.returnCode = pp.getParseError();
+ return;
+ }
+ // Get rid of all references to package scan path via parser.
+ pp = null;
+ String oldCodePath = null;
+ boolean systemApp = false;
+ synchronized (mPackages) {
+ // Check if installing already existing package
+ if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ String oldName = mSettings.mRenamedPackages.get(pkgName);
+ if (pkg.mOriginalPackages != null
+ && pkg.mOriginalPackages.contains(oldName)
+ && mPackages.containsKey(oldName)) {
+ // This package is derived from an original package,
+ // and this device has been updating from that original
+ // name. We must continue using the original name, so
+ // rename the new package here.
+ pkg.setPackageName(oldName);
+ pkgName = pkg.packageName;
+ replace = true;
+ } else if (mPackages.containsKey(pkgName)) {
+ // This package, under its official name, already exists
+ // on the device; we should replace it.
+ replace = true;
+ }
+ }
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null) {
+ systemApp = (ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+ }
+ }
+
+ if (systemApp && onSd) {
+ // Disable updates to system apps on sdcard
+ Slog.w(TAG, "Cannot install updates to system apps on sdcard");
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ return;
+ }
- main_flow: try {
- 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.INSTALL_FORWARD_LOCK) != 0)
- ? mDrmAppPrivateInstallDir
- : mAppInstallDir;
- final File destPackageFile = new File(destDir, pkgFileName);
- final String destFilePath = destPackageFile.getAbsolutePath();
- File destResourceFile;
- if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
- destResourceFile = getFwdLockedResource(pkgName);
- 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);
- final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
- destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
- if (pkg == null) {
- res.returnCode = pp.getParseError();
- break main_flow;
- }
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
- if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
- res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
- 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.INSTALL_REPLACE_EXISTING) != 0
- && mPackages.containsKey(pkgName)) {
- replacingExistingPackage = true;
- }
- }
-
- if(replacingExistingPackage) {
- replacePackageLI(pkgName,
- tmpPackageFile,
- destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall, installerPackageName,
- res);
- } else {
- installNewPackageLI(pkgName,
- tmpPackageFile,
- destFilePath, destPackageFile, destResourceFile,
- pkg, forwardLocked, newInstall, installerPackageName,
- res);
- }
- } finally {
- if (tmpPackageFile != null && tmpPackageFile.exists()) {
- tmpPackageFile.delete();
- }
+ if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return;
+ }
+ // Set application objects path explicitly after the rename
+ setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+ if (replace) {
+ replacePackageLI(pkg, parseFlags, scanMode,
+ installerPackageName, res);
+ } else {
+ installNewPackageLI(pkg, parseFlags, scanMode,
+ installerPackageName,res);
}
}
-
- private int setPermissionsLI(String pkgName,
- PackageParser.Package newPackage,
- String destFilePath,
- File destResourceFile,
- boolean forwardLocked) {
- int retCode;
- if (forwardLocked) {
+
+ private int setPermissionsLI(PackageParser.Package newPackage) {
+ String pkgName = newPackage.packageName;
+ int retCode = 0;
+ // TODO Gross hack but fix later. Ideally move this to be a post installation
+ // check after alloting uid.
+ if ((newPackage.applicationInfo.flags
+ & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+ File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir);
try {
extractPublicFiles(newPackage, destResourceFile);
} catch (IOException e) {
- Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
+ Slog.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,
+ retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
newPackage.applicationInfo.uid);
} else {
final int filePermissions =
FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
- retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
+ retCode = FileUtils.setPermissions(newPackage.mPath, 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);
+ // The permissions on the resource file was set when it was copied for
+ // non forward locked apps and apps on sdcard
}
+
if (retCode != 0) {
- Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
+ Slog.e(TAG, "Couldn't set new package file permissions for " +
+ newPackage.mPath
+ ". The return code was: " + retCode);
+ // TODO Define new internal error
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
return PackageManager.INSTALL_SUCCEEDED;
}
- private boolean isForwardLocked(PackageParser.Package deletedPackage) {
- final ApplicationInfo applicationInfo = deletedPackage.applicationInfo;
- return applicationInfo.sourceDir.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath());
+ private boolean isForwardLocked(PackageParser.Package pkg) {
+ return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ }
+
+ private boolean isExternal(PackageParser.Package pkg) {
+ return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
}
private void extractPublicFiles(PackageParser.Package newPackage,
@@ -4417,7 +6034,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
outZipStream.flush();
}
-
+
private void deleteTempPackageFiles() {
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
@@ -4434,12 +6051,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private File createTempPackageFile() {
+ private File createTempPackageFile(File installDir) {
File tmpPackageFile;
try {
- tmpPackageFile = File.createTempFile("vmdl", ".tmp", mAppInstallDir);
+ tmpPackageFile = File.createTempFile("vmdl", ".tmp", installDir);
} catch (IOException e) {
- Log.e(TAG, "Couldn't create temp file for downloaded package file.");
+ Slog.e(TAG, "Couldn't create temp file for downloaded package file.");
return null;
}
try {
@@ -4447,7 +6064,7 @@ class PackageManagerService extends IPackageManager.Stub {
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.");
+ Slog.e(TAG, "Trouble getting the canoncical path for a temp file.");
return null;
}
return tmpPackageFile;
@@ -4473,13 +6090,13 @@ class PackageManagerService extends IPackageManager.Stub {
} //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, 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,
@@ -4488,16 +6105,26 @@ class PackageManagerService extends IPackageManager.Stub {
* 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;
- synchronized (mInstallLock) {
- res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
+ IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ try {
+ if (dpm != null && dpm.packageHasActiveAdmins(packageName)) {
+ Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
+ return false;
+ }
+ } catch (RemoteException e) {
}
+ synchronized (mInstallLock) {
+ res = deletePackageLI(packageName, deleteCodeAndResources,
+ flags | REMOVE_CHATTY, info);
+ }
+
if(res && sendBroadCast) {
boolean systemUpdate = info.isRemovedPackageSystemUpdate;
info.sendBroadcast(deleteCodeAndResources, systemUpdate);
@@ -4509,8 +6136,17 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, null);
+ }
+ }
+ // Force a gc here.
+ Runtime.getRuntime().gc();
+ // Delete the resources here after sending the broadcast to let
+ // other processes clean up before deleting resources.
+ if (info.args != null) {
+ synchronized (mInstallLock) {
+ info.args.doPostDeleteLI(deleteCodeAndResources);
}
}
return res;
@@ -4521,6 +6157,8 @@ class PackageManagerService extends IPackageManager.Stub {
int uid = -1;
int removedUid = -1;
boolean isRemovedPackageSystemUpdate = false;
+ // Clean up resources deleted packages.
+ InstallArgs args = null;
void sendBroadcast(boolean fullRemove, boolean replacing) {
Bundle extras = new Bundle(1);
@@ -4530,27 +6168,27 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
if (removedPackage != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null);
}
if (removedUid >= 0) {
- sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
+ sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null);
}
}
}
-
+
/*
* 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
+ * 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,
+ private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
int flags) {
String packageName = p.packageName;
if (outInfo != null) {
outInfo.removedPackage = packageName;
}
- removePackageLI(p, true);
+ removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
PackageSetting deletedPs;
synchronized (mPackages) {
@@ -4560,7 +6198,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (mInstaller != null) {
int retCode = mInstaller.remove(packageName);
if (retCode < 0) {
- Log.w(TAG, "Couldn't remove app data or cache directory for package: "
+ Slog.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
}
@@ -4570,22 +6208,39 @@ class PackageManagerService extends IPackageManager.Stub {
File dataDir = new File(pkg.applicationInfo.dataDir);
dataDir.delete();
}
- synchronized (mPackages) {
- if (outInfo != null) {
- outInfo.removedUid = mSettings.removePackageLP(packageName);
- }
- }
}
synchronized (mPackages) {
- if ( (deletedPs != null) && (deletedPs.sharedUser != null)) {
- // remove permissions associated with package
- mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
+ if (deletedPs != null) {
+ schedulePackageCleaning(packageName);
+
+ if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
+ if (outInfo != null) {
+ outInfo.removedUid = mSettings.removePackageLP(packageName);
+ }
+ if (deletedPs != null) {
+ updatePermissionsLP(deletedPs.name, null, false, false, false);
+ if (deletedPs.sharedUser != null) {
+ // remove permissions associated with package
+ mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
+ }
+ }
+ }
+ // remove from preferred activities.
+ ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
+ if (pa.mActivity.getPackageName().equals(deletedPs.name)) {
+ removed.add(pa);
+ }
+ }
+ for (PreferredActivity pa : removed) {
+ mSettings.mPreferredActivities.removeFilter(pa);
+ }
}
// Save settings now
- mSettings.writeLP ();
+ mSettings.writeLP();
}
}
-
+
/*
* Tries to delete system package.
*/
@@ -4594,7 +6249,7 @@ class PackageManagerService extends IPackageManager.Stub {
ApplicationInfo applicationInfo = p.applicationInfo;
//applicable for non-partially installed applications only
if (applicationInfo == null) {
- Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
+ Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
PackageSetting ps = null;
@@ -4605,7 +6260,7 @@ class PackageManagerService extends IPackageManager.Stub {
ps = mSettings.getDisabledSystemPkg(p.packageName);
}
if (ps == null) {
- Log.w(TAG, "Attempt to delete system package "+ p.packageName);
+ Slog.w(TAG, "Attempt to delete system package "+ p.packageName);
return false;
} else {
Log.i(TAG, "Deleting system pkg from data partition");
@@ -4632,58 +6287,30 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
// Reinstate the old system package
mSettings.enableSystemPackageLP(p.packageName);
+ // Remove any native libraries.
+ removeNativeBinariesLI(p);
}
// Install the system package
- PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath,
+ PackageParser.Package newPkg = scanPackageLI(ps.codePath,
PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
- SCAN_MONITOR);
-
+ SCAN_MONITOR | SCAN_NO_PATHS);
+
if (newPkg == null) {
- Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
+ Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
return false;
}
synchronized (mPackages) {
- grantPermissionsLP(newPkg, true);
+ updatePermissionsLP(newPkg.packageName, newPkg, true, true, false);
mSettings.writeLP();
}
return true;
}
- private void deletePackageResourcesLI(String packageName,
- String sourceDir, String publicSourceDir) {
- if (sourceDir != null) {
- File sourceFile = new File(sourceDir);
- if (!sourceFile.exists()) {
- Log.w(TAG, "Package source " + sourceDir + " does not exist.");
- }
- // Delete application's code and resources
- sourceFile.delete();
- if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile.toString());
- if (retCode < 0) {
- Log.w(TAG, "Couldn't remove dex file for package: "
- + packageName + " at location "
- + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
- }
- if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
- final File publicSourceFile = new File(publicSourceDir);
- if (!publicSourceFile.exists()) {
- Log.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
- }
- if (publicSourceFile.exists()) {
- publicSourceFile.delete();
- }
- }
- }
-
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.");
+ Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
if (outInfo != null) {
@@ -4695,19 +6322,24 @@ class PackageManagerService extends IPackageManager.Stub {
// Delete application code and resources
if (deleteCodeAndResources) {
- deletePackageResourcesLI(applicationInfo.packageName,
+ // TODO can pick up from PackageSettings as well
+ int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) ?
+ PackageManager.INSTALL_EXTERNAL : 0;
+ installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
+ PackageManager.INSTALL_FORWARD_LOCK : 0;
+ outInfo.args = createInstallArgs(installFlags,
applicationInfo.sourceDir, applicationInfo.publicSourceDir);
}
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.");
+ Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
PackageParser.Package p;
@@ -4719,17 +6351,17 @@ class PackageManagerService extends IPackageManager.Stub {
dataOnly = true;
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ Slog.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.");
+ Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
return false;
}
-
+
if (dataOnly) {
// Delete application data first
removePackageDataLI(p, outInfo, flags);
@@ -4737,19 +6369,24 @@ class PackageManagerService extends IPackageManager.Stub {
}
// At this point the package should have ApplicationInfo associated with it
if (p.applicationInfo == null) {
- Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
+ Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
+ boolean ret = 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, flags, outInfo);
+ ret = deleteSystemPackageLI(p, flags, outInfo);
+ } else {
+ Log.i(TAG, "Removing non-system package:"+p.packageName);
+ // Kill application pre-emptively especially for apps on sd.
+ killApplication(packageName, p.applicationInfo.uid);
+ ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
}
- Log.i(TAG, "Removing non-system package:"+p.packageName);
- return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
+ return ret;
}
-
+
public void clearApplicationUserData(final String packageName,
final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -4780,10 +6417,10 @@ class PackageManagerService extends IPackageManager.Stub {
} //end run
});
}
-
+
private boolean clearApplicationUserDataLI(String packageName) {
if (packageName == null) {
- Log.w(TAG, "Attempt to delete null packageName.");
+ Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
PackageParser.Package p;
@@ -4794,28 +6431,29 @@ class PackageManagerService extends IPackageManager.Stub {
dataOnly = true;
PackageSetting ps = mSettings.mPackages.get(packageName);
if((ps == null) || (ps.pkg == null)) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ Slog.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.");
+ Slog.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.");
+ Slog.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: "
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ packageName);
return false;
}
@@ -4848,7 +6486,7 @@ class PackageManagerService extends IPackageManager.Stub {
private boolean deleteApplicationCacheFilesLI(String packageName) {
if (packageName == null) {
- Log.w(TAG, "Attempt to delete null packageName.");
+ Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
PackageParser.Package p;
@@ -4856,18 +6494,18 @@ class PackageManagerService extends IPackageManager.Stub {
p = mPackages.get(packageName);
}
if (p == null) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ Slog.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.");
+ Slog.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: "
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ packageName);
return false;
}
@@ -4901,7 +6539,7 @@ class PackageManagerService extends IPackageManager.Stub {
private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
if (packageName == null) {
- Log.w(TAG, "Attempt to get size of null packageName.");
+ Slog.w(TAG, "Attempt to get size of null packageName.");
return false;
}
PackageParser.Package p;
@@ -4912,7 +6550,7 @@ class PackageManagerService extends IPackageManager.Stub {
dataOnly = true;
PackageSetting ps = mSettings.mPackages.get(packageName);
if((ps == null) || (ps.pkg == null)) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
return false;
}
p = ps.pkg;
@@ -4922,7 +6560,7 @@ class PackageManagerService extends IPackageManager.Stub {
if(!dataOnly) {
final ApplicationInfo applicationInfo = p.applicationInfo;
if (applicationInfo == null) {
- Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
+ Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
@@ -4939,41 +6577,74 @@ class PackageManagerService extends IPackageManager.Stub {
return true;
}
-
+
public void addPackageToPreferred(String packageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
- Log.w(TAG, "addPackageToPreferred: no longer implemented");
+ Slog.w(TAG, "addPackageToPreferred: no longer implemented");
}
public void removePackageFromPreferred(String packageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
- Log.w(TAG, "removePackageFromPreferred: no longer implemented");
+ Slog.w(TAG, "removePackageFromPreferred: no longer implemented");
}
public List<PackageInfo> getPreferredPackages(int flags) {
return new ArrayList<PackageInfo>();
}
+ int getUidTargetSdkVersionLockedLP(int uid) {
+ Object obj = mSettings.getUserIdLP(uid);
+ if (obj instanceof SharedUserSetting) {
+ SharedUserSetting sus = (SharedUserSetting)obj;
+ final int N = sus.packages.size();
+ int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ Iterator<PackageSetting> it = sus.packages.iterator();
+ int i=0;
+ while (it.hasNext()) {
+ PackageSetting ps = it.next();
+ if (ps.pkg != null) {
+ int v = ps.pkg.applicationInfo.targetSdkVersion;
+ if (v < vers) vers = v;
+ }
+ }
+ return vers;
+ } else if (obj instanceof PackageSetting) {
+ PackageSetting ps = (PackageSetting)obj;
+ if (ps.pkg != null) {
+ return ps.pkg.applicationInfo.targetSdkVersion;
+ }
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
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 + ":");
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + Binder.getCallingUid());
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ }
+
+ Slog.i(TAG, "Adding preferred activity " + activity + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.mPreferredActivities.addFilter(
new PreferredActivity(filter, match, set, activity));
- mSettings.writeLP();
+ scheduleWriteSettingsLocked();
}
}
public void replacePreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
if (filter.countActions() != 1) {
throw new IllegalArgumentException(
"replacePreferredActivity expects filter to have only 1 action.");
@@ -4991,6 +6662,19 @@ class PackageManagerService extends IPackageManager.Stub {
"paths, schemes or types.");
}
synchronized (mPackages) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ + Binder.getCallingUid());
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ }
+
Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
String action = filter.getAction(0);
String category = filter.getCategory(0);
@@ -5007,12 +6691,26 @@ class PackageManagerService extends IPackageManager.Stub {
}
public void clearPackagePreferredActivities(String packageName) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
-
synchronized (mPackages) {
+ int uid = Binder.getCallingUid();
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null || pkg.applicationInfo.uid != uid) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
+ + Binder.getCallingUid());
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+ }
+ }
+
if (clearPackagePreferredActivitiesLP(packageName)) {
- mSettings.writeLP();
+ scheduleWriteSettingsLocked();
}
}
}
@@ -5101,21 +6799,31 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (className == null) {
// We're dealing with an application/package level state change
+ if (pkgSetting.enabled == newState) {
+ // Nothing to do
+ return;
+ }
pkgSetting.enabled = newState;
} else {
// We're dealing with a component level state change
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
- pkgSetting.enableComponentLP(className);
+ if (!pkgSetting.enableComponentLP(className)) {
+ return;
+ }
break;
case COMPONENT_ENABLED_STATE_DISABLED:
- pkgSetting.disableComponentLP(className);
+ if (!pkgSetting.disableComponentLP(className)) {
+ return;
+ }
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
- pkgSetting.restoreComponentLP(className);
+ if (!pkgSetting.restoreComponentLP(className)) {
+ return;
+ }
break;
default:
- Log.e(TAG, "Invalid new component state: " + newState);
+ Slog.e(TAG, "Invalid new component state: " + newState);
return;
}
}
@@ -5167,7 +6875,7 @@ class PackageManagerService extends IPackageManager.Stub {
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
extras.putInt(Intent.EXTRA_UID, packageUid);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null);
}
public String getInstallerPackageName(String packageName) {
@@ -5179,7 +6887,7 @@ class PackageManagerService extends IPackageManager.Stub {
return pkg.installerPackageName;
}
}
-
+
public int getApplicationEnabledSetting(String appPackageName) {
synchronized (mPackages) {
PackageSetting pkg = mSettings.mPackages.get(appPackageName);
@@ -5241,7 +6949,7 @@ class PackageManagerService extends IPackageManager.Stub {
buf.append(']');
return buf.toString();
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -5254,38 +6962,110 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
+ String packageName = null;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ // Right now we only know how to print all.
+ } else if ("-h".equals(opt)) {
+ pw.println("Package manager dump options:");
+ pw.println(" [-h] [cmd] ...");
+ pw.println(" cmd may be one of:");
+ pw.println(" [package.name]: info about given package");
+ return;
+ } else {
+ pw.println("Unknown argument: " + opt + "; use -h for help");
+ }
+ }
+
+ // Is the caller requesting to dump a particular piece of data?
+ if (opti < args.length) {
+ String cmd = args[opti];
+ opti++;
+ // Is this a package name?
+ if ("android".equals(cmd) || cmd.contains(".")) {
+ packageName = cmd;
+ }
+ }
+
+ boolean printedTitle = false;
+
synchronized (mPackages) {
- pw.println("Activity Resolver Table:");
- mActivities.dump(pw, " ");
- pw.println(" ");
- pw.println("Receiver Resolver Table:");
- mReceivers.dump(pw, " ");
- pw.println(" ");
- pw.println("Service Resolver Table:");
- mServices.dump(pw, " ");
- pw.println(" ");
- pw.println("Preferred Activities:");
- mSettings.mPreferredActivities.dump(pw, " ");
- pw.println(" ");
- pw.println("Permissions:");
+ if (mActivities.dump(pw, "Activity Resolver Table:", " ", packageName)) {
+ printedTitle = true;
+ }
+ if (mReceivers.dump(pw, printedTitle
+ ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:",
+ " ", packageName)) {
+ printedTitle = true;
+ }
+ if (mServices.dump(pw, printedTitle
+ ? "\nService Resolver Table:" : "Service Resolver Table:",
+ " ", packageName)) {
+ printedTitle = true;
+ }
+ if (mSettings.mPreferredActivities.dump(pw, printedTitle
+ ? "\nPreferred Activities:" : "Preferred Activities:",
+ " ", packageName)) {
+ printedTitle = true;
+ }
+ boolean printedSomething = false;
{
for (BasePermission p : mSettings.mPermissions.values()) {
+ if (packageName != null && !packageName.equals(p.sourcePackage)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Permissions:");
+ printedSomething = true;
+ printedTitle = true;
+ }
pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
pw.print(Integer.toHexString(System.identityHashCode(p)));
pw.println("):");
pw.print(" sourcePackage="); pw.println(p.sourcePackage);
pw.print(" uid="); pw.print(p.uid);
pw.print(" gids="); pw.print(arrayToString(p.gids));
- pw.print(" type="); pw.println(p.type);
+ pw.print(" type="); pw.print(p.type);
+ pw.print(" prot="); pw.println(p.protectionLevel);
+ if (p.packageSetting != null) {
+ pw.print(" packageSetting="); pw.println(p.packageSetting);
+ }
+ if (p.perm != null) {
+ pw.print(" perm="); pw.println(p.perm);
+ }
}
}
- pw.println(" ");
- pw.println("Packages:");
+ printedSomething = false;
+ SharedUserSetting packageSharedUser = null;
{
for (PackageSetting ps : mSettings.mPackages.values()) {
- pw.print(" Package ["); pw.print(ps.name); pw.print("] (");
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Packages:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ packageSharedUser = ps.sharedUser;
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
pw.print(Integer.toHexString(System.identityHashCode(ps)));
pw.println("):");
+ if (ps.realName != null) {
+ pw.print(" compat name="); pw.println(ps.name);
+ }
pw.print(" userId="); pw.print(ps.userId);
pw.print(" gids="); pw.println(arrayToString(ps.gids));
pw.print(" sharedUser="); pw.println(ps.sharedUser);
@@ -5297,31 +7077,31 @@ class PackageManagerService extends IPackageManager.Stub {
pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
pw.print(" supportsScreens=[");
boolean first = true;
- if ((ps.pkg.applicationInfo.flags &
+ if ((ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
if (!first) pw.print(", ");
first = false;
pw.print("medium");
}
- if ((ps.pkg.applicationInfo.flags &
+ if ((ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
if (!first) pw.print(", ");
first = false;
pw.print("large");
}
- if ((ps.pkg.applicationInfo.flags &
+ if ((ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
if (!first) pw.print(", ");
first = false;
pw.print("small");
}
- if ((ps.pkg.applicationInfo.flags &
+ if ((ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
if (!first) pw.print(", ");
first = false;
pw.print("resizeable");
}
- if ((ps.pkg.applicationInfo.flags &
+ if ((ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
if (!first) pw.print(", ");
first = false;
@@ -5332,7 +7112,8 @@ class PackageManagerService extends IPackageManager.Stub {
pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
pw.print(" signatures="); pw.println(ps.signatures);
pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
+ pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
pw.print(" installStatus="); pw.print(ps.installStatus);
pw.print(" enabled="); pw.println(ps.enabled);
if (ps.disabledComponents.size() > 0) {
@@ -5353,18 +7134,65 @@ class PackageManagerService extends IPackageManager.Stub {
pw.print(" "); pw.println(s);
}
}
- if (ps.loadedPermissions.size() > 0) {
- pw.println(" loadedPermissions:");
- for (String s : ps.loadedPermissions) {
- pw.print(" "); pw.println(s);
- }
+ }
+ }
+ printedSomething = false;
+ if (mSettings.mRenamedPackages.size() > 0) {
+ for (HashMap.Entry<String, String> e
+ : mSettings.mRenamedPackages.entrySet()) {
+ if (packageName != null && !packageName.equals(e.getKey())
+ && !packageName.equals(e.getValue())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ printedTitle = true;
}
+ pw.print(" "); pw.print(e.getKey()); pw.print(" -> ");
+ pw.println(e.getValue());
}
}
- pw.println(" ");
- pw.println("Shared Users:");
+ printedSomething = false;
+ if (mSettings.mDisabledSysPackages.size() > 0) {
+ for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Hidden system packages:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+ if (ps.realName != null) {
+ pw.print(" compat name="); pw.println(ps.name);
+ }
+ pw.print(" userId="); pw.println(ps.userId);
+ pw.print(" sharedUser="); pw.println(ps.sharedUser);
+ pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ }
+ }
+ printedSomething = false;
{
for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
+ if (packageName != null && su != packageSharedUser) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Shared users:");
+ printedSomething = true;
+ printedTitle = true;
+ }
pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
pw.print(Integer.toHexString(System.identityHashCode(su)));
pw.println("):");
@@ -5374,22 +7202,44 @@ class PackageManagerService extends IPackageManager.Stub {
for (String s : su.grantedPermissions) {
pw.print(" "); pw.println(s);
}
- pw.println(" loadedPermissions:");
- for (String s : su.loadedPermissions) {
- pw.print(" "); pw.println(s);
- }
}
}
- pw.println(" ");
- pw.println("Settings parse messages:");
- pw.println(mSettings.mReadMessages.toString());
+
+ if (packageName == null) {
+ if (printedTitle) pw.println(" ");
+ printedTitle = true;
+ pw.println("Settings parse messages:");
+ pw.println(mSettings.mReadMessages.toString());
+
+ pw.println(" ");
+ pw.println("Package warning messages:");
+ File fname = getSettingsProblemFile();
+ FileInputStream in;
+ try {
+ in = new FileInputStream(fname);
+ int avail = in.available();
+ byte[] data = new byte[avail];
+ in.read(data);
+ pw.println(new String(data));
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ }
+ }
}
synchronized (mProviders) {
- pw.println(" ");
- pw.println("Registered ContentProviders:");
+ boolean printedSomething = false;
for (PackageParser.Provider p : mProviders.values()) {
- pw.println(" ["); pw.println(p.info.authority); pw.println("]: ");
+ if (packageName != null && !packageName.equals(p.info.packageName)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (printedTitle) pw.println(" ");
+ pw.println("Registered ContentProviders:");
+ printedSomething = true;
+ printedTitle = true;
+ }
+ pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
pw.println(p.toString());
}
}
@@ -5401,8 +7251,10 @@ class PackageManagerService extends IPackageManager.Stub {
final static int TYPE_DYNAMIC = 2;
final String name;
- final String sourcePackage;
+ String sourcePackage;
+ PackageSettingBase packageSetting;
final int type;
+ int protectionLevel;
PackageParser.Permission perm;
PermissionInfo pendingInfo;
int uid;
@@ -5412,6 +7264,14 @@ class PackageManagerService extends IPackageManager.Stub {
name = _name;
sourcePackage = _sourcePackage;
type = _type;
+ // Default to most conservative protection level.
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ public String toString() {
+ return "BasePermission{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + name + "}";
}
}
@@ -5549,101 +7409,6 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- /**
- * 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;
@@ -5654,7 +7419,7 @@ class PackageManagerService extends IPackageManager.Stub {
mSignatures[i] = sigs[i];
}
}
-
+
@Override
public String toString() {
StringBuffer buf = new StringBuffer(128);
@@ -5840,22 +7605,28 @@ class PackageManagerService extends IPackageManager.Stub {
static class GrantedPermissions {
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;
+ setFlags(pkgFlags);
+ }
+
+ void setFlags(int pkgFlags) {
+ this.pkgFlags = pkgFlags & (
+ ApplicationInfo.FLAG_SYSTEM |
+ ApplicationInfo.FLAG_FORWARD_LOCK |
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
}
-
+
/**
* Settings base class for pending and resolved classes.
*/
static class PackageSettingBase extends GrantedPermissions {
final String name;
+ final String realName;
File codePath;
String codePathString;
File resourcePath;
@@ -5864,47 +7635,57 @@ class PackageManagerService extends IPackageManager.Stub {
private String timeStampString = "0";
int versionCode;
+ boolean uidError;
+
PackageSignatures signatures = new PackageSignatures();
boolean permissionsFixed;
-
+ boolean haveGids;
+
/* 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 origPackage;
/* package name of the app that installed this package */
String installerPackageName;
- PackageSettingBase(String name, File codePath, File resourcePath,
+ PackageSettingBase(String name, String realName, File codePath, File resourcePath,
int pVersionCode, int pkgFlags) {
super(pkgFlags);
this.name = name;
+ this.realName = realName;
+ init(codePath, resourcePath, pVersionCode);
+ }
+
+ void init(File codePath, File resourcePath, int pVersionCode) {
this.codePath = codePath;
this.codePathString = codePath.toString();
this.resourcePath = resourcePath;
this.resourcePathString = resourcePath.toString();
this.versionCode = pVersionCode;
}
-
+
public void setInstallerPackageName(String packageName) {
installerPackageName = packageName;
}
-
+
String getInstallerPackageName() {
return installerPackageName;
}
-
+
public void setInstallStatus(int newStatus) {
installStatus = newStatus;
}
-
+
public int getInstallStatus() {
return installStatus;
}
-
+
public void setTimeStamp(long newStamp) {
if (newStamp != timeStamp) {
timeStamp = newStamp;
@@ -5916,11 +7697,11 @@ class PackageManagerService extends IPackageManager.Stub {
timeStamp = newStamp;
timeStampString = newStampStr;
}
-
+
public long getTimeStamp() {
return timeStamp;
}
-
+
public String getTimeStampStr() {
return timeStampString;
}
@@ -5928,31 +7709,34 @@ class PackageManagerService extends IPackageManager.Stub {
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;
+ haveGids = base.haveGids;
disabledComponents = base.disabledComponents;
enabledComponents = base.enabledComponents;
enabled = base.enabled;
installStatus = base.installStatus;
}
- void enableComponentLP(String componentClassName) {
- disabledComponents.remove(componentClassName);
- enabledComponents.add(componentClassName);
+ boolean enableComponentLP(String componentClassName) {
+ boolean changed = disabledComponents.remove(componentClassName);
+ changed |= enabledComponents.add(componentClassName);
+ return changed;
}
- void disableComponentLP(String componentClassName) {
- enabledComponents.remove(componentClassName);
- disabledComponents.add(componentClassName);
+ boolean disableComponentLP(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.add(componentClassName);
+ return changed;
}
- void restoreComponentLP(String componentClassName) {
- enabledComponents.remove(componentClassName);
- disabledComponents.remove(componentClassName);
+ boolean restoreComponentLP(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.remove(componentClassName);
+ return changed;
}
int currentEnabledStateLP(String componentName) {
@@ -5974,11 +7758,11 @@ class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package pkg;
SharedUserSetting sharedUser;
- PackageSetting(String name, File codePath, File resourcePath,
+ PackageSetting(String name, String realName, File codePath, File resourcePath,
int pVersionCode, int pkgFlags) {
- super(name, codePath, resourcePath, pVersionCode, pkgFlags);
+ super(name, realName, codePath, resourcePath, pVersionCode, pkgFlags);
}
-
+
@Override
public String toString() {
return "PackageSetting{"
@@ -6000,7 +7784,7 @@ class PackageManagerService extends IPackageManager.Stub {
super(_pkgFlags);
name = _name;
}
-
+
@Override
public String toString() {
return "SharedUserSetting{"
@@ -6015,17 +7799,28 @@ class PackageManagerService extends IPackageManager.Stub {
private static final class Settings {
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
+ private final File mPackageListFilename;
private final HashMap<String, PackageSetting> mPackages =
new HashMap<String, PackageSetting>();
// List of replaced system applications
final HashMap<String, PackageSetting> mDisabledSysPackages =
new HashMap<String, PackageSetting>();
+
+ // These are the last platform API version we were using for
+ // the apps installed on internal and external storage. It is
+ // used to grant newer permissions one time during a system upgrade.
+ int mInternalSdkPlatform;
+ int mExternalSdkPlatform;
// The user's preferred activities associated with particular intent
// filters.
private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
new IntentResolver<PreferredActivity, PreferredActivity>() {
@Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mActivity.getPackageName();
+ }
+ @Override
protected void dumpFilter(PrintWriter out, String prefix,
PreferredActivity filter) {
out.print(prefix); out.print(
@@ -6061,14 +7856,24 @@ class PackageManagerService extends IPackageManager.Stub {
final HashMap<String, BasePermission> mPermissionTrees =
new HashMap<String, BasePermission>();
+ // Packages that have been uninstalled and still need their external
+ // storage data deleted.
+ final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+
+ // Packages that have been renamed since they were first installed.
+ // Keys are the new names of the packages, values are the original
+ // names. The packages appear everwhere else under their original
+ // names.
+ final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
+
private final StringBuilder mReadMessages = new StringBuilder();
private static final class PendingPackage extends PackageSettingBase {
final int sharedId;
- PendingPackage(String name, File codePath, File resourcePath,
+ PendingPackage(String name, String realName, File codePath, File resourcePath,
int sharedId, int pVersionCode, int pkgFlags) {
- super(name, codePath, resourcePath, pVersionCode, pkgFlags);
+ super(name, realName, codePath, resourcePath, pVersionCode, pkgFlags);
this.sharedId = sharedId;
}
}
@@ -6078,6 +7883,7 @@ class PackageManagerService extends IPackageManager.Stub {
Settings() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
+ // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
systemDir.mkdirs();
FileUtils.setPermissions(systemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
@@ -6085,17 +7891,18 @@ class PackageManagerService extends IPackageManager.Stub {
-1, -1);
mSettingsFilename = new File(systemDir, "packages.xml");
mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
+ mPackageListFilename = new File(systemDir, "packages.list");
}
- PackageSetting getPackageLP(PackageParser.Package pkg,
- SharedUserSetting sharedUser, File codePath, File resourcePath,
+ PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
int pkgFlags, boolean create, boolean add) {
final String name = pkg.packageName;
- PackageSetting p = getPackageLP(name, sharedUser, codePath,
+ PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath,
resourcePath, pkg.mVersionCode, pkgFlags, create, add);
return p;
}
-
+
PackageSetting peekPackageLP(String name) {
return mPackages.get(name);
/*
@@ -6106,7 +7913,7 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
*/
}
-
+
void setInstallStatus(String pkgName, int status) {
PackageSetting p = mPackages.get(pkgName);
if(p != null) {
@@ -6115,7 +7922,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
-
+
void setInstallerPackageName(String pkgName,
String installerPkgName) {
PackageSetting p = mPackages.get(pkgName);
@@ -6123,17 +7930,17 @@ class PackageManagerService extends IPackageManager.Stub {
p.setInstallerPackageName(installerPkgName);
}
}
-
+
String getInstallerPackageName(String pkgName) {
PackageSetting p = mPackages.get(pkgName);
- return (p == null) ? null : p.getInstallerPackageName();
+ return (p == null) ? null : p.getInstallerPackageName();
}
int getInstallStatus(String pkgName) {
PackageSetting p = mPackages.get(pkgName);
if(p != null) {
return p.getInstallStatus();
- }
+ }
return -1;
}
@@ -6177,7 +7984,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return removePackageLP(name);
}
-
+
PackageSetting enableSystemPackageLP(String name) {
PackageSetting p = mDisabledSysPackages.get(name);
if(p == null) {
@@ -6188,13 +7995,13 @@ class PackageManagerService extends IPackageManager.Stub {
if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- PackageSetting ret = addPackageLP(name, p.codePath,
+ PackageSetting ret = addPackageLP(name, p.realName, p.codePath,
p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
mDisabledSysPackages.remove(name);
return ret;
}
-
- PackageSetting addPackageLP(String name, File codePath,
+
+ PackageSetting addPackageLP(String name, String realName, File codePath,
File resourcePath, int uid, int vc, int pkgFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -6205,7 +8012,7 @@ class PackageManagerService extends IPackageManager.Stub {
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
+ p = new PackageSetting(name, realName, codePath, resourcePath, vc, pkgFlags);
p.userId = uid;
if (addUserIdLP(uid, p, name)) {
mPackages.put(name, p);
@@ -6233,8 +8040,33 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
- private PackageSetting getPackageLP(String name,
- SharedUserSetting sharedUser, File codePath, File resourcePath,
+ // Transfer ownership of permissions from one package to another.
+ private void transferPermissions(String origPkg, String newPkg) {
+ // Transfer ownership of permissions to the new package.
+ for (int i=0; i<2; i++) {
+ HashMap<String, BasePermission> permissions =
+ i == 0 ? mPermissionTrees : mPermissions;
+ for (BasePermission bp : permissions.values()) {
+ if (origPkg.equals(bp.sourcePackage)) {
+ if (DEBUG_UPGRADE) Log.v(TAG,
+ "Moving permission " + bp.name
+ + " from pkg " + bp.sourcePackage
+ + " to " + newPkg);
+ bp.sourcePackage = newPkg;
+ bp.packageSetting = null;
+ bp.perm = null;
+ if (bp.pendingInfo != null) {
+ bp.pendingInfo.packageName = newPkg;
+ }
+ bp.uid = 0;
+ bp.gids = null;
+ }
+ }
+ }
+ }
+
+ private PackageSetting getPackageLP(String name, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
int vc, int pkgFlags, boolean create, boolean add) {
PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -6244,12 +8076,12 @@ class PackageManagerService extends IPackageManager.Stub {
// This is an updated system app with versions in both system
// and data partition. Just let the most recent version
// take precedence.
- Log.w(TAG, "Trying to update system app code path from " +
+ Slog.w(TAG, "Trying to update system app code path from " +
p.codePathString + " to " + codePath.toString());
} else {
- // Let the app continue with previous uid if code path changes.
- reportSettingsProblem(Log.WARN,
- "Package " + name + " codePath changed from " + p.codePath
+ // Just a change in the code path is not an issue, but
+ // let's log a message about it.
+ Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath
+ " to " + codePath + "; Retaining data and using new");
}
}
@@ -6276,37 +8108,56 @@ class PackageManagerService extends IPackageManager.Stub {
if (!create) {
return null;
}
- p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
- p.setTimeStamp(codePath.lastModified());
- p.sharedUser = sharedUser;
- if (sharedUser != null) {
- p.userId = sharedUser.userId;
- } else if (MULTIPLE_APPLICATION_UIDS) {
- // Clone the setting here for disabled system packages
- PackageSetting dis = mDisabledSysPackages.get(name);
- if (dis != null) {
- // For disabled packages a new setting is created
- // from the existing user id. This still has to be
- // added to list of user id's
- // Copy signatures from previous setting
- if (dis.signatures.mSignatures != null) {
- p.signatures.mSignatures = dis.signatures.mSignatures.clone();
+ if (origPackage != null) {
+ // We are consuming the data from an existing package.
+ p = new PackageSetting(origPackage.name, name, codePath,
+ resourcePath, vc, pkgFlags);
+ if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
+ + " is adopting original package " + origPackage.name);
+ // Note that we will retain the new package's signature so
+ // that we can keep its data.
+ PackageSignatures s = p.signatures;
+ p.copyFrom(origPackage);
+ p.signatures = s;
+ p.sharedUser = origPackage.sharedUser;
+ p.userId = origPackage.userId;
+ p.origPackage = origPackage;
+ mRenamedPackages.put(name, origPackage.name);
+ name = origPackage.name;
+ // Update new package state.
+ p.setTimeStamp(codePath.lastModified());
+ } else {
+ p = new PackageSetting(name, realName, codePath, resourcePath, vc, pkgFlags);
+ p.setTimeStamp(codePath.lastModified());
+ p.sharedUser = sharedUser;
+ if (sharedUser != null) {
+ p.userId = sharedUser.userId;
+ } else if (MULTIPLE_APPLICATION_UIDS) {
+ // Clone the setting here for disabled system packages
+ PackageSetting dis = mDisabledSysPackages.get(name);
+ if (dis != null) {
+ // For disabled packages a new setting is created
+ // from the existing user id. This still has to be
+ // added to list of user id's
+ // Copy signatures from previous setting
+ if (dis.signatures.mSignatures != null) {
+ p.signatures.mSignatures = dis.signatures.mSignatures.clone();
+ }
+ p.userId = dis.userId;
+ // Clone permissions
+ p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
+ // Clone component info
+ p.disabledComponents = new HashSet<String>(dis.disabledComponents);
+ p.enabledComponents = new HashSet<String>(dis.enabledComponents);
+ // Add new setting to list of user ids
+ addUserIdLP(p.userId, p, name);
+ } else {
+ // Assign new user id
+ p.userId = newUserIdLP(p);
}
- p.userId = dis.userId;
- // Clone permissions
- p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
- p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
- // Clone component info
- p.disabledComponents = new HashSet<String>(dis.disabledComponents);
- p.enabledComponents = new HashSet<String>(dis.enabledComponents);
- // Add new setting to list of user ids
- addUserIdLP(p.userId, p, name);
} else {
- // Assign new user id
- p.userId = newUserIdLP(p);
+ p.userId = FIRST_APPLICATION_UID;
}
- } else {
- p.userId = FIRST_APPLICATION_UID;
}
if (p.userId < 0) {
reportSettingsProblem(Log.WARN,
@@ -6314,7 +8165,7 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
if (add) {
- // Finish adding new package by adding it and updating shared
+ // Finish adding new package by adding it and updating shared
// user preferences
addPackageSettingLP(p, name, sharedUser);
}
@@ -6322,27 +8173,37 @@ class PackageManagerService extends IPackageManager.Stub {
return p;
}
- private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg,
- File codePath, File resourcePath) {
+ private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
p.pkg = pkg;
+ String codePath = pkg.applicationInfo.sourceDir;
+ String resourcePath = pkg.applicationInfo.publicSourceDir;
// Update code path if needed
- if (!codePath.toString().equalsIgnoreCase(p.codePathString)) {
- Log.w(TAG, "Code path for pkg : " + p.pkg.packageName +
+ if (!codePath.equalsIgnoreCase(p.codePathString)) {
+ Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName +
" changing from " + p.codePathString + " to " + codePath);
- p.codePath = codePath;
- p.codePathString = codePath.toString();
+ p.codePath = new File(codePath);
+ p.codePathString = codePath;
}
//Update resource path if needed
- if (!resourcePath.toString().equalsIgnoreCase(p.resourcePathString)) {
- Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
+ if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
+ Slog.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
" changing from " + p.resourcePathString + " to " + resourcePath);
- p.resourcePath = resourcePath;
- p.resourcePathString = resourcePath.toString();
+ p.resourcePath = new File(resourcePath);
+ p.resourcePathString = resourcePath;
}
// Update version code if needed
if (pkg.mVersionCode != p.versionCode) {
p.versionCode = pkg.mVersionCode;
}
+ // Update signatures if needed.
+ if (p.signatures.mSignatures == null) {
+ p.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // If this app defines a shared user id initialize
+ // the shared user signatures as well.
+ if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+ }
addPackageSettingLP(p, pkg.packageName, p.sharedUser);
}
@@ -6382,7 +8243,7 @@ class PackageManagerService extends IPackageManager.Stub {
*/
private void updateSharedUserPermsLP(PackageSetting deletedPs, int[] globalGids) {
if ( (deletedPs == null) || (deletedPs.pkg == null)) {
- Log.i(TAG, "Trying to update info for null package. Just ignoring");
+ Slog.i(TAG, "Trying to update info for null package. Just ignoring");
return;
}
// No sharedUserId
@@ -6398,7 +8259,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
for (PackageSetting pkg:sus.packages) {
if (pkg.pkg != null &&
- !pkg.pkg.packageName.equalsIgnoreCase(deletedPs.pkg.packageName) &&
+ !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
pkg.pkg.requestedPermissions.contains(eachPerm)) {
used = true;
break;
@@ -6407,7 +8268,6 @@ class PackageManagerService extends IPackageManager.Stub {
if (!used) {
// can safely delete this permission from list
sus.grantedPermissions.remove(eachPerm);
- sus.loadedPermissions.remove(eachPerm);
}
}
// Update gids
@@ -6481,6 +8341,17 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ private Set<String> findPackagesWithFlag(int flag) {
+ Set<String> ret = new HashSet<String>();
+ for (PackageSetting ps : mPackages.values()) {
+ // Has to match atleast all the flag bits set on flag
+ if ((ps.pkgFlags & flag) == flag) {
+ ret.add(ps.name);
+ }
+ }
+ return ret;
+ }
+
private void removeUserIdLP(int uid) {
if (uid >= FIRST_APPLICATION_UID) {
int N = mUserIds.size();
@@ -6490,7 +8361,7 @@ class PackageManagerService extends IPackageManager.Stub {
mOtherUserIds.remove(uid);
}
}
-
+
void writeLP() {
//Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
@@ -6503,11 +8374,12 @@ class PackageManagerService extends IPackageManager.Stub {
// might have been corrupted.
if (!mBackupSettingsFilename.exists()) {
if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
- Log.w(TAG, "Unable to backup package manager settings, current changes will be lost at reboot");
+ Slog.w(TAG, "Unable to backup package manager settings, current changes will be lost at reboot");
return;
}
} else {
- Log.w(TAG, "Preserving older settings backup");
+ mSettingsFilename.delete();
+ Slog.w(TAG, "Preserving older settings backup");
}
}
@@ -6524,6 +8396,11 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.startTag(null, "packages");
+ serializer.startTag(null, "last-platform-version");
+ serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
+ serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
+ serializer.endTag(null, "last-platform-version");
+
serializer.startTag(null, "permission-trees");
for (BasePermission bp : mPermissionTrees.values()) {
writePermission(serializer, bp);
@@ -6539,7 +8416,7 @@ class PackageManagerService extends IPackageManager.Stub {
for (PackageSetting pkg : mPackages.values()) {
writePackage(serializer, pkg);
}
-
+
for (PackageSetting pkg : mDisabledSysPackages.values()) {
writeDisabledSysPackage(serializer, pkg);
}
@@ -6568,6 +8445,23 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.endTag(null, "shared-user");
}
+ if (mPackagesToBeCleaned.size() > 0) {
+ for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
+ serializer.startTag(null, "cleaning-package");
+ serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
+ serializer.endTag(null, "cleaning-package");
+ }
+ }
+
+ if (mRenamedPackages.size() > 0) {
+ for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ serializer.startTag(null, "renamed-package");
+ serializer.attribute(null, "new", e.getKey());
+ serializer.attribute(null, "old", e.getValue());
+ serializer.endTag(null, "renamed-package");
+ }
+ }
+
serializer.endTag(null, "packages");
serializer.endDocument();
@@ -6583,14 +8477,69 @@ class PackageManagerService extends IPackageManager.Stub {
|FileUtils.S_IRGRP|FileUtils.S_IWGRP
|FileUtils.S_IROTH,
-1, -1);
+
+ // Write package list file now, use a JournaledFile.
+ //
+ File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+ JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+ str = new FileOutputStream(journal.chooseForWrite());
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (PackageSetting pkg : mPackages.values()) {
+ ApplicationInfo ai = pkg.pkg.applicationInfo;
+ String dataPath = ai.dataDir;
+ boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ // Avoid any application that has a space in its path
+ // or that is handled by the system.
+ if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
+ continue;
+
+ // we store on each line the following information for now:
+ //
+ // pkgName - package name
+ // userId - application-specific user id
+ // debugFlag - 0 or 1 if the package is debuggable.
+ // dataPath - path to package's data path
+ //
+ // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+ //
+ // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+ // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+ // system/core/run-as/run-as.c
+ //
+ sb.setLength(0);
+ sb.append(ai.packageName);
+ sb.append(" ");
+ sb.append((int)ai.uid);
+ sb.append(isDebug ? " 1 " : " 0 ");
+ sb.append(dataPath);
+ sb.append("\n");
+ str.write(sb.toString().getBytes());
+ }
+ str.flush();
+ str.close();
+ journal.commit();
+ }
+ catch (Exception e) {
+ journal.rollback();
+ }
+
+ FileUtils.setPermissions(mPackageListFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
return;
} catch(XmlPullParserException e) {
- Log.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
+ Slog.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);
+ Slog.w(TAG, "Unable to write package manager settings, current changes will be lost at reboot", e);
}
- // Clean up partially written file
+ // Clean up partially written files
if (mSettingsFilename.exists()) {
if (!mSettingsFilename.delete()) {
Log.i(TAG, "Failed to clean up mangled file: " + mSettingsFilename);
@@ -6598,11 +8547,14 @@ class PackageManagerService extends IPackageManager.Stub {
}
//Debug.stopMethodTracing();
}
-
- void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
+
+ void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
serializer.startTag(null, "updated-package");
serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
serializer.attribute(null, "codePath", pkg.codePathString);
serializer.attribute(null, "ts", pkg.getTimeStampStr());
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
@@ -6624,7 +8576,7 @@ class PackageManagerService extends IPackageManager.Stub {
// be set.
for (final String name : pkg.grantedPermissions) {
BasePermission bp = mPermissions.get(name);
- if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) {
+ if (bp != 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");
@@ -6636,18 +8588,20 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.endTag(null, "perms");
serializer.endTag(null, "updated-package");
}
-
- void writePackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
+
+ void writePackage(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
serializer.startTag(null, "package");
serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
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, "flags",
+ Integer.toString(pkg.pkgFlags));
serializer.attribute(null, "ts", pkg.getTimeStampStr());
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (pkg.sharedUser == null) {
@@ -6657,6 +8611,9 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.attribute(null, "sharedUserId",
Integer.toString(pkg.userId));
}
+ if (pkg.uidError) {
+ serializer.attribute(null, "uidError", "true");
+ }
if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
serializer.attribute(null, "enabled",
pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
@@ -6702,10 +8659,10 @@ class PackageManagerService extends IPackageManager.Stub {
}
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
@@ -6713,6 +8670,11 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.startTag(null, "item");
serializer.attribute(null, "name", bp.name);
serializer.attribute(null, "package", bp.sourcePackage);
+ if (bp.protectionLevel !=
+ PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection",
+ Integer.toString(bp.protectionLevel));
+ }
if (DEBUG_SETTINGS) Log.v(TAG,
"Writing perm: name=" + bp.name + " type=" + bp.type);
if (bp.type == BasePermission.TYPE_DYNAMIC) {
@@ -6728,11 +8690,6 @@ class PackageManagerService extends IPackageManager.Stub {
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");
@@ -6756,7 +8713,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return ret;
}
-
+
boolean readLP() {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
@@ -6768,7 +8725,7 @@ class PackageManagerService extends IPackageManager.Stub {
// If both the backup and settings file exist, we
// ignore the settings since it might have been
// corrupted.
- Log.w(TAG, "Cleaning up settings file " + mSettingsFilename);
+ Slog.w(TAG, "Cleaning up settings file " + mSettingsFilename);
mSettingsFilename.delete();
}
} catch (java.io.IOException e) {
@@ -6782,7 +8739,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (str == null) {
if (!mSettingsFilename.exists()) {
mReadMessages.append("No settings file found\n");
- Log.i(TAG, "No current settings file!");
+ Slog.i(TAG, "No current settings file!");
return false;
}
str = new FileInputStream(mSettingsFilename);
@@ -6798,7 +8755,7 @@ class PackageManagerService extends IPackageManager.Stub {
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");
+ Slog.e(TAG, "No start tag found in package manager settings");
return false;
}
@@ -6826,8 +8783,32 @@ class PackageManagerService extends IPackageManager.Stub {
readPreferredActivitiesLP(parser);
} else if(tagName.equals("updated-package")) {
readDisabledSysPackageLP(parser);
+ } else if (tagName.equals("cleaning-package")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ mPackagesToBeCleaned.add(name);
+ }
+ } else if (tagName.equals("renamed-package")) {
+ String nname = parser.getAttributeValue(null, "new");
+ String oname = parser.getAttributeValue(null, "old");
+ if (nname != null && oname != null) {
+ mRenamedPackages.put(nname, oname);
+ }
+ } else if (tagName.equals("last-platform-version")) {
+ mInternalSdkPlatform = mExternalSdkPlatform = 0;
+ try {
+ String internal = parser.getAttributeValue(null, "internal");
+ if (internal != null) {
+ mInternalSdkPlatform = Integer.parseInt(internal);
+ }
+ String external = parser.getAttributeValue(null, "external");
+ if (external != null) {
+ mExternalSdkPlatform = Integer.parseInt(external);
+ }
+ } catch (NumberFormatException e) {
+ }
} else {
- Log.w(TAG, "Unknown element under <packages>: "
+ Slog.w(TAG, "Unknown element under <packages>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
@@ -6837,11 +8818,11 @@ class PackageManagerService extends IPackageManager.Stub {
} catch(XmlPullParserException e) {
mReadMessages.append("Error reading: " + e.toString());
- Log.e(TAG, "Error reading package manager settings", e);
+ Slog.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);
+ Slog.e(TAG, "Error reading package manager settings", e);
}
@@ -6850,11 +8831,11 @@ class PackageManagerService extends IPackageManager.Stub {
final PendingPackage pp = mPendingPackages.get(i);
Object idObj = getUserIdLP(pp.sharedId);
if (idObj != null && idObj instanceof SharedUserSetting) {
- PackageSetting p = getPackageLP(pp.name,
+ PackageSetting p = getPackageLP(pp.name, null, pp.realName,
(SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
pp.versionCode, pp.pkgFlags, true, true);
if (p == null) {
- Log.w(TAG, "Unable to create application package for "
+ Slog.w(TAG, "Unable to create application package for "
+ pp.name);
continue;
}
@@ -6864,13 +8845,13 @@ class PackageManagerService extends IPackageManager.Stub {
+ " has shared uid " + pp.sharedId
+ " that is not a shared uid\n";
mReadMessages.append(msg);
- Log.e(TAG, msg);
+ Slog.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);
+ Slog.e(TAG, msg);
}
}
mPendingPackages.clear();
@@ -6923,6 +8904,8 @@ class PackageManagerService extends IPackageManager.Stub {
dynamic
? BasePermission.TYPE_DYNAMIC
: BasePermission.TYPE_NORMAL);
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
if (dynamic) {
PermissionInfo pi = new PermissionInfo();
pi.packageName = sourcePackage.intern();
@@ -6930,8 +8913,7 @@ class PackageManagerService extends IPackageManager.Stub {
pi.icon = readInt(parser, null, "icon", 0);
pi.nonLocalizedLabel = parser.getAttributeValue(
null, "label");
- pi.protectionLevel = readInt(parser, null, "protection",
- PermissionInfo.PROTECTION_NORMAL);
+ pi.protectionLevel = bp.protectionLevel;
bp.pendingInfo = pi;
}
out.put(bp.name, bp);
@@ -6949,13 +8931,14 @@ class PackageManagerService extends IPackageManager.Stub {
XmlUtils.skipCurrentTag(parser);
}
}
-
+
private void readDisabledSysPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
+ String realName = parser.getAttributeValue(null, "realName");
String codePathStr = parser.getAttributeValue(null, "codePath");
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- if(resourcePathStr == null) {
+ if (resourcePathStr == null) {
resourcePathStr = codePathStr;
}
String version = parser.getAttributeValue(null, "version");
@@ -6966,11 +8949,11 @@ class PackageManagerService extends IPackageManager.Stub {
} catch (NumberFormatException e) {
}
}
-
+
int pkgFlags = 0;
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- PackageSetting ps = new PackageSetting(name,
- new File(codePathStr),
+ PackageSetting ps = new PackageSetting(name, realName,
+ new File(codePathStr),
new File(resourcePathStr), versionCode, pkgFlags);
String timeStampStr = parser.getAttributeValue(null, "ts");
if (timeStampStr != null) {
@@ -7009,16 +8992,18 @@ class PackageManagerService extends IPackageManager.Stub {
}
mDisabledSysPackages.put(name, ps);
}
-
+
private void readPackageLP(XmlPullParser parser)
throws XmlPullParserException, IOException {
String name = null;
+ String realName = null;
String idStr = null;
String sharedIdStr = null;
String codePathStr = null;
String resourcePathStr = null;
String systemStr = null;
String installerPackageName = null;
+ String uidError = null;
int pkgFlags = 0;
String timeStampStr;
long timeStamp = 0;
@@ -7027,7 +9012,9 @@ class PackageManagerService extends IPackageManager.Stub {
int versionCode = 0;
try {
name = parser.getAttributeValue(null, "name");
+ realName = parser.getAttributeValue(null, "realName");
idStr = parser.getAttributeValue(null, "userId");
+ uidError = parser.getAttributeValue(null, "uidError");
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
@@ -7038,16 +9025,24 @@ class PackageManagerService extends IPackageManager.Stub {
} catch (NumberFormatException e) {
}
}
- systemStr = parser.getAttributeValue(null, "system");
installerPackageName = parser.getAttributeValue(null, "installer");
+
+ systemStr = parser.getAttributeValue(null, "flags");
if (systemStr != null) {
- if ("true".equals(systemStr)) {
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
}
} else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0;
+ } 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) {
@@ -7062,6 +9057,9 @@ class PackageManagerService extends IPackageManager.Stub {
if (resourcePathStr == null) {
resourcePathStr = codePathStr;
}
+ if (realName != null) {
+ realName = realName.intern();
+ }
if (name == null) {
reportSettingsProblem(Log.WARN,
"Error in package manager settings: <package> has no name at "
@@ -7071,8 +9069,9 @@ class PackageManagerService extends IPackageManager.Stub {
"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, versionCode, pkgFlags);
+ packageSetting = addPackageLP(name.intern(), realName,
+ new File(codePathStr), new File(resourcePathStr),
+ userId, versionCode, pkgFlags);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
+ ": userId=" + userId + " pkg=" + packageSetting);
if (packageSetting == null) {
@@ -7087,8 +9086,9 @@ class PackageManagerService extends IPackageManager.Stub {
userId = sharedIdStr != null
? Integer.parseInt(sharedIdStr) : 0;
if (userId > 0) {
- packageSetting = new PendingPackage(name.intern(), new File(codePathStr),
- new File(resourcePathStr), userId, versionCode, pkgFlags);
+ packageSetting = new PendingPackage(name.intern(), realName,
+ new File(codePathStr), new File(resourcePathStr),
+ userId, versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp, timeStampStr);
mPendingPackages.add((PendingPackage) packageSetting);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
@@ -7113,6 +9113,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ parser.getPositionDescription());
}
if (packageSetting != null) {
+ packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
final String enabledStr = parser.getAttributeValue(null, "enabled");
if (enabledStr != null) {
@@ -7139,7 +9140,7 @@ class PackageManagerService extends IPackageManager.Stub {
packageSetting.installStatus = PKG_INSTALL_COMPLETE;
}
}
-
+
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -7159,7 +9160,7 @@ class PackageManagerService extends IPackageManager.Stub {
packageSetting.signatures.readXml(parser, mPastSignatures);
} else if (tagName.equals("perms")) {
readGrantedPermissionsLP(parser,
- packageSetting.loadedPermissions);
+ packageSetting.grantedPermissions);
packageSetting.permissionsFixed = true;
} else {
reportSettingsProblem(Log.WARN,
@@ -7288,7 +9289,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (tagName.equals("sigs")) {
su.signatures.readXml(parser, mPastSignatures);
} else if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser, su.loadedPermissions);
+ readGrantedPermissionsLP(parser, su.grantedPermissions);
} else {
reportSettingsProblem(Log.WARN,
"Unknown element under <shared-user>: "
@@ -7384,7 +9385,7 @@ class PackageManagerService extends IPackageManager.Stub {
mUserIds.add(obj);
return FIRST_APPLICATION_UID + N;
}
-
+
public PackageSetting getDisabledSystemPkg(String name) {
synchronized(mPackages) {
PackageSetting ps = mDisabledSysPackages.get(name);
@@ -7402,6 +9403,13 @@ class PackageManagerService extends IPackageManager.Stub {
Log.v(TAG, "disabledComponents: "
+ Arrays.toString(packageSettings.disabledComponents.toArray()));
}
+ if (packageSettings == null) {
+ if (false) {
+ Log.w(TAG, "WAITING FOR DEBUGGER");
+ Debug.waitForDebugger();
+ Log.i(TAG, "We will crash!");
+ }
+ }
return ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0)
|| ((componentInfo.enabled
&& ((packageSettings.enabled == COMPONENT_ENABLED_STATE_ENABLED)
@@ -7411,4 +9419,536 @@ class PackageManagerService extends IPackageManager.Stub {
|| packageSettings.enabledComponents.contains(componentInfo.name));
}
}
+
+ // ------- apps on sdcard specific code -------
+ static final boolean DEBUG_SD_INSTALL = false;
+ final private String mSdEncryptKey = "AppsOnSD";
+ final private String mSdEncryptAlg = "AES";
+ private boolean mMediaMounted = false;
+ private static final int MAX_CONTAINERS = 250;
+
+ private String getEncryptKey() {
+ try {
+ String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
+ if (sdEncKey == null) {
+ sdEncKey = SystemKeyStore.getInstance().
+ generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
+ if (sdEncKey == null) {
+ Slog.e(TAG, "Failed to create encryption keys");
+ return null;
+ }
+ }
+ return sdEncKey;
+ } catch (NoSuchAlgorithmException nsae) {
+ Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
+ return null;
+ }
+ }
+
+ static String getTempContainerId() {
+ String prefix = "smdl2tmp";
+ int tmpIdx = 1;
+ String list[] = PackageHelper.getSecureContainerList();
+ if (list != null) {
+ int idx = 0;
+ int idList[] = new int[MAX_CONTAINERS];
+ boolean neverFound = true;
+ for (String name : list) {
+ // Ignore null entries
+ if (name == null) {
+ continue;
+ }
+ int sidx = name.indexOf(prefix);
+ if (sidx == -1) {
+ // Not a temp file. just ignore
+ continue;
+ }
+ String subStr = name.substring(sidx + prefix.length());
+ idList[idx] = -1;
+ if (subStr != null) {
+ try {
+ int cid = Integer.parseInt(subStr);
+ idList[idx++] = cid;
+ neverFound = false;
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ if (!neverFound) {
+ // Sort idList
+ Arrays.sort(idList);
+ for (int j = 1; j <= idList.length; j++) {
+ if (idList[j-1] != j) {
+ tmpIdx = j;
+ break;
+ }
+ }
+ }
+ }
+ return prefix + tmpIdx;
+ }
+
+ /*
+ * Update media status on PackageManager.
+ */
+ public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Media status can only be updated by the system");
+ }
+ synchronized (mPackages) {
+ Log.i(TAG, "Updating external media status from " +
+ (mMediaMounted ? "mounted" : "unmounted") + " to " +
+ (mediaStatus ? "mounted" : "unmounted"));
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
+ mediaStatus+", mMediaMounted=" + mMediaMounted);
+ if (mediaStatus == mMediaMounted) {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, -1);
+ mHandler.sendMessage(msg);
+ return;
+ }
+ mMediaMounted = mediaStatus;
+ }
+ // Queue up an async operation since the package installation may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ updateExternalMediaStatusInner(mediaStatus, reportStatus);
+ }
+ });
+ }
+
+ /*
+ * Collect information of applications on external media, map them
+ * against existing containers and update information based on current
+ * mount status. Please note that we always have to report status
+ * if reportStatus has been set to true especially when unloading packages.
+ */
+ private void updateExternalMediaStatusInner(boolean mediaStatus,
+ boolean reportStatus) {
+ // Collection of uids
+ int uidArr[] = null;
+ // Collection of stale containers
+ HashSet<String> removeCids = new HashSet<String>();
+ // Collection of packages on external media with valid containers.
+ HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+ // Get list of secure containers.
+ final String list[] = PackageHelper.getSecureContainerList();
+ if (list == null || list.length == 0) {
+ Log.i(TAG, "No secure containers on sdcard");
+ } else {
+ // Process list of secure containers and categorize them
+ // as active or stale based on their package internal state.
+ int uidList[] = new int[list.length];
+ int num = 0;
+ synchronized (mPackages) {
+ for (String cid : list) {
+ SdInstallArgs args = new SdInstallArgs(cid);
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
+ String pkgName = args.getPackageName();
+ if (pkgName == null) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
+ continue;
+ }
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null && ps.codePathString != null) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid +
+ " corresponds to pkg : " + pkgName +
+ " at code path: " + ps.codePathString);
+ // We do have a valid package installed on sdcard
+ processCids.put(args, ps.codePathString);
+ int uid = ps.userId;
+ if (uid != -1) {
+ uidList[num++] = uid;
+ }
+ } else {
+ // Stale container on sdcard. Just delete
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
+ }
+ }
+ }
+
+ if (num > 0) {
+ // Sort uid list
+ Arrays.sort(uidList, 0, num);
+ // Throw away duplicates
+ uidArr = new int[num];
+ uidArr[0] = uidList[0];
+ int di = 0;
+ for (int i = 1; i < num; i++) {
+ if (uidList[i-1] != uidList[i]) {
+ uidArr[di++] = uidList[i];
+ }
+ }
+ }
+ }
+ // Process packages with valid entries.
+ if (mediaStatus) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
+ loadMediaPackages(processCids, uidArr, removeCids);
+ startCleaningPackages();
+ } else {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
+ unloadMediaPackages(processCids, uidArr, reportStatus);
+ }
+ }
+
+ private void sendResourcesChangedBroadcast(boolean mediaStatus,
+ ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+ int size = pkgList.size();
+ if (size > 0) {
+ // Send broadcasts here
+ Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ pkgList.toArray(new String[size]));
+ if (uidArr != null) {
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+ }
+ String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
+ sendPackageBroadcast(action, null, extras, finishedReceiver);
+ }
+ }
+
+ /*
+ * Look at potentially valid container ids from processCids
+ * If package information doesn't match the one on record
+ * or package scanning fails, the cid is added to list of
+ * removeCids. We currently don't delete stale containers.
+ */
+ private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
+ int uidArr[], HashSet<String> removeCids) {
+ ArrayList<String> pkgList = new ArrayList<String>();
+ Set<SdInstallArgs> keys = processCids.keySet();
+ boolean doGc = false;
+ for (SdInstallArgs args : keys) {
+ String codePath = processCids.get(args);
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading container : "
+ + args.cid);
+ int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+ try {
+ // Make sure there are no container errors first.
+ if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED)
+ != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Failed to mount cid : " + args.cid +
+ " when installing from sdcard");
+ continue;
+ }
+ // Check code path here.
+ if (codePath == null || !codePath.equals(args.getCodePath())) {
+ Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()+
+ " does not match one in settings " + codePath);
+ continue;
+ }
+ // Parse package
+ int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ doGc = true;
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg = scanPackageLI(new File(codePath),
+ parseFlags, 0);
+ // Scan the package
+ if (pkg != null) {
+ synchronized (mPackages) {
+ retCode = PackageManager.INSTALL_SUCCEEDED;
+ pkgList.add(pkg.packageName);
+ // Post process args
+ args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
+ }
+ } else {
+ Slog.i(TAG, "Failed to install pkg from " +
+ codePath + " from sdcard");
+ }
+ }
+
+ } finally {
+ if (retCode != PackageManager.INSTALL_SUCCEEDED) {
+ // Don't destroy container here. Wait till gc clears things up.
+ removeCids.add(args.cid);
+ }
+ }
+ }
+ synchronized (mPackages) {
+ // If the platform SDK has changed since the last time we booted,
+ // we need to re-grant app permission to catch any new ones that
+ // appear. This is really a hack, and means that apps can in some
+ // cases get permissions that the user didn't initially explicitly
+ // allow... it would be nice to have some better way to handle
+ // this situation.
+ final boolean regrantPermissions = mSettings.mExternalSdkPlatform
+ != mSdkVersion;
+ if (regrantPermissions) Slog.i(TAG, "Platform changed from "
+ + mSettings.mExternalSdkPlatform + " to " + mSdkVersion
+ + "; regranting permissions for external storage");
+ mSettings.mExternalSdkPlatform = mSdkVersion;
+
+ // Make sure group IDs have been assigned, and any permission
+ // changes in other apps are accounted for
+ updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
+ // Persist settings
+ mSettings.writeLP();
+ }
+ // Send a broadcast to let everyone know we are done processing
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ // Force gc to avoid any stale parser references that we might have.
+ if (doGc) {
+ Runtime.getRuntime().gc();
+ }
+ // List stale containers.
+ if (removeCids != null) {
+ for (String cid : removeCids) {
+ Log.w(TAG, "Container " + cid + " is stale");
+ }
+ }
+ }
+
+ /*
+ * Utility method to unload a list of specified containers
+ */
+ private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
+ // Just unmount all valid containers.
+ for (SdInstallArgs arg : cidArgs) {
+ synchronized (mInstallLock) {
+ arg.doPostDeleteLI(false);
+ }
+ }
+ }
+
+ /*
+ * Unload packages mounted on external media. This involves deleting
+ * package data from internal structures, sending broadcasts about
+ * diabled packages, gc'ing to free up references, unmounting all
+ * secure containers corresponding to packages on external media, and
+ * posting a UPDATED_MEDIA_STATUS message if status has been requested.
+ * Please note that we always have to post this message if status has
+ * been requested no matter what.
+ */
+ private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
+ int uidArr[], final boolean reportStatus) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
+ ArrayList<String> pkgList = new ArrayList<String>();
+ ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
+ final Set<SdInstallArgs> keys = processCids.keySet();
+ for (SdInstallArgs args : keys) {
+ String cid = args.cid;
+ String pkgName = args.getPackageName();
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
+ // Delete package internally
+ PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ synchronized (mInstallLock) {
+ boolean res = deletePackageLI(pkgName, false,
+ PackageManager.DONT_DELETE_DATA, outInfo);
+ if (res) {
+ pkgList.add(pkgName);
+ } else {
+ Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
+ failedList.add(args);
+ }
+ }
+ }
+ // We have to absolutely send UPDATED_MEDIA_STATUS only
+ // after confirming that all the receivers processed the ordered
+ // broadcast when packages get disabled, force a gc to clean things up.
+ // and unload all the containers.
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky) throws RemoteException {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, 1, keys);
+ mHandler.sendMessage(msg);
+ }
+ });
+ } else {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, -1, keys);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ public void movePackage(final String packageName,
+ final IPackageMoveObserver observer, final int flags) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MOVE_PACKAGE, null);
+ int returnCode = PackageManager.MOVE_SUCCEEDED;
+ int currFlags = 0;
+ int newFlags = 0;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else {
+ // Disable moving fwd locked apps and system packages
+ if (pkg.applicationInfo != null &&
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ Slog.w(TAG, "Cannot move system application");
+ returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+ } else if (pkg.applicationInfo != null &&
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+ Slog.w(TAG, "Cannot move forward locked app.");
+ returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
+ } else {
+ // Find install location first
+ if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 &&
+ (flags & PackageManager.MOVE_INTERNAL) != 0) {
+ Slog.w(TAG, "Ambigous flags specified for move location.");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ } else {
+ newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
+ PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
+ currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
+ PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
+ if (newFlags == currFlags) {
+ Slog.w(TAG, "No move required. Trying to move to same location");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ }
+ }
+ }
+ }
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ processPendingMove(new MoveParams(null, observer, 0, packageName), returnCode);
+ } else {
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
+ pkg.applicationInfo.publicSourceDir);
+ MoveParams mp = new MoveParams(srcArgs, observer, newFlags,
+ packageName);
+ msg.obj = mp;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void processPendingMove(final MoveParams mp, final int currentStatus) {
+ // Queue up an async operation since the package deletion may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ int returnCode = currentStatus;
+ if (currentStatus == PackageManager.MOVE_SUCCEEDED) {
+ int uidArr[] = null;
+ ArrayList<String> pkgList = null;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg == null ) {
+ Slog.w(TAG, " Package " + mp.packageName +
+ " doesn't exist. Aborting move");
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
+ mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
+ " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ uidArr = new int[] { pkg.applicationInfo.uid };
+ pkgList = new ArrayList<String>();
+ pkgList.add(mp.packageName);
+ }
+ }
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ // Send resources unavailable broadcast
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
+ // Update package code and resource paths
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ // Recheck for package again.
+ if (pkg == null ) {
+ Slog.w(TAG, " Package " + mp.packageName +
+ " doesn't exist. Aborting move");
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
+ mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
+ " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ String oldCodePath = pkg.mPath;
+ String newCodePath = mp.targetArgs.getCodePath();
+ String newResPath = mp.targetArgs.getResourcePath();
+ pkg.mPath = newCodePath;
+ // Move dex files around
+ if (moveDexFilesLI(pkg)
+ != PackageManager.INSTALL_SUCCEEDED) {
+ // Moving of dex files failed. Set
+ // error code and abort move.
+ pkg.mPath = pkg.mScanPath;
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ } else {
+ pkg.mScanPath = newCodePath;
+ pkg.applicationInfo.sourceDir = newCodePath;
+ pkg.applicationInfo.publicSourceDir = newResPath;
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ ps.codePath = new File(pkg.applicationInfo.sourceDir);
+ ps.codePathString = ps.codePath.getPath();
+ ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
+ ps.resourcePathString = ps.resourcePath.getPath();
+ // Set the application info flag correctly.
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ } else {
+ pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ }
+ ps.setFlags(pkg.applicationInfo.flags);
+ mAppDirs.remove(oldCodePath);
+ mAppDirs.put(newCodePath, pkg);
+ // Persist settings
+ mSettings.writeLP();
+ }
+ }
+ }
+ }
+ // Send resources available broadcast
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ }
+ if (returnCode != PackageManager.MOVE_SUCCEEDED){
+ // Clean up failed installation
+ if (mp.targetArgs != null) {
+ mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ }
+ } else {
+ // Force a gc to clear things up.
+ Runtime.getRuntime().gc();
+ // Delete older code
+ synchronized (mInstallLock) {
+ mp.srcArgs.doPostDeleteLI(true);
+ }
+ }
+ IPackageMoveObserver observer = mp.observer;
+ if (observer != null) {
+ try {
+ observer.packageMoved(mp.packageName, returnCode);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+ });
+ }
+
+ public boolean setInstallLocation(int loc) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
+ if (getInstallLocation() == loc) {
+ return true;
+ }
+ if (loc == PackageHelper.APP_INSTALL_AUTO ||
+ loc == PackageHelper.APP_INSTALL_INTERNAL ||
+ loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+ android.provider.Settings.System.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
+ return true;
+ }
+ return false;
+ }
+
+ public int getInstallLocation() {
+ return android.provider.Settings.System.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO);
+ }
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 966ecb0..b9021b0 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.app.ShutdownThread;
import com.android.server.am.BatteryStatsService;
import android.app.ActivityManagerNative;
@@ -29,6 +30,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -36,6 +38,7 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Binder;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -45,11 +48,13 @@ 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.provider.Settings.SettingNotFoundException;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
+import android.util.Slog;
import android.view.WindowManagerPolicy;
import static android.provider.Settings.System.DIM_SCREEN;
import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
@@ -59,6 +64,7 @@ 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.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -84,7 +90,7 @@ class PowerManagerService extends IPowerManager.Stub
| PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
// time since last state: time since last event:
- // The short keylight delay comes from Gservices; this is the default.
+ // The short keylight delay comes from secure settings; 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
@@ -99,7 +105,7 @@ class PowerManagerService extends IPowerManager.Stub
// trigger proximity if distance is less than 5 cm
private static final float PROXIMITY_THRESHOLD = 5.0f;
- // Cached Gservices settings; see updateGservicesValues()
+ // Cached secure settings; see updateSettingsValues()
private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
// flags for setPowerState
@@ -132,7 +138,7 @@ class PowerManagerService extends IPowerManager.Stub
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;
// Slower animation for autobrightness changes
static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;
@@ -143,21 +149,14 @@ class PowerManagerService extends IPowerManager.Stub
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 boolean mBootCompleted = false;
private int mStayOnConditions = 0;
- private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
- private int[] mBroadcastWhy = new int[3];
+ private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
+ private final int[] mBroadcastWhy = new int[3];
private int mPartialCount = 0;
private int mPowerState;
// mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,
@@ -171,7 +170,8 @@ class PowerManagerService extends IPowerManager.Stub
private boolean mProximitySensorActive = false;
private int mProximityPendingValue = -1; // -1 == nothing, 0 == inactive, 1 == active
private long mLastProximityEventTime;
- private int mTotalDelaySetting;
+ private int mScreenOffTimeoutSetting;
+ private int mMaximumScreenOffTimeout = Integer.MAX_VALUE;
private int mKeylightDelay;
private int mDimDelay;
private int mScreenOffDelay;
@@ -182,8 +182,12 @@ class PowerManagerService extends IPowerManager.Stub
private final LockList mLocks = new LockList();
private Intent mScreenOffIntent;
private Intent mScreenOnIntent;
- private HardwareService mHardware;
+ private LightsService mLightsService;
private Context mContext;
+ private LightsService.Light mLcdLight;
+ private LightsService.Light mButtonLight;
+ private LightsService.Light mKeyboardLight;
+ private LightsService.Light mAttentionLight;
private UnsynchronizedWakeLock mBroadcastWakeLock;
private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
@@ -191,8 +195,8 @@ class PowerManagerService extends IPowerManager.Stub
private UnsynchronizedWakeLock mProximityPartialLock;
private HandlerThread mHandlerThread;
private Handler mHandler;
- private TimeoutTask mTimeoutTask = new TimeoutTask();
- private LightAnimator mLightAnimator = new LightAnimator();
+ private final TimeoutTask mTimeoutTask = new TimeoutTask();
+ private final LightAnimator mLightAnimator = new LightAnimator();
private final BrightnessState mScreenBrightness
= new BrightnessState(SCREEN_BRIGHT_BIT);
private final BrightnessState mKeyboardBrightness
@@ -209,22 +213,23 @@ class PowerManagerService extends IPowerManager.Stub
private Sensor mLightSensor;
private boolean mLightSensorEnabled;
private float mLightSensorValue = -1;
+ private int mHighestLightSensorValue = -1;
private float mLightSensorPendingValue = -1;
- private int mLightSensorBrightness = -1;
+ private int mLightSensorScreenBrightness = -1;
+ private int mLightSensorButtonBrightness = -1;
+ private int mLightSensorKeyboardBrightness = -1;
private boolean mDimScreen = true;
+ private boolean mIsDocked = false;
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>();
- // mScreenOnTime and mScreenOnStartTime are used for computing total time screen
- // has been on since boot
- private long mScreenOnTime;
- private long mScreenOnStartTime;
+ private final HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
// mLastScreenOnTime is the time the screen was last turned on
private long mLastScreenOnTime;
private boolean mPreventScreenOn;
private int mScreenBrightnessOverride = -1;
+ private int mButtonBrightnessOverride = -1;
private boolean mUseSoftwareAutoBrightness;
private boolean mAutoBrightessEnabled;
private int[] mAutoBrightnessLevels;
@@ -250,25 +255,25 @@ class PowerManagerService extends IPowerManager.Stub
mLog = new PrintStream("/data/power.log");
}
catch (FileNotFoundException e) {
- android.util.Log.e(TAG, "Life is hard", e);
+ android.util.Slog.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);
+ android.util.Slog.d(tag, s);
}
static void i(String tag, String s) {
mLog.println(s);
- android.util.Log.i(tag, s);
+ android.util.Slog.i(tag, s);
}
static void w(String tag, String s) {
mLog.println(s);
- android.util.Log.w(tag, s);
+ android.util.Slog.w(tag, s);
}
static void e(String tag, String s) {
mLog.println(s);
- android.util.Log.e(tag, s);
+ android.util.Slog.e(tag, s);
}
}
*/
@@ -344,10 +349,14 @@ class PowerManagerService extends IPowerManager.Stub
// 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.
+ // to avoid turning on the screen when unplugging, we only trigger
+ // user activity when screen was already on.
// temporarily set mUserActivityAllowed to true so this will work
// even when the keyguard is on.
synchronized (mLocks) {
- forceUserActivityLocked();
+ if (!wasPowered || (mPowerState & SCREEN_ON_BIT) != 0) {
+ forceUserActivityLocked();
+ }
}
}
}
@@ -361,6 +370,15 @@ class PowerManagerService extends IPowerManager.Stub
}
}
+ private final class DockReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ dockStateChanged(state);
+ }
+ }
+
/**
* 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,
@@ -377,6 +395,16 @@ class PowerManagerService extends IPowerManager.Stub
Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
}
+ public void setMaximumScreenOffTimeount(int timeMs) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
+ synchronized (mLocks) {
+ mMaximumScreenOffTimeout = timeMs;
+ // recalculate everything
+ setScreenOffTimeoutsLocked();
+ }
+ }
+
private class SettingsObserver implements Observer {
private int getInt(String name) {
return mSettings.getValues(name).getAsInteger(Settings.System.VALUE);
@@ -389,7 +417,7 @@ class PowerManagerService extends IPowerManager.Stub
updateWakeLockLocked();
// SCREEN_OFF_TIMEOUT
- mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT);
+ mScreenOffTimeoutSetting = getInt(SCREEN_OFF_TIMEOUT);
// DIM_SCREEN
//mDimScreen = getInt(DIM_SCREEN) != 0;
@@ -415,22 +443,26 @@ class PowerManagerService extends IPowerManager.Stub
// 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, HardwareService hardware, IActivityManager activity,
+ void init(Context context, LightsService lights, IActivityManager activity,
BatteryService battery) {
- mHardware = hardware;
+ mLightsService = lights;
mContext = context;
mActivityService = activity;
mBatteryStats = BatteryStatsService.getService();
mBatteryService = battery;
+ mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
+ mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
+ mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
+ mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+
mHandlerThread = new HandlerThread("PowerManagerService") {
@Override
protected void onLooperPrepared() {
@@ -439,7 +471,7 @@ class PowerManagerService extends IPowerManager.Stub
}
};
mHandlerThread.start();
-
+
synchronized (mHandlerThread) {
while (!mInitComplete) {
try {
@@ -450,7 +482,7 @@ class PowerManagerService extends IPowerManager.Stub
}
}
}
-
+
void initInThread() {
mHandler = new Handler();
@@ -511,21 +543,19 @@ class PowerManagerService extends IPowerManager.Stub
filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
mContext.registerReceiver(new BootCompletedReceiver(), 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();
-
- if (mUseSoftwareAutoBrightness) {
- // turn the screen on
- setPowerState(SCREEN_BRIGHT);
- } else {
- // turn everything on
- setPowerState(ALL_BRIGHT);
- }
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DOCK_EVENT);
+ mContext.registerReceiver(new DockReceiver(), filter);
+
+ // Listen for secure settings changes
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.CONTENT_URI, true,
+ new ContentObserver(new Handler()) {
+ public void onChange(boolean selfChange) {
+ updateSettingsValues();
+ }
+ });
+ updateSettingsValues();
synchronized (mHandlerThread) {
mInitComplete = true;
@@ -541,6 +571,7 @@ class PowerManagerService extends IPowerManager.Stub
binder = b;
tag = t;
uid = u == MY_UID ? Process.SYSTEM_UID : u;
+ pid = Binder.getCallingPid();
if (u != MY_UID || (
!"KEEP_SCREEN_ON_FLAG".equals(tag)
&& !"KeyInputQueue".equals(tag))) {
@@ -565,6 +596,7 @@ class PowerManagerService extends IPowerManager.Stub
final IBinder binder;
final String tag;
final int uid;
+ final int pid;
final int monitorType;
boolean activated = true;
int minState;
@@ -610,7 +642,7 @@ class PowerManagerService extends IPowerManager.Stub
int acquireType = -1;
if (mSpew) {
- Log.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
+ Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
}
int index = mLocks.getIndex(lock);
@@ -639,7 +671,7 @@ class PowerManagerService extends IPowerManager.Stub
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 + "' "
+ Slog.e(TAG, "bad wakelock type for lock '" + tag + "' "
+ " flags=" + flags);
return;
}
@@ -658,14 +690,14 @@ class PowerManagerService extends IPowerManager.Stub
int oldWakeLockState = mWakeLockState;
mWakeLockState = mLocks.reactivateScreenLocksLocked();
if (mSpew) {
- Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
+ Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
+ " mWakeLockState=0x"
+ Integer.toHexString(mWakeLockState)
+ " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState));
}
} else {
if (mSpew) {
- Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
+ Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
+ " mLocks.gatherState()=0x"
+ Integer.toHexString(mLocks.gatherState())
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
@@ -678,7 +710,7 @@ class PowerManagerService extends IPowerManager.Stub
if (newlock) {
mPartialCount++;
if (mPartialCount == 1) {
- if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 1, tag);
+ if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag);
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
@@ -723,9 +755,9 @@ class PowerManagerService extends IPowerManager.Stub
if (wl == null) {
return;
}
-
+
if (mSpew) {
- Log.d(TAG, "releaseWakeLock flags=0x"
+ Slog.d(TAG, "releaseWakeLock flags=0x"
+ Integer.toHexString(wl.flags) + " tag=" + wl.tag);
}
@@ -740,7 +772,7 @@ class PowerManagerService extends IPowerManager.Stub
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);
+ if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
} else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
@@ -750,7 +782,7 @@ class PowerManagerService extends IPowerManager.Stub
((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) {
// wait for proximity sensor to go negative before disabling sensor
if (mDebugProximitySensor) {
- Log.d(TAG, "waiting for proximity sensor to go negative");
+ Slog.d(TAG, "waiting for proximity sensor to go negative");
}
} else {
disableProximityLockLocked();
@@ -800,7 +832,7 @@ class PowerManagerService extends IPowerManager.Stub
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 + "'");
+ Slog.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
return;
}
@@ -847,7 +879,7 @@ class PowerManagerService extends IPowerManager.Stub
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
@@ -899,87 +931,95 @@ class PowerManagerService extends IPowerManager.Stub
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(" mScreenOffReason=" + mScreenOffReason
- + " mUserState=" + mUserState);
- pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
- + ',' + mBroadcastQueue[2] + "}");
- pw.println(" mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
- + ',' + mBroadcastWhy[2] + "}");
- 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(" mLastScreenOnTime=" + mLastScreenOnTime);
- pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
- pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
- pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
- pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
- pw.println(" mProximityPartialLock=" + mProximityPartialLock);
- pw.println(" mProximityWakeLockCount=" + mProximityWakeLockCount);
- pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
- pw.println(" mProximitySensorActive=" + mProximitySensorActive);
- pw.println(" mProximityPendingValue=" + mProximityPendingValue);
- pw.println(" mLastProximityEventTime=" + mLastProximityEventTime);
- pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
- pw.println(" mLightSensorValue=" + mLightSensorValue);
- pw.println(" mLightSensorPendingValue=" + mLightSensorPendingValue);
- pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
- pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled);
- 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 ";
+ synchronized (mLocks) {
+ 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(" mScreenOffReason=" + mScreenOffReason
+ + " mUserState=" + mUserState);
+ pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
+ + ',' + mBroadcastQueue[2] + "}");
+ pw.println(" mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
+ + ',' + mBroadcastWhy[2] + "}");
+ 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
+ + " mButtonBrightnessOverride=" + mButtonBrightnessOverride);
+ pw.println(" mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting
+ + " mMaximumScreenOffTimeout=" + mMaximumScreenOffTimeout);
+ pw.println(" mLastScreenOnTime=" + mLastScreenOnTime);
+ pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
+ pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
+ pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
+ pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
+ pw.println(" mProximityPartialLock=" + mProximityPartialLock);
+ pw.println(" mProximityWakeLockCount=" + mProximityWakeLockCount);
+ pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
+ pw.println(" mProximitySensorActive=" + mProximitySensorActive);
+ pw.println(" mProximityPendingValue=" + mProximityPendingValue);
+ pw.println(" mLastProximityEventTime=" + mLastProximityEventTime);
+ pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
+ pw.println(" mLightSensorValue=" + mLightSensorValue
+ + " mLightSensorPendingValue=" + mLightSensorPendingValue);
+ pw.println(" mLightSensorScreenBrightness=" + mLightSensorScreenBrightness
+ + " mLightSensorButtonBrightness=" + mLightSensorButtonBrightness
+ + " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness);
+ pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
+ pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled);
+ 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 + ", uid=" + wl.uid
+ + ", pid=" + wl.pid + ")");
}
- String activated = "";
- if (wl.activated) {
- activated = " activated";
+
+ 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_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0
+ ? " POKE_LOCK_IGNORE_TOUCH_AND_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(" " + 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_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0
- ? " POKE_LOCK_IGNORE_TOUCH_AND_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();
+ pw.println();
+ }
}
private void setTimeoutLocked(long now, int nextState)
@@ -998,7 +1038,7 @@ class PowerManagerService extends IPowerManager.Stub
when += mDimDelay;
break;
} else {
- Log.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
+ Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
}
case SCREEN_OFF:
synchronized (mLocks) {
@@ -1007,7 +1047,7 @@ class PowerManagerService extends IPowerManager.Stub
break;
}
if (mSpew) {
- Log.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
+ Slog.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
+ " when=" + when);
}
mHandler.postAtTime(mTimeoutTask, when);
@@ -1028,7 +1068,7 @@ class PowerManagerService extends IPowerManager.Stub
{
synchronized (mLocks) {
if (mSpew) {
- Log.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
+ Slog.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
}
if (nextState == -1) {
@@ -1077,15 +1117,16 @@ class PowerManagerService extends IPowerManager.Stub
// 0 was to turn it off, and we can't strip that, because keyguard needs to come
// on, so have to run the queue then.
if (index == 2) {
- // Also, while we're collapsing them, if it's going to be an "off," and one
- // is off because of user, then use that, regardless of whether it's the first
- // or second one.
- if (!on && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
- mBroadcastWhy[0] = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
+ // While we're collapsing them, if it's going off, and the new reason
+ // is more significant than the first, then use the new one.
+ if (!on && mBroadcastWhy[0] > why) {
+ mBroadcastWhy[0] = why;
}
mBroadcastQueue[0] = on ? 1 : 0;
mBroadcastQueue[1] = -1;
mBroadcastQueue[2] = -1;
+ mBroadcastWakeLock.release();
+ mBroadcastWakeLock.release();
index = 0;
}
if (index == 1 && !on) {
@@ -1094,7 +1135,7 @@ class PowerManagerService extends IPowerManager.Stub
index = -1;
// The wake lock was being held, but we're not actually going to do any
// broadcasts, so release the wake lock.
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
@@ -1105,7 +1146,7 @@ class PowerManagerService extends IPowerManager.Stub
// We always increment the ref count for each notification in the queue
// and always decrement when that notification is handled.
mBroadcastWakeLock.acquire();
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
mHandler.post(mNotificationTask);
}
}
@@ -1129,7 +1170,7 @@ class PowerManagerService extends IPowerManager.Stub
}
if (value == 1) {
mScreenOnStart = SystemClock.uptimeMillis();
-
+
policy.screenTurnedOn();
try {
ActivityManagerNative.getDefault().wakingUp();
@@ -1138,14 +1179,14 @@ class PowerManagerService extends IPowerManager.Stub
}
if (mSpew) {
- Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
+ Slog.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
}
if (mContext != null && ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcast(mScreenOnIntent, null,
mScreenOnBroadcastDone, mHandler, 0, null, null);
} else {
synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2,
mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
@@ -1153,7 +1194,7 @@ class PowerManagerService extends IPowerManager.Stub
}
else if (value == 0) {
mScreenOffStart = SystemClock.uptimeMillis();
-
+
policy.screenTurnedOff(why);
try {
ActivityManagerNative.getDefault().goingToSleep();
@@ -1166,7 +1207,7 @@ class PowerManagerService extends IPowerManager.Stub
mScreenOffBroadcastDone, mHandler, 0, null, null);
} else {
synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3,
mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
@@ -1185,7 +1226,7 @@ class PowerManagerService extends IPowerManager.Stub
private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 1,
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
@@ -1196,7 +1237,7 @@ class PowerManagerService extends IPowerManager.Stub
private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 0,
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
@@ -1282,12 +1323,12 @@ class PowerManagerService extends IPowerManager.Stub
// a prior preventScreenOn(true) call.)
if (!mProximitySensorActive && (mPowerState & SCREEN_ON_BIT) != 0) {
if (mSpew) {
- Log.d(TAG,
+ Slog.d(TAG,
"preventScreenOn: turning on after a prior preventScreenOn(true)!");
}
int err = setScreenStateLocked(true);
if (err != 0) {
- Log.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
+ Slog.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
}
}
@@ -1308,7 +1349,18 @@ class PowerManagerService extends IPowerManager.Stub
}
}
}
-
+
+ public void setButtonBrightnessOverride(int brightness) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ synchronized (mLocks) {
+ if (mButtonBrightnessOverride != brightness) {
+ mButtonBrightnessOverride = brightness;
+ updateLightsLocked(mPowerState, BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT);
+ }
+ }
+ }
+
/**
* Sanity-check that gets called 5 seconds after any call to
* preventScreenOn(true). This ensures that the original call
@@ -1319,7 +1371,7 @@ class PowerManagerService extends IPowerManager.Stub
// we should have already removed any existing
// mForceReenableScreenTask messages...
if (!mPreventScreenOn) {
- Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
+ Slog.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
return;
}
@@ -1331,7 +1383,7 @@ class PowerManagerService extends IPowerManager.Stub
// 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! "
+ Slog.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
+ "Forcing the screen back on...");
preventScreenOn(false);
}
@@ -1350,16 +1402,13 @@ class PowerManagerService extends IPowerManager.Stub
enableLightSensor(on);
if (!on) {
// make sure button and key backlights are off too
- int brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0,
- brightnessMode);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, 0,
- brightnessMode);
+ mButtonLight.turnOff();
+ mKeyboardLight.turnOff();
// clear current value so we will update based on the new conditions
// when the sensor is reenabled.
mLightSensorValue = -1;
+ // reset our highest light sensor value when the screen turns off
+ mHighestLightSensorValue = -1;
}
}
}
@@ -1377,7 +1426,7 @@ class PowerManagerService extends IPowerManager.Stub
int err;
if (mSpew) {
- Log.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
+ Slog.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
+ " newState=0x" + Integer.toHexString(newState)
+ " noChangeLights=" + noChangeLights
+ " reason=" + reason);
@@ -1408,17 +1457,17 @@ class PowerManagerService extends IPowerManager.Stub
boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
if (mSpew) {
- Log.d(TAG, "setPowerState: mPowerState=" + mPowerState
+ Slog.d(TAG, "setPowerState: mPowerState=" + mPowerState
+ " newState=" + newState + " noChangeLights=" + noChangeLights);
- Log.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
+ Slog.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
+ " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
- Log.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
+ Slog.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
+ " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
- Log.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
+ Slog.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
+ " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
- Log.d(TAG, " oldScreenOn=" + oldScreenOn
+ Slog.d(TAG, " oldScreenOn=" + oldScreenOn
+ " newScreenOn=" + newScreenOn);
- Log.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
+ Slog.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
+ " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
}
@@ -1444,13 +1493,13 @@ class PowerManagerService extends IPowerManager.Stub
// screen forever; see forceReenableScreen().)
boolean reallyTurnScreenOn = true;
if (mSpew) {
- Log.d(TAG, "- turning screen on... mPreventScreenOn = "
+ Slog.d(TAG, "- turning screen on... mPreventScreenOn = "
+ mPreventScreenOn);
}
if (mPreventScreenOn) {
if (mSpew) {
- Log.d(TAG, "- PREVENTING screen from really turning on!");
+ Slog.d(TAG, "- PREVENTING screen from really turning on!");
}
reallyTurnScreenOn = false;
}
@@ -1458,11 +1507,10 @@ class PowerManagerService extends IPowerManager.Stub
err = setScreenStateLocked(true);
long identity = Binder.clearCallingIdentity();
try {
- mBatteryStats.noteScreenBrightness(
- getPreferredBrightness());
+ mBatteryStats.noteScreenBrightness(getPreferredBrightness());
mBatteryStats.noteScreenOn();
} catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
+ Slog.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1472,11 +1520,10 @@ class PowerManagerService extends IPowerManager.Stub
err = 0;
}
- mScreenOnStartTime = SystemClock.elapsedRealtime();
mLastTouchDown = 0;
mTotalTouchDownTime = 0;
mTouchCycles = 0;
- EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 1, reason,
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason,
mTotalTouchDownTime, mTouchCycles);
if (err == 0) {
mPowerState |= SCREEN_ON_BIT;
@@ -1490,7 +1537,7 @@ class PowerManagerService extends IPowerManager.Stub
try {
mBatteryStats.noteScreenOff();
} catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
+ Slog.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1506,18 +1553,14 @@ class PowerManagerService extends IPowerManager.Stub
}
}
}
-
+
private int screenOffFinishedAnimatingLocked(int reason) {
// I don't think we need to check the current state here because all of these
- // Power.setScreenState and sendNotificationLocked can both handle being
+ // Power.setScreenState and sendNotificationLocked can both handle being
// called multiple times in the same state. -joeo
- EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, reason, mTotalTouchDownTime, mTouchCycles);
+ EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, reason, mTotalTouchDownTime, mTouchCycles);
mLastTouchDown = 0;
int err = setScreenStateLocked(false);
- if (mScreenOnStartTime != 0) {
- mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
- mScreenOnStartTime = 0;
- }
if (err == 0) {
mScreenOffReason = reason;
sendNotificationLocked(false, reason);
@@ -1532,27 +1575,29 @@ class PowerManagerService extends IPowerManager.Stub
private void updateLightsLocked(int newState, int forceState) {
final int oldState = mPowerState;
+ newState = applyButtonState(newState);
+ newState = applyKeyboardState(newState);
final int realDifference = (newState ^ oldState);
final int difference = realDifference | forceState;
if (difference == 0) {
return;
}
-
+
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,
- preferredBrightness);
+ Power.BRIGHTNESS_ON);
} else {
- mKeyboardBrightness.setTargetLocked(preferredBrightness,
+ mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS,
Power.BRIGHTNESS_OFF);
}
@@ -1571,9 +1616,9 @@ class PowerManagerService extends IPowerManager.Stub
if ((newState & BUTTON_BRIGHT_BIT) == 0) {
mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- preferredBrightness);
+ Power.BRIGHTNESS_ON);
} else {
- mButtonBrightness.setTargetLocked(preferredBrightness,
+ mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_ON,
ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
Power.BRIGHTNESS_OFF);
}
@@ -1678,14 +1723,14 @@ class PowerManagerService extends IPowerManager.Stub
if (startAnimation) {
if (mSpew) {
- Log.i(TAG, "Scheduling light animator!");
+ Slog.i(TAG, "Scheduling light animator!");
}
mHandler.removeCallbacks(mLightAnimator);
mHandler.post(mLightAnimator);
}
-
+
if (offMask != 0) {
- //Log.i(TAG, "Setting brightess off: " + offMask);
+ if (mSpew) Slog.i(TAG, "Setting brightess off: " + offMask);
setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
}
if (dimMask != 0) {
@@ -1694,7 +1739,7 @@ class PowerManagerService extends IPowerManager.Stub
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
brightness = Power.BRIGHTNESS_LOW_BATTERY;
}
- //Log.i(TAG, "Setting brightess dim " + brightness + ": " + offMask);
+ if (mSpew) Slog.i(TAG, "Setting brightess dim " + brightness + ": " + dimMask);
setLightBrightness(dimMask, brightness);
}
if (onMask != 0) {
@@ -1703,52 +1748,46 @@ class PowerManagerService extends IPowerManager.Stub
brightness > Power.BRIGHTNESS_LOW_BATTERY) {
brightness = Power.BRIGHTNESS_LOW_BATTERY;
}
- //Log.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
+ if (mSpew) Slog.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
setLightBrightness(onMask, brightness);
}
}
private void setLightBrightness(int mask, int value) {
int brightnessMode = (mAutoBrightessEnabled
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
+ ? LightsService.BRIGHTNESS_MODE_SENSOR
+ : LightsService.BRIGHTNESS_MODE_USER);
if ((mask & SCREEN_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, value,
- brightnessMode);
+ mLcdLight.setBrightness(value, brightnessMode);
}
- brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
if ((mask & BUTTON_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, value,
- brightnessMode);
+ mButtonLight.setBrightness(value);
}
if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, value,
- brightnessMode);
+ mKeyboardLight.setBrightness(value);
}
}
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);
}
-
+
boolean setTargetLocked(int target, int stepsToTarget, int initialValue,
int nominalCurrentValue) {
if (!initialized) {
@@ -1763,7 +1802,7 @@ class PowerManagerService extends IPowerManager.Stub
/ stepsToTarget;
if (mSpew) {
String noticeMe = nominalCurrentValue == curValue ? "" : " ******************";
- Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
+ Slog.i(TAG, "Setting target " + mask + ": cur=" + curValue
+ " target=" + targetValue + " delta=" + delta
+ " nominalCurrentValue=" + nominalCurrentValue
+ noticeMe);
@@ -1771,11 +1810,11 @@ class PowerManagerService extends IPowerManager.Stub
animating = true;
return true;
}
-
+
boolean stepLocked() {
if (!animating) return false;
if (false && mSpew) {
- Log.i(TAG, "Step target " + mask + ": cur=" + curValue
+ Slog.i(TAG, "Step target " + mask + ": cur=" + curValue
+ " target=" + targetValue + " delta=" + delta);
}
curValue += delta;
@@ -1795,7 +1834,7 @@ class PowerManagerService extends IPowerManager.Stub
more = false;
}
}
- //Log.i(TAG, "Animating brightess " + curIntValue + ": " + mask);
+ //Slog.i(TAG, "Animating brightess " + curIntValue + ": " + mask);
setLightBrightness(mask, curIntValue);
animating = more;
if (!more) {
@@ -1806,7 +1845,7 @@ class PowerManagerService extends IPowerManager.Stub
return more;
}
}
-
+
private class LightAnimator implements Runnable {
public void run() {
synchronized (mLocks) {
@@ -1824,14 +1863,14 @@ class PowerManagerService extends IPowerManager.Stub
}
}
}
-
+
private int getPreferredBrightness() {
try {
if (mScreenBrightnessOverride >= 0) {
return mScreenBrightnessOverride;
- } else if (mLightSensorBrightness >= 0 && mUseSoftwareAutoBrightness
+ } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
&& mAutoBrightessEnabled) {
- return mLightSensorBrightness;
+ return mLightSensorScreenBrightness;
}
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
SCREEN_BRIGHTNESS);
@@ -1842,6 +1881,48 @@ class PowerManagerService extends IPowerManager.Stub
}
}
+ private int applyButtonState(int state) {
+ int brightness = -1;
+ if ((state & BATTERY_LOW_BIT) != 0) {
+ // do not override brightness if the battery is low
+ return state;
+ }
+ if (mButtonBrightnessOverride >= 0) {
+ brightness = mButtonBrightnessOverride;
+ } else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) {
+ brightness = mLightSensorButtonBrightness;
+ }
+ if (brightness > 0) {
+ return state | BUTTON_BRIGHT_BIT;
+ } else if (brightness == 0) {
+ return state & ~BUTTON_BRIGHT_BIT;
+ } else {
+ return state;
+ }
+ }
+
+ private int applyKeyboardState(int state) {
+ int brightness = -1;
+ if ((state & BATTERY_LOW_BIT) != 0) {
+ // do not override brightness if the battery is low
+ return state;
+ }
+ if (!mKeyboardVisible) {
+ brightness = 0;
+ } else if (mButtonBrightnessOverride >= 0) {
+ brightness = mButtonBrightnessOverride;
+ } else if (mLightSensorKeyboardBrightness >= 0 && mUseSoftwareAutoBrightness) {
+ brightness = mLightSensorKeyboardBrightness;
+ }
+ if (brightness > 0) {
+ return state | KEYBOARD_BRIGHT_BIT;
+ } else if (brightness == 0) {
+ return state & ~KEYBOARD_BRIGHT_BIT;
+ } else {
+ return state;
+ }
+ }
+
public boolean isScreenOn() {
synchronized (mLocks) {
return (mPowerState & SCREEN_ON_BIT) != 0;
@@ -1888,7 +1969,7 @@ class PowerManagerService extends IPowerManager.Stub
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
&& (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
if (false) {
- Log.d(TAG, "dropping cheek or short event mPokey=0x" + Integer.toHexString(mPokey));
+ Slog.d(TAG, "dropping cheek or short event mPokey=0x" + Integer.toHexString(mPokey));
}
return;
}
@@ -1897,22 +1978,22 @@ class PowerManagerService extends IPowerManager.Stub
&& (eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT
|| eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT)) {
if (false) {
- Log.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
+ Slog.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
}
return;
}
if (false) {
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
- Log.d(TAG, "userActivity !!!");//, new RuntimeException());
+ Slog.d(TAG, "userActivity !!!");//, new RuntimeException());
} else {
- Log.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
+ Slog.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
}
}
synchronized (mLocks) {
if (mSpew) {
- Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
+ Slog.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
+ " mUserActivityAllowed=" + mUserActivityAllowed
+ " mUserState=0x" + Integer.toHexString(mUserState)
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
@@ -1921,7 +2002,7 @@ class PowerManagerService extends IPowerManager.Stub
}
// ignore user activity if we are in the process of turning off the screen
if (isScreenTurningOffLocked()) {
- Log.d(TAG, "ignoring user activity while turning off screen");
+ Slog.d(TAG, "ignoring user activity while turning off screen");
return;
}
// Disable proximity sensor if if user presses power key while we are in the
@@ -1950,7 +2031,7 @@ class PowerManagerService extends IPowerManager.Stub
} finally {
Binder.restoreCallingIdentity(ident);
}
-
+
mWakeLockState = mLocks.reactivateScreenLocksLocked();
setPowerState(mUserState | mWakeLockState, noChangeLights,
WindowManagerPolicy.OFF_BECAUSE_OF_USER);
@@ -1958,6 +2039,10 @@ class PowerManagerService extends IPowerManager.Stub
}
}
}
+
+ if (mPolicy != null) {
+ mPolicy.userActivity();
+ }
}
private int getAutoBrightnessValue(int sensorValue, int[] values) {
@@ -1971,7 +2056,7 @@ class PowerManagerService extends IPowerManager.Stub
return values[i];
} catch (Exception e) {
// guard against null pointer or index out of bounds errors
- Log.e(TAG, "getAutoBrightnessValue", e);
+ Slog.e(TAG, "getAutoBrightnessValue", e);
return 255;
}
}
@@ -2002,15 +2087,40 @@ class PowerManagerService extends IPowerManager.Stub
}
};
+ private void dockStateChanged(int state) {
+ synchronized (mLocks) {
+ mIsDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ if (mIsDocked) {
+ mHighestLightSensorValue = -1;
+ }
+ if ((mPowerState & SCREEN_ON_BIT) != 0) {
+ // force lights recalculation
+ int value = (int)mLightSensorValue;
+ mLightSensorValue = -1;
+ lightSensorChangedLocked(value);
+ }
+ }
+ }
+
private void lightSensorChangedLocked(int value) {
if (mDebugLightSensor) {
- Log.d(TAG, "lightSensorChangedLocked " + value);
+ Slog.d(TAG, "lightSensorChangedLocked " + value);
+ }
+
+ // do not allow light sensor value to decrease
+ if (mHighestLightSensorValue < value) {
+ mHighestLightSensorValue = value;
}
if (mLightSensorValue != value) {
mLightSensorValue = value;
if ((mPowerState & BATTERY_LOW_BIT) == 0) {
- int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
+ // use maximum light sensor value seen since screen went on for LCD to avoid flicker
+ // we only do this if we are undocked, since lighting should be stable when
+ // stationary in a dock.
+ int lcdValue = getAutoBrightnessValue(
+ (mIsDocked ? value : mHighestLightSensorValue),
+ mLcdBacklightValues);
int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
int keyboardValue;
if (mKeyboardVisible) {
@@ -2018,12 +2128,14 @@ class PowerManagerService extends IPowerManager.Stub
} else {
keyboardValue = 0;
}
- mLightSensorBrightness = lcdValue;
+ mLightSensorScreenBrightness = lcdValue;
+ mLightSensorButtonBrightness = buttonValue;
+ mLightSensorKeyboardBrightness = keyboardValue;
if (mDebugLightSensor) {
- Log.d(TAG, "lcdValue " + lcdValue);
- Log.d(TAG, "buttonValue " + buttonValue);
- Log.d(TAG, "keyboardValue " + keyboardValue);
+ Slog.d(TAG, "lcdValue " + lcdValue);
+ Slog.d(TAG, "buttonValue " + buttonValue);
+ Slog.d(TAG, "keyboardValue " + keyboardValue);
}
boolean startAnimation = false;
@@ -2036,41 +2148,36 @@ class PowerManagerService extends IPowerManager.Stub
}
} else {
int brightnessMode = (mAutoBrightessEnabled
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
- lcdValue, brightnessMode);
+ ? LightsService.BRIGHTNESS_MODE_SENSOR
+ : LightsService.BRIGHTNESS_MODE_USER);
+ mLcdLight.setBrightness(lcdValue, brightnessMode);
}
}
- if (ANIMATE_BUTTON_LIGHTS) {
- if (mButtonBrightness.setTargetLocked(buttonValue,
- AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- (int)mButtonBrightness.curValue)) {
- startAnimation = true;
+ if (mButtonBrightnessOverride < 0) {
+ if (ANIMATE_BUTTON_LIGHTS) {
+ if (mButtonBrightness.setTargetLocked(buttonValue,
+ AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+ (int)mButtonBrightness.curValue)) {
+ startAnimation = true;
+ }
+ } else {
+ mButtonLight.setBrightness(buttonValue);
}
- } else {
- int brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
- buttonValue, brightnessMode);
- }
- if (ANIMATE_KEYBOARD_LIGHTS) {
- if (mKeyboardBrightness.setTargetLocked(keyboardValue,
- AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
- (int)mKeyboardBrightness.curValue)) {
- startAnimation = true;
+ }
+ if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
+ if (ANIMATE_KEYBOARD_LIGHTS) {
+ if (mKeyboardBrightness.setTargetLocked(keyboardValue,
+ AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+ (int)mKeyboardBrightness.curValue)) {
+ startAnimation = true;
+ }
+ } else {
+ mKeyboardLight.setBrightness(keyboardValue);
}
- } else {
- int brightnessMode = (mUseSoftwareAutoBrightness
- ? HardwareService.BRIGHTNESS_MODE_SENSOR
- : HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
- keyboardValue, brightnessMode);
}
if (startAnimation) {
if (mDebugLightSensor) {
- Log.i(TAG, "lightSensorChangedLocked scheduling light animator");
+ Slog.i(TAG, "lightSensorChangedLocked scheduling light animator");
}
mHandler.removeCallbacks(mLightAnimator);
mHandler.post(mLightAnimator);
@@ -2085,26 +2192,74 @@ class PowerManagerService extends IPowerManager.Stub
*/
public void goToSleep(long time)
{
+ goToSleepWithReason(time, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ }
+
+ /**
+ * The user requested that we go to sleep (probably with the power button).
+ * This overrides all wake locks that are held.
+ */
+ public void goToSleepWithReason(long time, int reason)
+ {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
synchronized (mLocks) {
- goToSleepLocked(time, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ goToSleepLocked(time, reason);
}
}
-
+
/**
- * Returns the time the screen has been on since boot, in millis.
- * @return screen on time
+ * Reboot the device immediately, passing 'reason' (may be null)
+ * to the underlying __reboot system call. Should not return.
*/
- public long getScreenOnTime() {
- synchronized (mLocks) {
- if (mScreenOnStartTime == 0) {
- return mScreenOnTime;
- } else {
- return SystemClock.elapsedRealtime() - mScreenOnStartTime + mScreenOnTime;
+ public void reboot(String reason)
+ {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+ if (mHandler == null || !ActivityManagerNative.isSystemReady()) {
+ throw new IllegalStateException("Too early to call reboot()");
+ }
+
+ final String finalReason = reason;
+ Runnable runnable = new Runnable() {
+ public void run() {
+ synchronized (this) {
+ ShutdownThread.reboot(mContext, finalReason, false);
+ }
+
+ }
+ };
+ // ShutdownThread must run on a looper capable of displaying the UI.
+ mHandler.post(runnable);
+
+ // PowerManager.reboot() is documented not to return so just wait for the inevitable.
+ synchronized (runnable) {
+ while (true) {
+ try {
+ runnable.wait();
+ } catch (InterruptedException e) {
+ }
}
}
}
+ /**
+ * Crash the runtime (causing a complete restart of the Android framework).
+ * Requires REBOOT permission. Mostly for testing. Should not return.
+ */
+ public void crash(final String message)
+ {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+ Thread t = new Thread("PowerManagerService.crash()") {
+ public void run() { throw new RuntimeException(message); }
+ };
+ try {
+ t.start();
+ t.join();
+ } catch (InterruptedException e) {
+ Log.wtf(TAG, e);
+ }
+ }
+
private void goToSleepLocked(long time, int reason) {
if (mLastEventTime <= time) {
@@ -2120,7 +2275,7 @@ class PowerManagerService extends IPowerManager.Stub
numCleared++;
}
}
- EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared);
+ EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared);
mStillNeedSleepNotification = true;
mUserState = SCREEN_OFF;
setPowerState(SCREEN_OFF, false, reason);
@@ -2136,11 +2291,11 @@ class PowerManagerService extends IPowerManager.Stub
return SystemClock.elapsedRealtime() - mScreenOffTime;
}
}
-
+
public void setKeyboardVisibility(boolean visible) {
synchronized (mLocks) {
if (mSpew) {
- Log.d(TAG, "setKeyboardVisibility: " + visible);
+ Slog.d(TAG, "setKeyboardVisibility: " + visible);
}
if (mKeyboardVisible != visible) {
mKeyboardVisible = visible;
@@ -2169,7 +2324,7 @@ class PowerManagerService extends IPowerManager.Stub
*/
public void enableUserActivity(boolean enabled) {
if (mSpew) {
- Log.d(TAG, "enableUserActivity " + enabled);
+ Slog.d(TAG, "enableUserActivity " + enabled);
}
synchronized (mLocks) {
mUserActivityAllowed = enabled;
@@ -2202,7 +2357,7 @@ class PowerManagerService extends IPowerManager.Stub
* */
private void setScreenOffTimeoutsLocked() {
if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
- mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices
+ mKeylightDelay = mShortKeylightDelay; // Configurable via secure settings
mDimDelay = -1;
mScreenOffDelay = 0;
} else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
@@ -2210,7 +2365,10 @@ class PowerManagerService extends IPowerManager.Stub
mDimDelay = -1;
mScreenOffDelay = 0;
} else {
- int totalDelay = mTotalDelaySetting;
+ int totalDelay = mScreenOffTimeoutSetting;
+ if (totalDelay > mMaximumScreenOffTimeout) {
+ totalDelay = mMaximumScreenOffTimeout;
+ }
mKeylightDelay = LONG_KEYLIGHT_DELAY;
if (totalDelay < 0) {
mScreenOffDelay = Integer.MAX_VALUE;
@@ -2230,35 +2388,22 @@ class PowerManagerService extends IPowerManager.Stub
}
}
if (mSpew) {
- Log.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
+ Slog.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).
+ * Refreshes cached secure settings. Called once on startup, and
+ * on subsequent changes to secure settings.
*/
- private void updateGservicesValues() {
- mShortKeylightDelay = Settings.Gservices.getInt(
+ private void updateSettingsValues() {
+ mShortKeylightDelay = Settings.Secure.getInt(
mContext.getContentResolver(),
- Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS,
+ Settings.Secure.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();
- }
+ // Slog.i(TAG, "updateSettingsValues(): mShortKeylightDelay now " + mShortKeylightDelay);
}
private class LockList extends ArrayList<WakeLock>
@@ -2306,7 +2451,7 @@ class PowerManagerService extends IPowerManager.Stub
}
return result;
}
-
+
int reactivateScreenLocksLocked()
{
int result = 0;
@@ -2339,7 +2484,7 @@ class PowerManagerService extends IPowerManager.Stub
}
return mPolicy;
}
-
+
void systemReady() {
mSensorManager = new SensorManager(mHandlerThread.getLooper());
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
@@ -2349,9 +2494,21 @@ class PowerManagerService extends IPowerManager.Stub
enableLightSensor(true);
}
+ // wait until sensors are enabled before turning on screen.
+ // some devices will not activate the light sensor properly on boot
+ // unless we do this.
+ if (mUseSoftwareAutoBrightness) {
+ // turn the screen on
+ setPowerState(SCREEN_BRIGHT);
+ } else {
+ // turn everything on
+ setPowerState(ALL_BRIGHT);
+ }
+
synchronized (mLocks) {
- Log.d(TAG, "system ready!");
+ Slog.d(TAG, "system ready!");
mDoneBooting = true;
+
long identity = Binder.clearCallingIdentity();
try {
mBatteryStats.noteScreenBrightness(getPreferredBrightness());
@@ -2365,7 +2522,7 @@ class PowerManagerService extends IPowerManager.Stub
}
void bootCompleted() {
- Log.d(TAG, "bootCompleted");
+ Slog.d(TAG, "bootCompleted");
synchronized (mLocks) {
mBootCompleted = true;
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
@@ -2394,17 +2551,14 @@ class PowerManagerService extends IPowerManager.Stub
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
// Don't let applications turn the screen all the way off
brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness,
- HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
- (mKeyboardVisible ? brightness : 0), HardwareService.BRIGHTNESS_MODE_USER);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness,
- HardwareService.BRIGHTNESS_MODE_USER);
+ mLcdLight.setBrightness(brightness);
+ mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0);
+ mButtonLight.setBrightness(brightness);
long identity = Binder.clearCallingIdentity();
try {
mBatteryStats.noteScreenBrightness(brightness);
} catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
+ Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2427,9 +2581,14 @@ class PowerManagerService extends IPowerManager.Stub
}
}
+ public void setAttentionLight(boolean on, int color) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ mAttentionLight.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ }
+
private void enableProximityLockLocked() {
if (mDebugProximitySensor) {
- Log.d(TAG, "enableProximityLockLocked");
+ Slog.d(TAG, "enableProximityLockLocked");
}
if (!mProximitySensorEnabled) {
// clear calling identity so sensor manager battery stats are accurate
@@ -2446,7 +2605,7 @@ class PowerManagerService extends IPowerManager.Stub
private void disableProximityLockLocked() {
if (mDebugProximitySensor) {
- Log.d(TAG, "disableProximityLockLocked");
+ Slog.d(TAG, "disableProximityLockLocked");
}
if (mProximitySensorEnabled) {
// clear calling identity so sensor manager battery stats are accurate
@@ -2470,10 +2629,10 @@ class PowerManagerService extends IPowerManager.Stub
private void proximityChangedLocked(boolean active) {
if (mDebugProximitySensor) {
- Log.d(TAG, "proximityChangedLocked, active: " + active);
+ Slog.d(TAG, "proximityChangedLocked, active: " + active);
}
if (!mProximitySensorEnabled) {
- Log.d(TAG, "Ignoring proximity change after sensor is disabled");
+ Slog.d(TAG, "Ignoring proximity change after sensor is disabled");
return;
}
if (active) {
@@ -2496,7 +2655,7 @@ class PowerManagerService extends IPowerManager.Stub
private void enableLightSensor(boolean enable) {
if (mDebugLightSensor) {
- Log.d(TAG, "enableLightSensor " + enable);
+ Slog.d(TAG, "enableLightSensor " + enable);
}
if (mSensorManager != null && mLightSensorEnabled != enable) {
mLightSensorEnabled = enable;
@@ -2531,7 +2690,7 @@ class PowerManagerService extends IPowerManager.Stub
distance < mProximitySensor.getMaximumRange());
if (mDebugProximitySensor) {
- Log.d(TAG, "mProximityListener.onSensorChanged active: " + active);
+ Slog.d(TAG, "mProximityListener.onSensorChanged active: " + active);
}
if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
// enforce delaying atleast PROXIMITY_SENSOR_DELAY before processing
@@ -2571,7 +2730,7 @@ class PowerManagerService extends IPowerManager.Stub
int value = (int)event.values[0];
long milliseconds = SystemClock.elapsedRealtime();
if (mDebugLightSensor) {
- Log.d(TAG, "onSensorChanged: light value: " + value);
+ Slog.d(TAG, "onSensorChanged: light value: " + value);
}
mHandler.removeCallbacks(mAutoBrightnessTask);
if (mLightSensorValue != value) {
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index ac3b723..a02c4e7 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -21,7 +21,7 @@ import static android.os.Process.*;
import android.os.Process;
import android.os.SystemClock;
import android.util.Config;
-import android.util.Log;
+import android.util.Slog;
import java.io.File;
import java.io.FileInputStream;
@@ -289,11 +289,11 @@ public class ProcessStats {
mRelIdleTime = (int)(idletime - mBaseIdleTime);
if (false) {
- Log.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
+ Slog.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
+ Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
+ " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
}
@@ -331,7 +331,7 @@ public class ProcessStats {
// Update an existing process...
st.added = false;
curStatsIndex++;
- if (localLOGV) Log.v(TAG, "Existing pid " + pid + ": " + st);
+ if (localLOGV) Slog.v(TAG, "Existing pid " + pid + ": " + st);
final long[] procStats = mProcessStatsData;
if (!Process.readProcFile(st.statFile.toString(),
@@ -376,7 +376,7 @@ public class ProcessStats {
st.rel_majfaults = (int)(majfaults - st.base_majfaults);
st.base_minfaults = minfaults;
st.base_majfaults = majfaults;
- //Log.i("Load", "Stats changed " + name + " pid=" + st.pid
+ //Slog.i("Load", "Stats changed " + name + " pid=" + st.pid
// + " name=" + st.name + " utime=" + utime
// + " stime=" + stime);
workingProcs.add(st);
@@ -389,7 +389,7 @@ public class ProcessStats {
allProcs.add(curStatsIndex, st);
curStatsIndex++;
NS++;
- if (localLOGV) Log.v(TAG, "New pid " + pid + ": " + st);
+ if (localLOGV) Slog.v(TAG, "New pid " + pid + ": " + st);
final String[] procStatsString = mProcessFullStatsStringData;
final long[] procStats = mProcessFullStatsData;
@@ -419,7 +419,7 @@ public class ProcessStats {
}
}
- //Log.i("Load", "New process: " + st.pid + " " + st.name);
+ //Slog.i("Load", "New process: " + st.pid + " " + st.name);
st.rel_utime = 0;
st.rel_stime = 0;
st.rel_minfaults = 0;
@@ -440,7 +440,7 @@ public class ProcessStats {
workingProcs.add(st);
allProcs.remove(curStatsIndex);
NS--;
- if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st);
+ if (localLOGV) Slog.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--;
@@ -458,7 +458,7 @@ public class ProcessStats {
workingProcs.add(st);
allProcs.remove(curStatsIndex);
NS--;
- if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st);
+ if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
}
return pids;
@@ -523,11 +523,11 @@ public class ProcessStats {
speed++;
if (speed == MAX_SPEEDS) break; // No more
if (localLOGV && out == null) {
- Log.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+ Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+ "\t" + tempTimes[speed - 1]);
}
} catch (NumberFormatException nfe) {
- Log.i(TAG, "Unable to parse time_in_state");
+ Slog.i(TAG, "Unable to parse time_in_state");
}
}
}
diff --git a/services/java/com/android/server/RandomBlock.java b/services/java/com/android/server/RandomBlock.java
index f7847ec..cc22bd9 100644
--- a/services/java/com/android/server/RandomBlock.java
+++ b/services/java/com/android/server/RandomBlock.java
@@ -16,7 +16,7 @@
package com.android.server;
-import android.util.Log;
+import android.util.Slog;
import java.io.Closeable;
import java.io.DataOutput;
@@ -39,7 +39,7 @@ class RandomBlock {
private RandomBlock() { }
static RandomBlock fromFile(String filename) throws IOException {
- if (DEBUG) Log.v(TAG, "reading from file " + filename);
+ if (DEBUG) Slog.v(TAG, "reading from file " + filename);
InputStream stream = null;
try {
stream = new FileInputStream(filename);
@@ -63,7 +63,7 @@ class RandomBlock {
}
void toFile(String filename) throws IOException {
- if (DEBUG) Log.v(TAG, "writing to file " + filename);
+ if (DEBUG) Slog.v(TAG, "writing to file " + filename);
RandomAccessFile out = null;
try {
out = new RandomAccessFile(filename, "rws");
@@ -95,7 +95,7 @@ class RandomBlock {
}
c.close();
} catch (IOException e) {
- Log.w(TAG, "IOException thrown while closing Closeable", e);
+ Slog.w(TAG, "IOException thrown while closing Closeable", e);
}
}
}
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java
new file mode 100644
index 0000000..8e55512
--- /dev/null
+++ b/services/java/com/android/server/RecognitionManagerService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.content.PackageMonitor;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.provider.Settings;
+import android.speech.RecognitionService;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.util.List;
+
+public class RecognitionManagerService extends Binder {
+ final static String TAG = "RecognitionManagerService";
+
+ final Context mContext;
+ final MyPackageMonitor mMonitor;
+
+ class MyPackageMonitor extends PackageMonitor {
+ public void onSomePackagesChanged() {
+ ComponentName comp = getCurRecognizer();
+ if (comp == null) {
+ if (anyPackagesAppearing()) {
+ comp = findAvailRecognizer(null);
+ if (comp != null) {
+ setCurRecognizer(comp);
+ }
+ }
+ return;
+ }
+
+ int change = isPackageDisappearing(comp.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ setCurRecognizer(findAvailRecognizer(null));
+
+ } else if (isPackageModified(comp.getPackageName())) {
+ setCurRecognizer(findAvailRecognizer(comp.getPackageName()));
+ }
+ }
+ }
+
+ RecognitionManagerService(Context context) {
+ mContext = context;
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
+ }
+
+ public void systemReady() {
+ ComponentName comp = getCurRecognizer();
+ if (comp != null) {
+ // See if the current recognizer is no longer available.
+ try {
+ mContext.getPackageManager().getServiceInfo(comp, 0);
+ } catch (NameNotFoundException e) {
+ setCurRecognizer(null);
+ }
+ } else {
+ comp = findAvailRecognizer(null);
+ if (comp != null) {
+ setCurRecognizer(comp);
+ }
+ }
+ }
+
+ ComponentName findAvailRecognizer(String prefPackage) {
+ List<ResolveInfo> available =
+ mContext.getPackageManager().queryIntentServices(
+ new Intent(RecognitionService.SERVICE_INTERFACE), 0);
+ int numAvailable = available.size();
+
+ if (numAvailable == 0) {
+ Slog.w(TAG, "no available voice recognition services found");
+ return null;
+ } else {
+ if (prefPackage != null) {
+ for (int i=0; i<numAvailable; i++) {
+ ServiceInfo serviceInfo = available.get(i).serviceInfo;
+ if (prefPackage.equals(serviceInfo.packageName)) {
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+ }
+ if (numAvailable > 1) {
+ Slog.w(TAG, "more than one voice recognition service found, picking first");
+ }
+
+ ServiceInfo serviceInfo = available.get(0).serviceInfo;
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+
+ ComponentName getCurRecognizer() {
+ String curRecognizer = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ if (TextUtils.isEmpty(curRecognizer)) {
+ return null;
+ }
+ return ComponentName.unflattenFromString(curRecognizer);
+ }
+
+ void setCurRecognizer(ComponentName comp) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ comp != null ? comp.flattenToShortString() : "");
+ }
+}
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index 4dfeb9d..9f5718f 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -23,8 +23,12 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.util.Config;
-import android.util.Log;
+import android.util.Slog;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import com.android.internal.app.IBatteryStats;
@@ -43,6 +47,7 @@ class SensorService extends ISensorService.Stub {
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
private static final int SENSOR_DISABLE = -1;
+ private int mCurrentDelay = 0;
/**
* Battery statistics to be updated when sensors are enabled and disabled.
@@ -51,17 +56,19 @@ class SensorService extends ISensorService.Stub {
private final class Listener implements IBinder.DeathRecipient {
final IBinder mToken;
+ final int mUid;
int mSensors = 0;
int mDelay = 0x7FFFFFFF;
- Listener(IBinder token) {
+ Listener(IBinder token, int uid) {
mToken = token;
+ mUid = uid;
}
void addSensor(int sensor, int delay) {
mSensors |= (1<<sensor);
- if (mDelay > delay)
+ if (delay < mDelay)
mDelay = delay;
}
@@ -74,7 +81,7 @@ class SensorService extends ISensorService.Stub {
}
public void binderDied() {
- if (localLOGV) Log.d(TAG, "sensor listener died");
+ if (localLOGV) Slog.d(TAG, "sensor listener died");
synchronized(mListeners) {
mListeners.remove(this);
mToken.unlinkToDeath(this, 0);
@@ -83,16 +90,20 @@ class SensorService extends ISensorService.Stub {
for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) {
if (hasSensor(sensor)) {
removeSensor(sensor);
+ deactivateIfUnusedLocked(sensor);
try {
- deactivateIfUnusedLocked(sensor);
+ mBatteryStats.noteStopSensor(mUid, sensor);
} catch (RemoteException e) {
- Log.w(TAG, "RemoteException in binderDied");
+ // oops. not a big deal.
}
}
}
if (mListeners.size() == 0) {
_sensors_control_wake();
_sensors_control_close();
+ } else {
+ // TODO: we should recalculate the delay, since removing
+ // a listener may increase the overall rate.
}
mListeners.notify();
}
@@ -101,7 +112,7 @@ class SensorService extends ISensorService.Stub {
@SuppressWarnings("unused")
public SensorService(Context context) {
- if (localLOGV) Log.d(TAG, "SensorService startup");
+ if (localLOGV) Slog.d(TAG, "SensorService startup");
_sensors_control_init();
}
@@ -113,86 +124,151 @@ class SensorService extends ISensorService.Stub {
}
public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
- throws RemoteException {
- if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
+ throws RemoteException {
- // 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 (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
if (binder == null) {
- Log.w(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")");
+ Slog.e(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")");
+ return false;
+ }
+
+ if (enable < 0 && (enable != SENSOR_DISABLE)) {
+ Slog.e(TAG, "invalid enable parameter (enable=" + enable +
+ ", sensor=" + name + ", id=" + sensor + ")");
return false;
}
+ boolean res;
+ int uid = Binder.getCallingUid();
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;
+ res = enableSensorInternalLocked(binder, uid, name, sensor, enable);
+ if (res == true) {
+ // Inform battery statistics service of status change
+ long identity = Binder.clearCallingIdentity();
+ if (enable == SENSOR_DISABLE) {
+ mBatteryStats.noteStopSensor(uid, sensor);
+ } else {
+ mBatteryStats.noteStartSensor(uid, sensor);
}
- if (minDelay > listener.mDelay)
- minDelay = listener.mDelay;
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return res;
+ }
+
+ private boolean enableSensorInternalLocked(IBinder binder, int uid,
+ String name, int sensor, int enable) throws RemoteException {
+
+ // check if we have this listener
+ Listener l = null;
+ for (Listener listener : mListeners) {
+ if (binder == listener.mToken) {
+ l = listener;
+ break;
}
-
- if (l == null && enable!=SENSOR_DISABLE) {
- l = new Listener(binder);
+ }
+
+ if (enable != SENSOR_DISABLE) {
+ // Activate the requested sensor
+ if (_sensors_control_activate(sensor, true) == false) {
+ Slog.w(TAG, "could not enable sensor " + sensor);
+ return false;
+ }
+
+ if (l == null) {
+ /*
+ * we don't have a listener for this binder yet, so
+ * create a new one and add it to the list.
+ */
+ l = new Listener(binder, uid);
binder.linkToDeath(l, 0);
mListeners.add(l);
mListeners.notify();
}
-
+
+ // take note that this sensor is now used by this client
+ l.addSensor(sensor, enable);
+
+ } else {
+
if (l == null) {
- // by construction, this means we're disabling a listener we
- // don't know about...
- Log.w(TAG, "listener with binder " + binder +
- ", doesn't exist (sensor=" + name + ", id=" + sensor + ")");
+ /*
+ * This client isn't in the list, this usually happens
+ * when enabling the sensor failed, but the client
+ * didn't handle the error and later tries to shut that
+ * sensor off.
+ */
+ Slog.w(TAG, "listener with binder " + binder +
+ ", doesn't exist (sensor=" + name +
+ ", id=" + sensor + ")");
return false;
}
-
- if (minDelay >= 0) {
- _sensors_control_set_delay(minDelay);
- }
-
- if (enable != SENSOR_DISABLE) {
- l.addSensor(sensor, enable);
- } else {
- l.removeSensor(sensor);
- deactivateIfUnusedLocked(sensor);
- if (l.mSensors == 0) {
- mListeners.remove(l);
- binder.unlinkToDeath(l, 0);
- mListeners.notify();
+
+ // remove this sensor from this client
+ l.removeSensor(sensor);
+
+ // see if we need to deactivate this sensors=
+ deactivateIfUnusedLocked(sensor);
+
+ // if the listener doesn't have any more sensors active
+ // we can get rid of it
+ if (l.mSensors == 0) {
+ // we won't need this death notification anymore
+ binder.unlinkToDeath(l, 0);
+ // remove the listener from the list
+ mListeners.remove(l);
+ // and if the list is empty, turn off the whole sensor h/w
+ if (mListeners.size() == 0) {
+ _sensors_control_wake();
+ _sensors_control_close();
}
+ mListeners.notify();
}
-
- if (mListeners.size() == 0) {
- _sensors_control_wake();
- _sensors_control_close();
- }
- }
+ }
+
+ // calculate and set the new delay
+ int minDelay = 0x7FFFFFFF;
+ for (Listener listener : mListeners) {
+ if (listener.mDelay < minDelay)
+ minDelay = listener.mDelay;
+ }
+ if (minDelay != 0x7FFFFFFF) {
+ mCurrentDelay = minDelay;
+ _sensors_control_set_delay(minDelay);
+ }
+
return true;
}
- private void deactivateIfUnusedLocked(int sensor) throws RemoteException {
+ private void deactivateIfUnusedLocked(int sensor) {
int size = mListeners.size();
for (int i=0 ; i<size ; i++) {
- if (mListeners.get(i).hasSensor(sensor))
+ if (mListeners.get(i).hasSensor(sensor)) {
+ // this sensor is still in use, don't turn it off
return;
+ }
+ }
+ if (_sensors_control_activate(sensor, false) == false) {
+ Slog.w(TAG, "could not disable sensor " + sensor);
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mListeners) {
+ Printer pr = new PrintWriterPrinter(pw);
+ int c = 0;
+ pr.println(mListeners.size() + " listener(s), delay=" + mCurrentDelay + " ms");
+ for (Listener l : mListeners) {
+ pr.println("listener[" + c + "] " +
+ "sensors=0x" + Integer.toString(l.mSensors, 16) +
+ ", uid=" + l.mUid +
+ ", delay=" +
+ l.mDelay + " ms");
+ c++;
+ }
}
- _sensors_control_activate(sensor, false);
}
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/java/com/android/server/ShutdownActivity.java
index 7f0e90d..64b9c5d 100644
--- a/services/java/com/android/server/ShutdownActivity.java
+++ b/services/java/com/android/server/ShutdownActivity.java
@@ -21,7 +21,7 @@ import android.content.BroadcastReceiver;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.app.ShutdownThread;
public class ShutdownActivity extends Activity {
@@ -34,7 +34,7 @@ public class ShutdownActivity extends Activity {
super.onCreate(savedInstanceState);
mConfirm = getIntent().getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
- Log.i(TAG, "onCreate(): confirm=" + mConfirm);
+ Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
Handler h = new Handler();
h.post(new Runnable() {
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 67abe55..fff1874 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -16,17 +16,17 @@
package com.android.server;
-import android.backup.AbsoluteFileBackupHelper;
-import android.backup.BackupDataInput;
-import android.backup.BackupDataInputStream;
-import android.backup.BackupDataOutput;
-import android.backup.BackupHelper;
-import android.backup.BackupHelperAgent;
+import android.app.backup.AbsoluteFileBackupHelper;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.app.backup.BackupAgentHelper;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.ServiceManager;
import android.os.SystemService;
-import android.util.Log;
+import android.util.Slog;
import java.io.File;
import java.io.IOException;
@@ -34,7 +34,7 @@ import java.io.IOException;
/**
* Backup agent for various system-managed data, currently just the system wallpaper
*/
-public class SystemBackupAgent extends BackupHelperAgent {
+public class SystemBackupAgent extends BackupAgentHelper {
private static final String TAG = "SystemBackupAgent";
// These paths must match what the WallpaperManagerService uses
@@ -77,7 +77,7 @@ public class SystemBackupAgent extends BackupHelperAgent {
} catch (IOException ex) {
// If there was a failure, delete everything for the wallpaper, this is too aggresive,
// but this is hopefully a rare failure.
- Log.d(TAG, "restore failed", ex);
+ Slog.d(TAG, "restore failed", ex);
(new File(WALLPAPER_IMAGE)).delete();
(new File(WALLPAPER_INFO)).delete();
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b8cf844..9d5d035 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -18,9 +18,11 @@ package com.android.server;
import com.android.server.am.ActivityManagerService;
import com.android.server.status.StatusBarService;
+import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import dalvik.system.VMRuntime;
+import dalvik.system.Zygote;
import android.app.ActivityManagerNative;
import android.bluetooth.BluetoothAdapter;
@@ -40,9 +42,10 @@ import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import android.accounts.AccountManagerService;
+import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
@@ -69,21 +72,21 @@ class ServerThread extends Thread {
@Override
public void run() {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN,
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
SystemClock.uptimeMillis());
- ActivityManagerService.prepareTraceFile(false); // create dir
-
Looper.prepare();
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
+ BinderInternal.disableBackgroundScheduling(true);
+
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);
- HardwareService hardware = null;
+ LightsService lights = null;
PowerManagerService power = null;
BatteryService battery = null;
ConnectivityService connectivity = null;
@@ -94,25 +97,28 @@ class ServerThread extends Thread {
BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
DockObserver dock = null;
+ UiModeManagerService uiMode = null;
+ RecognitionManagerService recognition = null;
+ ThrottleService throttle = null;
// Critical services...
try {
- Log.i(TAG, "Entropy Service");
+ Slog.i(TAG, "Entropy Service");
ServiceManager.addService("entropy", new EntropyService());
- Log.i(TAG, "Power Manager");
+ Slog.i(TAG, "Power Manager");
power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);
- Log.i(TAG, "Activity Manager");
+ Slog.i(TAG, "Activity Manager");
context = ActivityManagerService.main(factoryTest);
- Log.i(TAG, "Telephony Registry");
+ Slog.i(TAG, "Telephony Registry");
ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
AttributeCache.init(context);
- Log.i(TAG, "Package Manager");
+ Slog.i(TAG, "Package Manager");
pm = PackageManagerService.main(context,
factoryTest != SystemServer.FACTORY_TEST_OFF);
@@ -122,45 +128,47 @@ class ServerThread extends Thread {
// The AccountManager must come before the ContentService
try {
- Log.i(TAG, "Account Manager");
+ Slog.i(TAG, "Account Manager");
ServiceManager.addService(Context.ACCOUNT_SERVICE,
new AccountManagerService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Account Manager", e);
+ Slog.e(TAG, "Failure starting Account Manager", e);
}
- Log.i(TAG, "Content Manager");
+ Slog.i(TAG, "Content Manager");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
- Log.i(TAG, "System Content Providers");
+ Slog.i(TAG, "System Content Providers");
ActivityManagerService.installSystemProviders();
- Log.i(TAG, "Battery Service");
+ Slog.i(TAG, "Battery Service");
battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
- Log.i(TAG, "Hardware Service");
- hardware = new HardwareService(context);
- ServiceManager.addService("hardware", hardware);
+ Slog.i(TAG, "Lights Service");
+ lights = new LightsService(context);
+
+ Slog.i(TAG, "Vibrator Service");
+ ServiceManager.addService("vibrator", new VibratorService(context));
// only initialize the power service after we have started the
- // hardware service, content providers and the battery service.
- power.init(context, hardware, ActivityManagerService.getDefault(), battery);
+ // lights service, content providers and the battery service.
+ power.init(context, lights, ActivityManagerService.getDefault(), battery);
- Log.i(TAG, "Alarm Manager");
+ Slog.i(TAG, "Alarm Manager");
AlarmManagerService alarm = new AlarmManagerService(context);
ServiceManager.addService(Context.ALARM_SERVICE, alarm);
- Log.i(TAG, "Init Watchdog");
+ Slog.i(TAG, "Init Watchdog");
Watchdog.getInstance().init(context, battery, power, alarm,
ActivityManagerService.self());
// Sensor Service is needed by Window Manager, so this goes first
- Log.i(TAG, "Sensor Service");
+ Slog.i(TAG, "Sensor Service");
ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context));
- Log.i(TAG, "Window Manager");
+ Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
@@ -172,13 +180,13 @@ class ServerThread extends Thread {
// 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)");
+ Slog.i(TAG, "Registering null Bluetooth Service (emulator)");
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
} else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
- Log.i(TAG, "Registering null Bluetooth Service (factory test)");
+ Slog.i(TAG, "Registering null Bluetooth Service (factory test)");
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
} else {
- Log.i(TAG, "Bluetooth Service");
+ Slog.i(TAG, "Bluetooth Service");
bluetooth = new BluetoothService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
bluetooth.initAfterRegistration();
@@ -194,168 +202,219 @@ class ServerThread extends Thread {
}
} catch (RuntimeException e) {
- Log.e("System", "Failure starting core service", e);
+ Slog.e("System", "Failure starting core service", e);
}
+ DevicePolicyManagerService devicePolicy = null;
StatusBarService statusBar = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
+ LocationManagerService location = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
- Log.i(TAG, "Status Bar");
+ Slog.i(TAG, "Device Policy");
+ devicePolicy = new DevicePolicyManagerService(context);
+ ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting DevicePolicyService", e);
+ }
+
+ try {
+ Slog.i(TAG, "Status Bar");
statusBar = new StatusBarService(context);
- ServiceManager.addService("statusbar", statusBar);
+ ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting StatusBarService", e);
+ Slog.e(TAG, "Failure starting StatusBarService", e);
}
try {
- Log.i(TAG, "Clipboard Service");
- ServiceManager.addService("clipboard", new ClipboardService(context));
+ Slog.i(TAG, "Clipboard Service");
+ ServiceManager.addService(Context.CLIPBOARD_SERVICE,
+ new ClipboardService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Clipboard Service", e);
+ Slog.e(TAG, "Failure starting Clipboard Service", e);
}
try {
- Log.i(TAG, "Input Method Service");
+ Slog.i(TAG, "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);
+ Slog.e(TAG, "Failure starting Input Manager Service", e);
}
try {
- Log.i(TAG, "NetStat Service");
+ Slog.i(TAG, "NetStat Service");
ServiceManager.addService("netstat", new NetStatService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting NetStat Service", e);
+ Slog.e(TAG, "Failure starting NetStat Service", e);
+ }
+
+ try {
+ Slog.i(TAG, "NetworkManagement Service");
+ ServiceManager.addService(
+ Context.NETWORKMANAGEMENT_SERVICE, new NetworkManagementService(context));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting NetworkManagement Service", e);
}
try {
- Log.i(TAG, "Connectivity Service");
+ Slog.i(TAG, "Connectivity Service");
connectivity = ConnectivityService.getInstance(context);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Connectivity Service", e);
+ Slog.e(TAG, "Failure starting Connectivity Service", e);
}
try {
- Log.i(TAG, "Accessibility Manager");
+ Slog.i(TAG, "Throttle Service");
+ throttle = new ThrottleService(context);
+ ServiceManager.addService(
+ Context.THROTTLE_SERVICE, throttle);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting ThrottleService", e);
+ }
+
+ try {
+ Slog.i(TAG, "Accessibility Manager");
ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
new AccessibilityManagerService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Accessibility Manager", e);
+ Slog.e(TAG, "Failure starting Accessibility Manager", e);
}
try {
- Log.i(TAG, "Notification Manager");
- notification = new NotificationManagerService(context, statusBar, hardware);
- ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
+ /*
+ * NotificationManagerService is dependant on MountService,
+ * (for media / usb notifications) so we must start MountService first.
+ */
+ Slog.i(TAG, "Mount Service");
+ ServiceManager.addService("mount", new MountService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Notification Manager", e);
+ Slog.e(TAG, "Failure starting Mount Service", e);
}
try {
- // MountService must start after NotificationManagerService
- Log.i(TAG, "Mount Service");
- ServiceManager.addService("mount", new MountService(context));
+ Slog.i(TAG, "Notification Manager");
+ notification = new NotificationManagerService(context, statusBar, lights);
+ ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Mount Service", e);
+ Slog.e(TAG, "Failure starting Notification Manager", e);
}
try {
- Log.i(TAG, "Device Storage Monitor");
+ Slog.i(TAG, "Device Storage Monitor");
ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
new DeviceStorageMonitorService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting DeviceStorageMonitor service", e);
+ Slog.e(TAG, "Failure starting DeviceStorageMonitor service", e);
}
try {
- Log.i(TAG, "Location Manager");
- ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context));
+ Slog.i(TAG, "Location Manager");
+ location = new LocationManagerService(context);
+ ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Location Manager", e);
+ Slog.e(TAG, "Failure starting Location Manager", e);
}
try {
- Log.i(TAG, "Search Service");
- ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) );
+ Slog.i(TAG, "Search Service");
+ ServiceManager.addService(Context.SEARCH_SERVICE,
+ new SearchManagerService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Search Service", e);
+ Slog.e(TAG, "Failure starting Search Service", e);
}
if (INCLUDE_DEMO) {
- Log.i(TAG, "Installing demo data...");
+ Slog.i(TAG, "Installing demo data...");
(new DemoThread(context)).start();
}
try {
- Log.i(TAG, "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));
- }
+ Slog.i(TAG, "DropBox Service");
+ ServiceManager.addService(Context.DROPBOX_SERVICE,
+ new DropBoxManagerService(context, new File("/data/system/dropbox")));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Checkin Service", e);
+ Slog.e(TAG, "Failure starting DropBoxManagerService", e);
}
try {
- Log.i(TAG, "Wallpaper Service");
+ Slog.i(TAG, "Wallpaper Service");
wallpaper = new WallpaperManagerService(context);
ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Wallpaper Service", e);
+ Slog.e(TAG, "Failure starting Wallpaper Service", e);
}
try {
- Log.i(TAG, "Audio Service");
+ Slog.i(TAG, "Audio Service");
ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Audio Service", e);
+ Slog.e(TAG, "Failure starting Audio Service", e);
}
try {
- Log.i(TAG, "Headset Observer");
+ Slog.i(TAG, "Headset Observer");
// Listen for wired headset changes
headset = new HeadsetObserver(context);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting HeadsetObserver", e);
+ Slog.e(TAG, "Failure starting HeadsetObserver", e);
}
try {
- Log.i(TAG, "Dock Observer");
+ Slog.i(TAG, "Dock Observer");
// Listen for dock station changes
dock = new DockObserver(context, power);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting DockObserver", e);
+ Slog.e(TAG, "Failure starting DockObserver", e);
}
try {
- Log.i(TAG, "Backup Service");
- ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
+ Slog.i(TAG, "UI Mode Manager Service");
+ // Listen for dock station changes
+ uiMode = new UiModeManagerService(context);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Backup Service", e);
+ Slog.e(TAG, "Failure starting UiModeManagerService", e);
}
try {
- Log.i(TAG, "AppWidget Service");
+ Slog.i(TAG, "Backup Service");
+ ServiceManager.addService(Context.BACKUP_SERVICE,
+ new BackupManagerService(context));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Backup Service", e);
+ }
+
+ try {
+ Slog.i(TAG, "AppWidget Service");
appWidget = new AppWidgetService(context);
ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting AppWidget Service", e);
+ Slog.e(TAG, "Failure starting AppWidget Service", e);
+ }
+
+ try {
+ Slog.i(TAG, "Recognition Service");
+ recognition = new RecognitionManagerService(context);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting Recognition Service", e);
}
try {
com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
} catch (Throwable e) {
- Log.e(TAG, "Failure installing status bar icons", e);
+ Slog.e(TAG, "Failure installing status bar icons", e);
+ }
+
+ try {
+ Slog.i(TAG, "DiskStats Service");
+ ServiceManager.addService("diskstats", new DiskStatsService(context));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting DiskStats Service", e);
}
}
@@ -373,12 +432,23 @@ class ServerThread extends Thread {
if (safeMode) {
try {
ActivityManagerNative.getDefault().enterSafeMode();
+ // Post the safe mode state in the Zygote class
+ Zygote.systemInSafeMode = true;
+ // Disable the JIT for the system_server process
+ VMRuntime.getRuntime().disableJitCompilation();
} catch (RemoteException e) {
}
+ } else {
+ // Enable the JIT for the system_server process
+ VMRuntime.getRuntime().startJitCompilation();
}
-
+
// It is now time to start up the app processes...
+ if (devicePolicy != null) {
+ devicePolicy.systemReady();
+ }
+
if (notification != null) {
notification.systemReady();
}
@@ -397,10 +467,14 @@ class ServerThread extends Thread {
final BatteryService batteryF = battery;
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
+ final ThrottleService throttleF = throttle;
+ final UiModeManagerService uiModeF = uiMode;
final AppWidgetService appWidgetF = appWidget;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
-
+ final RecognitionManagerService recognitionF = recognition;
+ final LocationManagerService locationF = location;
+
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
@@ -409,24 +483,28 @@ class ServerThread extends Thread {
((ActivityManagerService)ActivityManagerNative.getDefault())
.systemReady(new Runnable() {
public void run() {
- Log.i(TAG, "Making services ready");
-
+ Slog.i(TAG, "Making services ready");
+
if (batteryF != null) batteryF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
if (dockF != null) dockF.systemReady();
+ if (uiModeF != null) uiModeF.systemReady();
+ if (recognitionF != null) recognitionF.systemReady();
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
// third party code...
-
+
if (appWidgetF != null) appWidgetF.systemReady(safeMode);
if (wallpaperF != null) wallpaperF.systemReady();
if (immF != null) immF.systemReady();
+ if (locationF != null) locationF.systemReady();
+ if (throttleF != null) throttleF.systemReady();
}
});
-
+
Looper.loop();
- Log.d(TAG, "System ServerThread is exiting!");
+ Slog.d(TAG, "System ServerThread is exiting!");
}
}
@@ -451,7 +529,7 @@ class DemoThread extends Thread
dataset.add(mContext);
}
} catch (Throwable e) {
- Log.e("SystemServer", "Failure installing demo data", e);
+ Slog.e("SystemServer", "Failure installing demo data", e);
}
}
@@ -492,13 +570,13 @@ public class SystemServer
// 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!");
+ Slog.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
index 47cb6ad..664dfa5 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -29,7 +29,7 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.Log;
+import android.util.Slog;
import java.util.ArrayList;
import java.io.FileDescriptor;
@@ -124,7 +124,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
- // Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
+ // Slog.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
// Integer.toHexString(events));
if (events != 0) {
/* Checks permission and throws Security exception */
@@ -485,6 +485,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
intent.putExtras(data);
@@ -502,6 +503,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
@@ -523,6 +525,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString());
if (!TextUtils.isEmpty(incomingNumber)) {
intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
@@ -537,6 +540,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
// status bar takes care of that after taking into account all of the
// required info.
Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
if (!isDataConnectivityPossible) {
intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true);
@@ -559,6 +563,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private void broadcastDataConnectionFailed(String reason) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
mContext.sendStickyBroadcast(intent);
}
@@ -570,7 +575,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
String msg = "Modify Phone State Permission Denial: " + method + " from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
return false;
}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
new file mode 100644
index 0000000..6a5bbd2
--- /dev/null
+++ b/services/java/com/android/server/ThrottleService.java
@@ -0,0 +1,1040 @@
+/*
+ * 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.Notification;
+import android.app.NotificationManager;
+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.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.IThrottleManager;
+import android.net.SntpClient;
+import android.net.ThrottleManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.telephony.TelephonyProperties;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Properties;
+import java.util.Random;
+
+// TODO - add comments - reference the ThrottleManager for public API
+public class ThrottleService extends IThrottleManager.Stub {
+
+ private static final String TESTING_ENABLED_PROPERTY = "persist.throttle.testing";
+
+ private static final String TAG = "ThrottleService";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+ private Handler mHandler;
+ private HandlerThread mThread;
+
+ private Context mContext;
+
+ private static final int INITIAL_POLL_DELAY_SEC = 90;
+ private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
+ private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
+ private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
+
+ private int mPolicyPollPeriodSec;
+ private long mPolicyThreshold;
+ private int mPolicyThrottleValue;
+ private int mPolicyResetDay; // 1-28
+ private int mPolicyNotificationsAllowedMask;
+
+ private long mLastRead; // read byte count from last poll
+ private long mLastWrite; // write byte count from last poll
+
+ private static final String ACTION_POLL = "com.android.server.ThrottleManager.action.POLL";
+ private static int POLL_REQUEST = 0;
+ private PendingIntent mPendingPollIntent;
+ private static final String ACTION_RESET = "com.android.server.ThorottleManager.action.RESET";
+ private static int RESET_REQUEST = 1;
+ private PendingIntent mPendingResetIntent;
+
+ private INetworkManagementService mNMService;
+ private AlarmManager mAlarmManager;
+ private NotificationManager mNotificationManager;
+
+ private DataRecorder mRecorder;
+
+ private String mIface;
+
+ private static final int NOTIFICATION_WARNING = 2;
+
+ private Notification mThrottlingNotification;
+ private boolean mWarningNotificationSent = false;
+
+ private SettingsObserver mSettingsObserver;
+
+ private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
+ private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
+ private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
+
+ private static final String PROPERTIES_FILE = "/etc/gps.conf";
+ private String mNtpServer;
+ private boolean mNtpActive;
+
+ public ThrottleService(Context context) {
+ if (DBG) Slog.d(TAG, "Starting ThrottleService");
+ mContext = context;
+
+ mNtpActive = false;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ Intent pollIntent = new Intent(ACTION_POLL, null);
+ mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+ Intent resetIntent = new Intent(ACTION_RESET, null);
+ mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNMService = INetworkManagementService.Stub.asInterface(b);
+
+ mNotificationManager = (NotificationManager)mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ }
+
+ private static class SettingsObserver extends ContentObserver {
+ private int mMsg;
+ private Handler mHandler;
+ SettingsObserver(Handler handler, int msg) {
+ super(handler);
+ mHandler = handler;
+ mMsg = msg;
+ }
+
+ void observe(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_POLLING_SEC), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_RESET_DAY), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_HELP_URI), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
+ private void enforceAccessPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE,
+ "ThrottleService");
+ }
+
+ private long ntpToWallTime(long ntpTime) {
+ long bestNow = getBestTime();
+ long localNow = System.currentTimeMillis();
+ return localNow + (ntpTime - bestNow);
+ }
+
+ // TODO - fetch for the iface
+ // return time in the local, system wall time, correcting for the use of ntp
+
+ public synchronized long getResetTime(String iface) {
+ enforceAccessPermission();
+ long resetTime = 0;
+ if (mRecorder != null) {
+ resetTime = ntpToWallTime(mRecorder.getPeriodEnd());
+ }
+ return resetTime;
+ }
+
+ // TODO - fetch for the iface
+ // return time in the local, system wall time, correcting for the use of ntp
+ public synchronized long getPeriodStartTime(String iface) {
+ enforceAccessPermission();
+ long startTime = 0;
+ if (mRecorder != null) {
+ startTime = ntpToWallTime(mRecorder.getPeriodStart());
+ }
+ return startTime;
+ }
+ //TODO - a better name? getCliffByteCountThreshold?
+ // TODO - fetch for the iface
+ public synchronized long getCliffThreshold(String iface, int cliff) {
+ enforceAccessPermission();
+ if (cliff == 1) {
+ return mPolicyThreshold;
+ }
+ return 0;
+ }
+ // TODO - a better name? getThrottleRate?
+ // TODO - fetch for the iface
+ public synchronized int getCliffLevel(String iface, int cliff) {
+ enforceAccessPermission();
+ if (cliff == 1) {
+ return mPolicyThrottleValue;
+ }
+ return 0;
+ }
+
+ public String getHelpUri() {
+ enforceAccessPermission();
+ return Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_HELP_URI);
+ }
+
+ // TODO - fetch for the iface
+ public synchronized long getByteCount(String iface, int dir, int period, int ago) {
+ enforceAccessPermission();
+ if ((period == ThrottleManager.PERIOD_CYCLE) &&
+ (mRecorder != null)) {
+ if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
+ if (dir == ThrottleManager.DIRECTION_RX) return mRecorder.getPeriodRx(ago);
+ }
+ return 0;
+ }
+
+ // TODO - a better name - getCurrentThrottleRate?
+ // TODO - fetch for the iface
+ public synchronized int getThrottle(String iface) {
+ enforceAccessPermission();
+ if (mThrottleIndex == 1) {
+ return mPolicyThrottleValue;
+ }
+ return 0;
+ }
+
+ void systemReady() {
+ if (DBG) Slog.d(TAG, "systemReady");
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
+ }
+ }, new IntentFilter(ACTION_POLL));
+
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
+ }
+ }, new IntentFilter(ACTION_RESET));
+
+ // use a new thread as we don't want to stall the system for file writes
+ mThread = new HandlerThread(TAG);
+ mThread.start();
+ mHandler = new MyHandler(mThread.getLooper());
+ mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
+
+ mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
+ mSettingsObserver.observe(mContext);
+
+ FileInputStream stream = null;
+ try {
+ Properties properties = new Properties();
+ File file = new File(PROPERTIES_FILE);
+ stream = new FileInputStream(file);
+ properties.load(stream);
+ mNtpServer = properties.getProperty("NTP_SERVER", null);
+ } catch (IOException e) {
+ Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (Exception e) {}
+ }
+ }
+ }
+
+
+ private static final int EVENT_REBOOT_RECOVERY = 0;
+ private static final int EVENT_POLICY_CHANGED = 1;
+ private static final int EVENT_POLL_ALARM = 2;
+ private static final int EVENT_RESET_ALARM = 3;
+ private class MyHandler extends Handler {
+ public MyHandler(Looper l) {
+ super(l);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_REBOOT_RECOVERY:
+ onRebootRecovery();
+ break;
+ case EVENT_POLICY_CHANGED:
+ onPolicyChanged();
+ break;
+ case EVENT_POLL_ALARM:
+ onPollAlarm();
+ break;
+ case EVENT_RESET_ALARM:
+ onResetAlarm();
+ }
+ }
+
+ private void onRebootRecovery() {
+ if (DBG) Slog.d(TAG, "onRebootRecovery");
+ // check for sim change TODO
+ // reregister for notification of policy change
+
+ mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
+
+ mRecorder = new DataRecorder(mContext, ThrottleService.this);
+
+ // get policy
+ mHandler.obtainMessage(EVENT_POLICY_CHANGED).sendToTarget();
+
+ // if we poll now we won't have network connectivity or even imsi access
+ // queue up a poll to happen in a little while - after ntp and imsi are avail
+ // TODO - make this callback based (ie, listen for notificaitons)
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_POLL_ALARM),
+ INITIAL_POLL_DELAY_SEC * 1000);
+ }
+
+ // check for new policy info (threshold limit/value/etc)
+ private void onPolicyChanged() {
+ boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
+
+ int pollingPeriod = mContext.getResources().getInteger(
+ R.integer.config_datause_polling_period_sec);
+ mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
+
+ // TODO - remove testing stuff?
+ long defaultThreshold = mContext.getResources().getInteger(
+ R.integer.config_datause_threshold_bytes);
+ int defaultValue = mContext.getResources().getInteger(
+ R.integer.config_datause_throttle_kbitsps);
+ synchronized (ThrottleService.this) {
+ mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
+ mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
+ if (testing) {
+ mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
+ mPolicyThreshold = TESTING_THRESHOLD;
+ }
+ }
+
+ mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_RESET_DAY, -1);
+ if (mPolicyResetDay == -1 ||
+ ((mPolicyResetDay < 1) || (mPolicyResetDay > 28))) {
+ Random g = new Random();
+ mPolicyResetDay = 1 + g.nextInt(28); // 1-28
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
+ }
+ mIface = mContext.getResources().getString(R.string.config_datause_iface);
+ synchronized (ThrottleService.this) {
+ if (mIface == null) {
+ mPolicyThreshold = 0;
+ }
+ }
+
+ int defaultNotificationType = mContext.getResources().getInteger(
+ R.integer.config_datause_notification_type);
+ mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
+
+ Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
+ ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
+ ", resetDay=" + mPolicyResetDay + ", noteType=" +
+ mPolicyNotificationsAllowedMask);
+
+ // force updates
+ mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
+
+ onResetAlarm();
+
+ onPollAlarm();
+
+ Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
+ mContext.sendBroadcast(broadcast);
+ }
+
+ private void onPollAlarm() {
+ long now = SystemClock.elapsedRealtime();
+ long next = now + mPolicyPollPeriodSec*1000;
+
+ checkForAuthoritativeTime();
+
+ long incRead = 0;
+ long incWrite = 0;
+ try {
+ incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
+ incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
+ // handle iface resets - on some device the 3g iface comes and goes and gets
+ // totals reset to 0. Deal with it
+ if ((incRead < 0) || (incWrite < 0)) {
+ incRead += mLastRead;
+ incWrite += mLastWrite;
+ mLastRead = 0;
+ mLastWrite = 0;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
+ }
+ // don't count this data if we're roaming.
+ boolean roaming = "true".equals(
+ SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+ if (!roaming) {
+ mRecorder.addData(incRead, incWrite);
+ }
+
+ long periodRx = mRecorder.getPeriodRx(0);
+ long periodTx = mRecorder.getPeriodTx(0);
+ long total = periodRx + periodTx;
+ if (DBG) {
+ Slog.d(TAG, "onPollAlarm - roaming =" + roaming +
+ ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
+ }
+ mLastRead += incRead;
+ mLastWrite += incWrite;
+
+ checkThrottleAndPostNotification(total);
+
+ Intent broadcast = new Intent(ThrottleManager.THROTTLE_POLL_ACTION);
+ broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_READ, periodRx);
+ broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_WRITE, periodTx);
+ broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
+ broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
+ mContext.sendStickyBroadcast(broadcast);
+
+ mAlarmManager.cancel(mPendingPollIntent);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
+ }
+
+ private void checkThrottleAndPostNotification(long currentTotal) {
+ // is throttling enabled?
+ if (mPolicyThreshold == 0) {
+ clearThrottleAndNotification();
+ return;
+ }
+
+ // have we spoken with an ntp server yet?
+ // this is controversial, but we'd rather err towards not throttling
+ if ((mNtpServer != null) && !mNtpActive) {
+ return;
+ }
+
+ // check if we need to throttle
+ if (currentTotal > mPolicyThreshold) {
+ if (mThrottleIndex != 1) {
+ synchronized (ThrottleService.this) {
+ mThrottleIndex = 1;
+ }
+ if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
+ try {
+ mNMService.setInterfaceThrottle(mIface,
+ mPolicyThrottleValue, mPolicyThrottleValue);
+ } catch (Exception e) {
+ Slog.e(TAG, "error setting Throttle: " + e);
+ }
+
+ mNotificationManager.cancel(R.drawable.stat_sys_throttled);
+
+ postNotification(R.string.throttled_notification_title,
+ R.string.throttled_notification_message,
+ R.drawable.stat_sys_throttled,
+ Notification.FLAG_ONGOING_EVENT);
+
+ Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
+ broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
+ mContext.sendStickyBroadcast(broadcast);
+
+ } // else already up!
+ } else {
+ clearThrottleAndNotification();
+ if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
+ // check if we should warn about throttle
+ // pretend we only have 1/2 the time remaining that we actually do
+ // if our burn rate in the period so far would have us exceed the limit
+ // in that 1/2 window, warn the user.
+ // this gets more generous in the early to middle period and converges back
+ // to the limit as we move toward the period end.
+
+ // adding another factor - it must be greater than the total cap/4
+ // else we may get false alarms very early in the period.. in the first
+ // tenth of a percent of the period if we used more than a tenth of a percent
+ // of the cap we'd get a warning and that's not desired.
+ long start = mRecorder.getPeriodStart();
+ long end = mRecorder.getPeriodEnd();
+ long periodLength = end - start;
+ long now = System.currentTimeMillis();
+ long timeUsed = now - start;
+ long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
+ if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
+ if (mWarningNotificationSent == false) {
+ mWarningNotificationSent = true;
+ mNotificationManager.cancel(R.drawable.stat_sys_throttled);
+ postNotification(R.string.throttle_warning_notification_title,
+ R.string.throttle_warning_notification_message,
+ R.drawable.stat_sys_throttled,
+ 0);
+ }
+ } else {
+ if (mWarningNotificationSent == true) {
+ mNotificationManager.cancel(R.drawable.stat_sys_throttled);
+ mWarningNotificationSent =false;
+ }
+ }
+ }
+ }
+ }
+
+ private void postNotification(int titleInt, int messageInt, int icon, int flags) {
+ Intent intent = new Intent();
+ // TODO - fix up intent
+ intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ Resources r = Resources.getSystem();
+ CharSequence title = r.getText(titleInt);
+ CharSequence message = r.getText(messageInt);
+ if (mThrottlingNotification == null) {
+ mThrottlingNotification = new Notification();
+ mThrottlingNotification.when = 0;
+ // TODO - fixup icon
+ mThrottlingNotification.icon = icon;
+ mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ }
+ mThrottlingNotification.flags = flags;
+ mThrottlingNotification.tickerText = title;
+ mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
+
+ mNotificationManager.notify(mThrottlingNotification.icon, mThrottlingNotification);
+ }
+
+
+ private synchronized void clearThrottleAndNotification() {
+ if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
+ synchronized (ThrottleService.this) {
+ mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
+ }
+ try {
+ mNMService.setInterfaceThrottle(mIface, -1, -1);
+ } catch (Exception e) {
+ Slog.e(TAG, "error clearing Throttle: " + e);
+ }
+ Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
+ broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, -1);
+ mContext.sendStickyBroadcast(broadcast);
+ mNotificationManager.cancel(R.drawable.stat_sys_throttled);
+ mWarningNotificationSent = false;
+ }
+ }
+
+ private Calendar calculatePeriodEnd(long now) {
+ Calendar end = GregorianCalendar.getInstance();
+ end.setTimeInMillis(now);
+ int day = end.get(Calendar.DAY_OF_MONTH);
+ end.set(Calendar.DAY_OF_MONTH, mPolicyResetDay);
+ end.set(Calendar.HOUR_OF_DAY, 0);
+ end.set(Calendar.MINUTE, 0);
+ end.set(Calendar.SECOND, 0);
+ end.set(Calendar.MILLISECOND, 0);
+ if (day >= mPolicyResetDay) {
+ int month = end.get(Calendar.MONTH);
+ if (month == Calendar.DECEMBER) {
+ end.set(Calendar.YEAR, end.get(Calendar.YEAR) + 1);
+ month = Calendar.JANUARY - 1;
+ }
+ end.set(Calendar.MONTH, month + 1);
+ }
+
+ // TODO - remove!
+ if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
+ end = GregorianCalendar.getInstance();
+ end.setTimeInMillis(now);
+ end.add(Calendar.SECOND, TESTING_RESET_PERIOD_SEC);
+ }
+ return end;
+ }
+ private Calendar calculatePeriodStart(Calendar end) {
+ Calendar start = (Calendar)end.clone();
+ int month = end.get(Calendar.MONTH);
+ if (end.get(Calendar.MONTH) == Calendar.JANUARY) {
+ month = Calendar.DECEMBER + 1;
+ start.set(Calendar.YEAR, start.get(Calendar.YEAR) - 1);
+ }
+ start.set(Calendar.MONTH, month - 1);
+
+ // TODO - remove!!
+ if (SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true")) {
+ start = (Calendar)end.clone();
+ start.add(Calendar.SECOND, -TESTING_RESET_PERIOD_SEC);
+ }
+ return start;
+ }
+
+ private void onResetAlarm() {
+ if (DBG) {
+ Slog.d(TAG, "onResetAlarm - last period had " + mRecorder.getPeriodRx(0) +
+ " bytes read and " + mRecorder.getPeriodTx(0) + " written");
+ }
+
+ long now = getBestTime();
+
+ if (mNtpActive || (mNtpServer == null)) {
+ Calendar end = calculatePeriodEnd(now);
+ Calendar start = calculatePeriodStart(end);
+
+ if (mRecorder.setNextPeriod(start, end)) {
+ onPollAlarm();
+ }
+
+ mAlarmManager.cancel(mPendingResetIntent);
+ long offset = end.getTimeInMillis() - now;
+ // use Elapsed realtime so clock changes don't fool us.
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + offset,
+ mPendingResetIntent);
+ } else {
+ if (DBG) Slog.d(TAG, "no authoritative time - not resetting period");
+ }
+ }
+ }
+
+ private void checkForAuthoritativeTime() {
+ if (mNtpActive || (mNtpServer == null)) return;
+
+ // will try to get the ntp time and switch to it if found.
+ // will also cache the time so we don't fetch it repeatedly.
+ getBestTime();
+ }
+
+ private static final int MAX_NTP_CACHE_AGE = 30 * 1000;
+ private static final int MAX_NTP_FETCH_WAIT = 10 * 1000;
+ private long cachedNtp;
+ private long cachedNtpTimestamp;
+
+ private long getBestTime() {
+ if (mNtpServer != null) {
+ if (mNtpActive) {
+ long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
+ if (ntpAge < MAX_NTP_CACHE_AGE) {
+ if (VDBG) Slog.v(TAG, "using cached time");
+ return cachedNtp + ntpAge;
+ }
+ }
+ SntpClient client = new SntpClient();
+ if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
+ cachedNtp = client.getNtpTime();
+ cachedNtpTimestamp = SystemClock.elapsedRealtime();
+ if (!mNtpActive) {
+ mNtpActive = true;
+ if (DBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
+ mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
+ }
+ if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
+ return cachedNtp;
+ }
+ }
+ long time = System.currentTimeMillis();
+ if (VDBG) Slog.v(TAG, "using User time: " + time);
+ mNtpActive = false;
+ return time;
+ }
+
+ // records bytecount data for a given time and accumulates it into larger time windows
+ // for logging and other purposes
+ //
+ // since time can be changed (user or network action) we will have to track the time of the
+ // last recording and deal with it.
+ private static class DataRecorder {
+ long[] mPeriodRxData;
+ long[] mPeriodTxData;
+ int mCurrentPeriod;
+ int mPeriodCount;
+
+ Calendar mPeriodStart;
+ Calendar mPeriodEnd;
+
+ ThrottleService mParent;
+ Context mContext;
+ String mImsi = null;
+
+ TelephonyManager mTelephonyManager;
+
+ DataRecorder(Context context, ThrottleService parent) {
+ mContext = context;
+ mParent = parent;
+
+ mTelephonyManager = (TelephonyManager)mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+
+ synchronized (mParent) {
+ mPeriodCount = 6;
+ mPeriodRxData = new long[mPeriodCount];
+ mPeriodTxData = new long[mPeriodCount];
+
+ mPeriodStart = Calendar.getInstance();
+ mPeriodEnd = Calendar.getInstance();
+
+ retrieve();
+ }
+ }
+
+ boolean setNextPeriod(Calendar start, Calendar end) {
+ // TODO - how would we deal with a dual-IMSI device?
+ checkForSubscriberId();
+ boolean startNewPeriod = true;
+
+ if (start.equals(mPeriodStart) && end.equals(mPeriodEnd)) {
+ // same endpoints - keep collecting
+ if (DBG) {
+ Slog.d(TAG, "same period (" + start.getTimeInMillis() + "," +
+ end.getTimeInMillis() +") - ammending data");
+ }
+ startNewPeriod = false;
+ } else {
+ if (DBG) {
+ if(start.equals(mPeriodEnd) || start.after(mPeriodEnd)) {
+ Slog.d(TAG, "next period (" + start.getTimeInMillis() + "," +
+ end.getTimeInMillis() + ") - old end was " +
+ mPeriodEnd.getTimeInMillis() + ", following");
+ } else {
+ Slog.d(TAG, "new period (" + start.getTimeInMillis() + "," +
+ end.getTimeInMillis() + ") replacing old (" +
+ mPeriodStart.getTimeInMillis() + "," +
+ mPeriodEnd.getTimeInMillis() + ")");
+ }
+ }
+ synchronized (mParent) {
+ ++mCurrentPeriod;
+ if (mCurrentPeriod >= mPeriodCount) mCurrentPeriod = 0;
+ mPeriodRxData[mCurrentPeriod] = 0;
+ mPeriodTxData[mCurrentPeriod] = 0;
+ }
+ }
+ setPeriodStart(start);
+ setPeriodEnd(end);
+ record();
+ return startNewPeriod;
+ }
+
+ public long getPeriodEnd() {
+ synchronized (mParent) {
+ return mPeriodEnd.getTimeInMillis();
+ }
+ }
+
+ private void setPeriodEnd(Calendar end) {
+ synchronized (mParent) {
+ mPeriodEnd = end;
+ }
+ }
+
+ public long getPeriodStart() {
+ synchronized (mParent) {
+ return mPeriodStart.getTimeInMillis();
+ }
+ }
+
+ private void setPeriodStart(Calendar start) {
+ synchronized (mParent) {
+ mPeriodStart = start;
+ }
+ }
+
+ public int getPeriodCount() {
+ synchronized (mParent) {
+ return mPeriodCount;
+ }
+ }
+
+ private void zeroData(int field) {
+ synchronized (mParent) {
+ for(int period = 0; period<mPeriodCount; period++) {
+ mPeriodRxData[period] = 0;
+ mPeriodTxData[period] = 0;
+ }
+ mCurrentPeriod = 0;
+ }
+
+ }
+
+ // if time moves backward accumulate all read/write that's lost into the now
+ // otherwise time moved forward.
+ void addData(long bytesRead, long bytesWritten) {
+ checkForSubscriberId();
+
+ synchronized (mParent) {
+ mPeriodRxData[mCurrentPeriod] += bytesRead;
+ mPeriodTxData[mCurrentPeriod] += bytesWritten;
+ }
+ record();
+ }
+
+ private File getDataFile() {
+ File dataDir = Environment.getDataDirectory();
+ File throttleDir = new File(dataDir, "system/throttle");
+ throttleDir.mkdirs();
+ String mImsi = mTelephonyManager.getSubscriberId();
+ File dataFile;
+ if (mImsi == null) {
+ dataFile = useMRUFile(throttleDir);
+ if (VDBG) Slog.v(TAG, "imsi not available yet, using " + dataFile);
+ } else {
+ String imsiHash = Integer.toString(mImsi.hashCode());
+ dataFile = new File(throttleDir, imsiHash);
+ }
+ // touch the file so it's not LRU
+ dataFile.setLastModified(System.currentTimeMillis());
+ checkAndDeleteLRUDataFile(throttleDir);
+ return dataFile;
+ }
+
+ // TODO - get broadcast (TelephonyIntents.ACTION_SIM_STATE_CHANGED) instead of polling
+ private void checkForSubscriberId() {
+ if (mImsi != null) return;
+
+ mImsi = mTelephonyManager.getSubscriberId();
+ if (mImsi == null) return;
+
+ if (DBG) Slog.d(TAG, "finally have imsi - retreiving data");
+ retrieve();
+ }
+
+ private final static int MAX_SIMS_SUPPORTED = 3;
+
+ private void checkAndDeleteLRUDataFile(File dir) {
+ File[] files = dir.listFiles();
+
+ if (files.length <= MAX_SIMS_SUPPORTED) return;
+ if (DBG) Slog.d(TAG, "Too many data files");
+ do {
+ File oldest = null;
+ for (File f : files) {
+ if ((oldest == null) || (oldest.lastModified() > f.lastModified())) {
+ oldest = f;
+ }
+ }
+ if (oldest == null) return;
+ if (DBG) Slog.d(TAG, " deleting " + oldest);
+ oldest.delete();
+ files = dir.listFiles();
+ } while (files.length > MAX_SIMS_SUPPORTED);
+ }
+
+ private File useMRUFile(File dir) {
+ File newest = null;
+ File[] files = dir.listFiles();
+
+ for (File f : files) {
+ if ((newest == null) || (newest.lastModified() < f.lastModified())) {
+ newest = f;
+ }
+ }
+ if (newest == null) {
+ newest = new File(dir, "temp");
+ }
+ return newest;
+ }
+
+
+ private static final int DATA_FILE_VERSION = 1;
+
+ private void record() {
+ // 1 int version
+ // 1 int mPeriodCount
+ // 13*6 long[PERIOD_COUNT] mPeriodRxData
+ // 13*6 long[PERIOD_COUNT] mPeriodTxData
+ // 1 int mCurrentPeriod
+ // 13 long periodStartMS
+ // 13 long periodEndMS
+ // 200 chars max
+ StringBuilder builder = new StringBuilder();
+ builder.append(DATA_FILE_VERSION);
+ builder.append(":");
+ builder.append(mPeriodCount);
+ builder.append(":");
+ for(int i = 0; i < mPeriodCount; i++) {
+ builder.append(mPeriodRxData[i]);
+ builder.append(":");
+ }
+ for(int i = 0; i < mPeriodCount; i++) {
+ builder.append(mPeriodTxData[i]);
+ builder.append(":");
+ }
+ builder.append(mCurrentPeriod);
+ builder.append(":");
+ builder.append(mPeriodStart.getTimeInMillis());
+ builder.append(":");
+ builder.append(mPeriodEnd.getTimeInMillis());
+
+ BufferedWriter out = null;
+ try {
+ out = new BufferedWriter(new FileWriter(getDataFile()), 256);
+ out.write(builder.toString());
+ } catch (IOException e) {
+ Slog.e(TAG, "Error writing data file");
+ return;
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (Exception e) {}
+ }
+ }
+ }
+
+ private void retrieve() {
+ // clean out any old data first. If we fail to read we don't want old stuff
+ zeroData(0);
+
+ File f = getDataFile();
+ byte[] buffer;
+ FileInputStream s = null;
+ try {
+ buffer = new byte[(int)f.length()];
+ s = new FileInputStream(f);
+ s.read(buffer);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading data file");
+ return;
+ } finally {
+ if (s != null) {
+ try {
+ s.close();
+ } catch (Exception e) {}
+ }
+ }
+ String data = new String(buffer);
+ if (data == null || data.length() == 0) {
+ if (DBG) Slog.d(TAG, "data file empty");
+ return;
+ }
+ synchronized (mParent) {
+ String[] parsed = data.split(":");
+ int parsedUsed = 0;
+ if (parsed.length < 6) {
+ Slog.e(TAG, "reading data file with insufficient length - ignoring");
+ return;
+ }
+
+ if (Integer.parseInt(parsed[parsedUsed++]) != DATA_FILE_VERSION) {
+ Slog.e(TAG, "reading data file with bad version - ignoring");
+ return;
+ }
+
+ mPeriodCount = Integer.parseInt(parsed[parsedUsed++]);
+ if (parsed.length != 5 + (2 * mPeriodCount)) {
+ Slog.e(TAG, "reading data file with bad length ("+parsed.length+" != "+(5 + (2*mPeriodCount))+") - ignoring");
+ return;
+ }
+
+ mPeriodRxData = new long[mPeriodCount];
+ for(int i = 0; i < mPeriodCount; i++) {
+ mPeriodRxData[i] = Long.parseLong(parsed[parsedUsed++]);
+ }
+ mPeriodTxData = new long[mPeriodCount];
+ for(int i = 0; i < mPeriodCount; i++) {
+ mPeriodTxData[i] = Long.parseLong(parsed[parsedUsed++]);
+ }
+ mCurrentPeriod = Integer.parseInt(parsed[parsedUsed++]);
+ mPeriodStart = new GregorianCalendar();
+ mPeriodStart.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+ mPeriodEnd = new GregorianCalendar();
+ mPeriodEnd.setTimeInMillis(Long.parseLong(parsed[parsedUsed++]));
+ }
+ }
+
+ long getPeriodRx(int which) {
+ synchronized (mParent) {
+ if (which > mPeriodCount) return 0;
+ which = mCurrentPeriod - which;
+ if (which < 0) which += mPeriodCount;
+ return mPeriodRxData[which];
+ }
+ }
+ long getPeriodTx(int which) {
+ synchronized (mParent) {
+ if (which > mPeriodCount) return 0;
+ which = mCurrentPeriod - which;
+ if (which < 0) which += mPeriodCount;
+ return mPeriodTxData[which];
+ }
+ }
+ }
+
+ @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 ThrottleService " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
+ return;
+ }
+ pw.println();
+
+ pw.println("The threshold is " + mPolicyThreshold +
+ ", after which you experince throttling to " +
+ mPolicyThrottleValue + "kbps");
+ pw.println("Current period is " +
+ (mRecorder.getPeriodEnd() - mRecorder.getPeriodStart())/1000 + " seconds long " +
+ "and ends in " + (getResetTime(mIface) - System.currentTimeMillis()) / 1000 +
+ " seconds.");
+ pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
+ pw.println("Current Throttle Index is " + mThrottleIndex);
+
+ for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
+ pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
+ mRecorder.getPeriodTx(i));
+ }
+ }
+}
diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/java/com/android/server/TwilightCalculator.java
new file mode 100644
index 0000000..a5c93b5
--- /dev/null
+++ b/services/java/com/android/server/TwilightCalculator.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.text.format.DateUtils;
+import android.util.FloatMath;
+
+/** @hide */
+public class TwilightCalculator {
+
+ /** Value of {@link #mState} if it is currently day */
+ public static final int DAY = 0;
+
+ /** Value of {@link #mState} if it is currently night */
+ public static final int NIGHT = 1;
+
+ private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
+
+ // element for calculating solar transit.
+ private static final float J0 = 0.0009f;
+
+ // correction for civil twilight
+ private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
+
+ // coefficients for calculating Equation of Center.
+ private static final float C1 = 0.0334196f;
+ private static final float C2 = 0.000349066f;
+ private static final float C3 = 0.000005236f;
+
+ private static final float OBLIQUITY = 0.40927971f;
+
+ // Java time on Jan 1, 2000 12:00 UTC.
+ private static final long UTC_2000 = 946728000000L;
+
+ /**
+ * Time of sunset (civil twilight) in milliseconds or -1 in the case the day
+ * or night never ends.
+ */
+ public long mSunset;
+
+ /**
+ * Time of sunrise (civil twilight) in milliseconds or -1 in the case the
+ * day or night never ends.
+ */
+ public long mSunrise;
+
+ /** Current state */
+ public int mState;
+
+ /**
+ * calculates the civil twilight bases on time and geo-coordinates.
+ *
+ * @param time time in milliseconds.
+ * @param latiude latitude in degrees.
+ * @param longitude latitude in degrees.
+ */
+ public void calculateTwilight(long time, double latiude, double longitude) {
+ final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
+
+ // mean anomaly
+ final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
+
+ // true anomaly
+ final float trueAnomaly = meanAnomaly + C1 * FloatMath.sin(meanAnomaly) + C2
+ * FloatMath.sin(2 * meanAnomaly) + C3 * FloatMath.sin(3 * meanAnomaly);
+
+ // ecliptic longitude
+ final float solarLng = trueAnomaly + 1.796593063f + (float) Math.PI;
+
+ // solar transit in days since 2000
+ final double arcLongitude = -longitude / 360;
+ float n = Math.round(daysSince2000 - J0 - arcLongitude);
+ double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053f * FloatMath.sin(meanAnomaly)
+ + -0.0069f * FloatMath.sin(2 * solarLng);
+
+ // declination of sun
+ double solarDec = Math.asin(FloatMath.sin(solarLng) * FloatMath.sin(OBLIQUITY));
+
+ final double latRad = latiude * DEGREES_TO_RADIANS;
+
+ double cosHourAngle = (FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
+ * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
+ // The day or night never ends for the given date and location, if this value is out of
+ // range.
+ if (cosHourAngle >= 1) {
+ mState = NIGHT;
+ mSunset = -1;
+ mSunrise = -1;
+ return;
+ } else if (cosHourAngle <= -1) {
+ mState = DAY;
+ mSunset = -1;
+ mSunrise = -1;
+ return;
+ }
+
+ float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
+
+ mSunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+ mSunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+
+ if (mSunrise < time && mSunset > time) {
+ mState = DAY;
+ } else {
+ mState = NIGHT;
+ }
+ }
+
+}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
new file mode 100644
index 0000000..3606629
--- /dev/null
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -0,0 +1,772 @@
+/*
+ * 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.Activity;
+import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
+import android.app.IUiModeManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.StatusBarManager;
+import android.app.UiModeManager;
+import android.content.ActivityNotFoundException;
+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.Configuration;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.BatteryManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import com.android.internal.R;
+import com.android.internal.app.DisableCarModeActivity;
+
+class UiModeManagerService extends IUiModeManager.Stub {
+ private static final String TAG = UiModeManager.class.getSimpleName();
+ private static final boolean LOG = false;
+
+ private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL";
+
+ private static final int MSG_UPDATE_TWILIGHT = 0;
+ private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
+
+ private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+ private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
+ private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
+ private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS;
+ private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
+
+ private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
+
+ private final Context mContext;
+
+ final Object mLock = new Object();
+
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+ private int mNightMode = UiModeManager.MODE_NIGHT_NO;
+ private boolean mCarModeEnabled = false;
+ private boolean mCharging = false;
+ private final boolean mCarModeKeepsScreenOn;
+ private final boolean mDeskModeKeepsScreenOn;
+
+ private boolean mComputedNightMode;
+ private int mCurUiMode = 0;
+ private int mSetUiMode = 0;
+
+ private boolean mHoldingConfiguration = false;
+ private Configuration mConfiguration = new Configuration();
+
+ private boolean mSystemReady;
+
+ private NotificationManager mNotificationManager;
+
+ private AlarmManager mAlarmManager;
+
+ private LocationManager mLocationManager;
+ private Location mLocation;
+ private StatusBarManager mStatusBarManager;
+ private final PowerManager.WakeLock mWakeLock;
+
+ static Intent buildHomeIntent(String category) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ return intent;
+ }
+
+ // The broadcast receiver which receives the result of the ordered broadcast sent when
+ // the dock state changes. The original ordered broadcast is sent with an initial result
+ // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
+ // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
+ private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() != Activity.RESULT_OK) {
+ return;
+ }
+
+ final int enableFlags = intent.getIntExtra("enableFlags", 0);
+ final int disableFlags = intent.getIntExtra("disableFlags", 0);
+
+ synchronized (mLock) {
+ // Launch a dock activity
+ String category = null;
+ if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
+ // Only launch car home when car mode is enabled and the caller
+ // has asked us to switch to it.
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_CAR_DOCK;
+ }
+ } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
+ // Only launch car home when desk mode is enabled and the caller
+ // has asked us to switch to it. Currently re-using the car
+ // mode flag since we don't have a formal API for "desk mode".
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_DESK_DOCK;
+ }
+ } else {
+ // Launch the standard home app if requested.
+ if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ category = Intent.CATEGORY_HOME;
+ }
+ }
+
+ if (category != null) {
+ // This is the new activity that will serve as home while
+ // we are in care mode.
+ Intent homeIntent = buildHomeIntent(category);
+
+ // Now we are going to be careful about switching the
+ // configuration and starting the activity -- we need to
+ // do this in a specific order under control of the
+ // activity manager, to do it cleanly. So compute the
+ // new config, but don't set it yet, and let the
+ // activity manager take care of both the start and config
+ // change.
+ Configuration newConfig = null;
+ if (mHoldingConfiguration) {
+ mHoldingConfiguration = false;
+ updateConfigurationLocked(false);
+ newConfig = mConfiguration;
+ }
+ try {
+ ActivityManagerNative.getDefault().startActivityWithConfig(
+ null, homeIntent, null, null, 0, null, null, 0, false, false,
+ newConfig);
+ mHoldingConfiguration = false;
+ } catch (RemoteException e) {
+ Slog.w(TAG, e.getCause());
+ }
+ }
+
+ if (mHoldingConfiguration) {
+ mHoldingConfiguration = false;
+ updateConfigurationLocked(true);
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
+ }
+ }
+ };
+
+ private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ updateDockState(state);
+ }
+ };
+
+ private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
+ synchronized (mLock) {
+ if (mSystemReady) {
+ updateLocked(0, 0);
+ }
+ }
+ }
+ };
+
+ // A LocationListener to initialize the network location provider. The location updates
+ // are handled through the passive location provider.
+ private final LocationListener mEmptyLocationListener = new LocationListener() {
+ public void onLocationChanged(Location location) {
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ };
+
+ private final LocationListener mLocationListener = new LocationListener() {
+
+ public void onLocationChanged(Location location) {
+ final boolean hasMoved = hasMoved(location);
+ final boolean hasBetterAccuracy = mLocation == null
+ || location.getAccuracy() < mLocation.getAccuracy();
+ if (hasMoved || hasBetterAccuracy) {
+ synchronized (mLock) {
+ mLocation = location;
+ if (hasMoved && isDoingNightMode()
+ && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
+ }
+ }
+ }
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
+ /*
+ * The user has moved if the accuracy circles of the two locations
+ * don't overlap.
+ */
+ private boolean hasMoved(Location location) {
+ if (location == null) {
+ return false;
+ }
+ if (mLocation == null) {
+ return true;
+ }
+
+ /* if new location is older than the current one, the devices hasn't
+ * moved.
+ */
+ if (location.getTime() < mLocation.getTime()) {
+ return false;
+ }
+
+ /* Get the distance between the two points */
+ float distance = mLocation.distanceTo(location);
+
+ /* Get the total accuracy radius for both locations */
+ float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy();
+
+ /* If the distance is greater than the combined accuracy of the two
+ * points then they can't overlap and hence the user has moved.
+ */
+ return distance >= totalAccuracy;
+ }
+ };
+
+ public UiModeManagerService(Context context) {
+ mContext = context;
+
+ ServiceManager.addService(Context.UI_MODE_SERVICE, this);
+
+ mAlarmManager =
+ (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mLocationManager =
+ (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+ mContext.registerReceiver(mTwilightUpdateReceiver,
+ new IntentFilter(ACTION_UPDATE_NIGHT_MODE));
+ mContext.registerReceiver(mDockModeReceiver,
+ new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ mContext.registerReceiver(mBatteryReceiver,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+
+ PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+
+ mConfiguration.setToDefaults();
+
+ mCarModeKeepsScreenOn = (context.getResources().getInteger(
+ com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
+ mDeskModeKeepsScreenOn = (context.getResources().getInteger(
+ com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
+
+ mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+ }
+
+ public void disableCarMode(int flags) {
+ synchronized (mLock) {
+ setCarModeLocked(false);
+ if (mSystemReady) {
+ updateLocked(0, flags);
+ }
+ }
+ }
+
+ public void enableCarMode(int flags) {
+ synchronized (mLock) {
+ setCarModeLocked(true);
+ if (mSystemReady) {
+ updateLocked(flags, 0);
+ }
+ }
+ }
+
+ public int getCurrentModeType() {
+ synchronized (mLock) {
+ return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
+ }
+ }
+
+ public void setNightMode(int mode) throws RemoteException {
+ synchronized (mLock) {
+ switch (mode) {
+ case UiModeManager.MODE_NIGHT_NO:
+ case UiModeManager.MODE_NIGHT_YES:
+ case UiModeManager.MODE_NIGHT_AUTO:
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown mode: " + mode);
+ }
+ if (!isDoingNightMode()) {
+ return;
+ }
+
+ if (mNightMode != mode) {
+ long ident = Binder.clearCallingIdentity();
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.UI_NIGHT_MODE, mode);
+ Binder.restoreCallingIdentity(ident);
+ mNightMode = mode;
+ updateLocked(0, 0);
+ }
+ }
+ }
+
+ public int getNightMode() throws RemoteException {
+ return mNightMode;
+ }
+
+ void systemReady() {
+ synchronized (mLock) {
+ mSystemReady = true;
+ mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+ updateLocked(0, 0);
+ mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
+ }
+ }
+
+ boolean isDoingNightMode() {
+ return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ }
+
+ void setCarModeLocked(boolean enabled) {
+ if (mCarModeEnabled != enabled) {
+ mCarModeEnabled = enabled;
+ }
+ }
+
+ void updateDockState(int newState) {
+ synchronized (mLock) {
+ if (newState != mDockState) {
+ mDockState = newState;
+ setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR);
+ if (mSystemReady) {
+ updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
+ }
+ }
+ }
+ }
+
+ final void updateConfigurationLocked(boolean sendIt) {
+ int uiMode = Configuration.UI_MODE_TYPE_NORMAL;
+ if (mCarModeEnabled) {
+ uiMode = Configuration.UI_MODE_TYPE_CAR;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ uiMode = Configuration.UI_MODE_TYPE_DESK;
+ }
+ if (mCarModeEnabled) {
+ if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ updateTwilightLocked();
+ uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
+ : Configuration.UI_MODE_NIGHT_NO;
+ } else {
+ uiMode |= mNightMode << 4;
+ }
+ } else {
+ // Disabling the car mode clears the night mode.
+ uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
+ }
+
+ if (LOG) {
+ Slog.d(TAG,
+ "updateConfigurationLocked: mDockState=" + mDockState
+ + "; mCarMode=" + mCarModeEnabled
+ + "; mNightMode=" + mNightMode
+ + "; uiMode=" + uiMode);
+ }
+
+ mCurUiMode = uiMode;
+
+ if (!mHoldingConfiguration && uiMode != mSetUiMode) {
+ mSetUiMode = uiMode;
+ mConfiguration.uiMode = uiMode;
+
+ if (sendIt) {
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure communicating with activity manager", e);
+ }
+ }
+ }
+ }
+
+ final void updateLocked(int enableFlags, int disableFlags) {
+ long ident = Binder.clearCallingIdentity();
+
+ try {
+ String action = null;
+ String oldAction = null;
+ if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
+ adjustStatusBarCarModeLocked();
+ oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
+ } else if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_DESK) {
+ oldAction = UiModeManager.ACTION_EXIT_DESK_MODE;
+ }
+
+ if (mCarModeEnabled) {
+ if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) {
+ adjustStatusBarCarModeLocked();
+
+ if (oldAction != null) {
+ mContext.sendBroadcast(new Intent(oldAction));
+ }
+ mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
+ action = UiModeManager.ACTION_ENTER_CAR_MODE;
+ }
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_DESK) {
+ if (oldAction != null) {
+ mContext.sendBroadcast(new Intent(oldAction));
+ }
+ mLastBroadcastState = Intent.EXTRA_DOCK_STATE_DESK;
+ action = UiModeManager.ACTION_ENTER_DESK_MODE;
+ }
+ } else {
+ mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ action = oldAction;
+ }
+
+ if (action != null) {
+ // Send the ordered broadcast; the result receiver will receive after all
+ // broadcasts have been sent. If any broadcast receiver changes the result
+ // code from the initial value of RESULT_OK, then the result receiver will
+ // not launch the corresponding dock application. This gives apps a chance
+ // to override the behavior and stay in their app even when the device is
+ // placed into a dock.
+ Intent intent = new Intent(action);
+ intent.putExtra("enableFlags", enableFlags);
+ intent.putExtra("disableFlags", disableFlags);
+ mContext.sendOrderedBroadcast(intent, null,
+ mResultReceiver, null, Activity.RESULT_OK, null, null);
+ // Attempting to make this transition a little more clean, we are going
+ // to hold off on doing a configuration change until we have finished
+ // the broadcast and started the home activity.
+ mHoldingConfiguration = true;
+ } else {
+ Intent homeIntent = null;
+ if (mCarModeEnabled) {
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_CAR_DOCK);
+ }
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_DESK_DOCK);
+ }
+ } else {
+ if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_HOME);
+ }
+ }
+ if (homeIntent != null) {
+ try {
+ mContext.startActivity(homeIntent);
+ } catch (ActivityNotFoundException e) {
+ }
+ }
+ }
+
+ updateConfigurationLocked(true);
+
+ // keep screen on when charging and in car mode
+ boolean keepScreenOn = mCharging &&
+ ((mCarModeEnabled && mCarModeKeepsScreenOn) ||
+ (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
+ if (keepScreenOn != mWakeLock.isHeld()) {
+ if (keepScreenOn) {
+ mWakeLock.acquire();
+ } else {
+ mWakeLock.release();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void adjustStatusBarCarModeLocked() {
+ if (mStatusBarManager == null) {
+ mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+ }
+
+ // Fear not: StatusBarService manages a list of requests to disable
+ // features of the status bar; these are ORed together to form the
+ // active disabled list. So if (for example) the device is locked and
+ // the status bar should be totally disabled, the calls below will
+ // have no effect until the device is unlocked.
+ if (mStatusBarManager != null) {
+ mStatusBarManager.disable(mCarModeEnabled
+ ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
+ : StatusBarManager.DISABLE_NONE);
+ }
+
+ if (mNotificationManager == null) {
+ mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ if (mNotificationManager != null) {
+ if (mCarModeEnabled) {
+ Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+
+ Notification n = new Notification();
+ n.icon = R.drawable.stat_notify_car_mode;
+ n.defaults = Notification.DEFAULT_LIGHTS;
+ n.flags = Notification.FLAG_ONGOING_EVENT;
+ n.when = 0;
+ n.setLatestEventInfo(
+ mContext,
+ mContext.getString(R.string.car_mode_disable_notification_title),
+ mContext.getString(R.string.car_mode_disable_notification_message),
+ PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0));
+ mNotificationManager.notify(0, n);
+ } else {
+ mNotificationManager.cancel(0);
+ }
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+
+ boolean mPassiveListenerEnabled;
+ boolean mNetworkListenerEnabled;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_TWILIGHT:
+ synchronized (mLock) {
+ if (isDoingNightMode() && mLocation != null
+ && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ updateTwilightLocked();
+ updateLocked(0, 0);
+ }
+ }
+ break;
+ case MSG_ENABLE_LOCATION_UPDATES:
+ // enable network provider to receive at least location updates for a given
+ // distance.
+ boolean networkLocationEnabled;
+ try {
+ networkLocationEnabled =
+ mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+ } catch (Exception e) {
+ // we may get IllegalArgumentException if network location provider
+ // does not exist or is not yet installed.
+ networkLocationEnabled = false;
+ }
+ if (!mNetworkListenerEnabled && networkLocationEnabled) {
+ mNetworkListenerEnabled = true;
+ mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
+ LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
+
+ if (mLocation == null) {
+ retrieveLocation();
+ }
+ synchronized (mLock) {
+ if (isDoingNightMode() && mLocation != null
+ && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+ updateTwilightLocked();
+ updateLocked(0, 0);
+ }
+ }
+ }
+ // enable passive provider to receive updates from location fixes (gps
+ // and network).
+ boolean passiveLocationEnabled;
+ try {
+ passiveLocationEnabled =
+ mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
+ } catch (Exception e) {
+ // we may get IllegalArgumentException if passive location provider
+ // does not exist or is not yet installed.
+ passiveLocationEnabled = false;
+ }
+ if (!mPassiveListenerEnabled && passiveLocationEnabled) {
+ mPassiveListenerEnabled = true;
+ mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
+ 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
+ }
+ if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
+ long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL);
+ interval *= 1.5;
+ if (interval == 0) {
+ interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
+ } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
+ interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
+ }
+ Bundle bundle = new Bundle();
+ bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval);
+ Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES);
+ newMsg.setData(bundle);
+ mHandler.sendMessageDelayed(newMsg, interval);
+ }
+ break;
+ }
+ }
+
+ private void retrieveLocation() {
+ Location location = null;
+ final Iterator<String> providers =
+ mLocationManager.getProviders(new Criteria(), true).iterator();
+ while (providers.hasNext()) {
+ final Location lastKnownLocation =
+ mLocationManager.getLastKnownLocation(providers.next());
+ // pick the most recent location
+ if (location == null || (lastKnownLocation != null &&
+ location.getTime() < lastKnownLocation.getTime())) {
+ location = lastKnownLocation;
+ }
+ }
+ // In the case there is no location available (e.g. GPS fix or network location
+ // is not available yet), the longitude of the location is estimated using the timezone,
+ // latitude and accuracy are set to get a good average.
+ if (location == null) {
+ Time currentTime = new Time();
+ currentTime.set(System.currentTimeMillis());
+ double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
+ (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
+ location = new Location("fake");
+ location.setLongitude(lngOffset);
+ location.setLatitude(0);
+ location.setAccuracy(417000.0f);
+ location.setTime(System.currentTimeMillis());
+ }
+ synchronized (mLock) {
+ mLocation = location;
+ }
+ }
+ };
+
+ void updateTwilightLocked() {
+ if (mLocation == null) {
+ return;
+ }
+ final long currentTime = System.currentTimeMillis();
+ boolean nightMode;
+ // calculate current twilight
+ TwilightCalculator tw = new TwilightCalculator();
+ tw.calculateTwilight(currentTime,
+ mLocation.getLatitude(), mLocation.getLongitude());
+ if (tw.mState == TwilightCalculator.DAY) {
+ nightMode = false;
+ } else {
+ nightMode = true;
+ }
+
+ // schedule next update
+ long nextUpdate = 0;
+ if (tw.mSunrise == -1 || tw.mSunset == -1) {
+ // In the case the day or night never ends the update is scheduled 12 hours later.
+ nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS;
+ } else {
+ final int mLastTwilightState = tw.mState;
+ // add some extra time to be on the save side.
+ nextUpdate += DateUtils.MINUTE_IN_MILLIS;
+ if (currentTime > tw.mSunset) {
+ // next update should be on the following day
+ tw.calculateTwilight(currentTime
+ + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
+ mLocation.getLongitude());
+ }
+
+ if (mLastTwilightState == TwilightCalculator.NIGHT) {
+ nextUpdate += tw.mSunrise;
+ } else {
+ nextUpdate += tw.mSunset;
+ }
+ }
+
+ Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+ mAlarmManager.cancel(pendingIntent);
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
+
+ mComputedNightMode = nightMode;
+ }
+
+ @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 uimode service from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("Current UI Mode Service state:");
+ pw.print(" mDockState="); pw.print(mDockState);
+ pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+ pw.print(" mNightMode="); pw.print(mNightMode);
+ pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+ pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
+ pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+ pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+ pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
+ pw.print(" mSystemReady="); pw.println(mSystemReady);
+ if (mLocation != null) {
+ pw.print(" mLocation="); pw.println(mLocation);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/VibratorService.java
index 88074c2..2e7e3e1 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -16,60 +16,30 @@
package com.android.server;
-import com.android.internal.app.IBatteryStats;
-import com.android.server.am.BatteryStatsService;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.os.Hardware;
-import android.os.IHardwareService;
-import android.os.Message;
-import android.os.Power;
+import android.os.IVibratorService;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Binder;
import android.os.SystemClock;
-import android.util.Log;
+import android.util.Slog;
import java.util.LinkedList;
import java.util.ListIterator;
-public class HardwareService extends IHardwareService.Stub {
- private static final String TAG = "HardwareService";
-
- static final int LIGHT_ID_BACKLIGHT = 0;
- static final int LIGHT_ID_KEYBOARD = 1;
- static final int LIGHT_ID_BUTTONS = 2;
- static final int LIGHT_ID_BATTERY = 3;
- static final int LIGHT_ID_NOTIFICATIONS = 4;
- static final int LIGHT_ID_ATTENTION = 5;
-
- static final int LIGHT_FLASH_NONE = 0;
- static final int LIGHT_FLASH_TIMED = 1;
- static final int LIGHT_FLASH_HARDWARE = 2;
-
- /**
- * Light brightness is managed by a user setting.
- */
- static final int BRIGHTNESS_MODE_USER = 0;
-
- /**
- * Light brightness is managed by a light sensor.
- */
- static final int BRIGHTNESS_MODE_SENSOR = 1;
+public class VibratorService extends IVibratorService.Stub {
+ private static final String TAG = "VibratorService";
private final LinkedList<Vibration> mVibrations;
private Vibration mCurrentVibration;
- private boolean mAttentionLightOn;
- private boolean mPulsing;
-
private class Vibration implements IBinder.DeathRecipient {
private final IBinder mToken;
private final long mTimeout;
@@ -120,13 +90,11 @@ public class HardwareService extends IHardwareService.Stub {
}
}
- HardwareService(Context context) {
+ VibratorService(Context context) {
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
vibratorOff();
- mNativePointer = init_native();
-
mContext = context;
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
@@ -135,18 +103,11 @@ public class HardwareService extends IHardwareService.Stub {
mVibrations = new LinkedList<Vibration>();
- mBatteryStats = BatteryStatsService.getService();
-
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(mIntentReceiver, filter);
}
- protected void finalize() throws Throwable {
- finalize_native(mNativePointer);
- super.finalize();
- }
-
public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -194,7 +155,7 @@ public class HardwareService extends IHardwareService.Stub {
for (int i=0; i<N; i++) {
s += " " + pattern[i];
}
- Log.i(TAG, "vibrating with pattern: " + s);
+ Slog.i(TAG, "vibrating with pattern: " + s);
}
// we're running in the server so we can't fail
@@ -251,92 +212,6 @@ public class HardwareService extends IHardwareService.Stub {
}
}
- 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);
- }
-
- void setLightOff_UNCHECKED(int light) {
- setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0);
- }
-
- void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {
- int b = brightness & 0x000000ff;
- b = 0xff000000 | (b << 16) | (b << 8) | b;
- setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
- }
-
- void setLightColor_UNCHECKED(int light, int color) {
- setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0);
- }
-
- void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
- setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0);
- }
-
- public void setAttentionLight(boolean on, int color) {
- // Not worthy of a permission. We shouldn't have a flashlight permission.
- synchronized (this) {
- mAttentionLightOn = on;
- mPulsing = false;
- setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
- LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0);
- }
- }
-
- public void pulseBreathingLight() {
- synchronized (this) {
- // HACK: Added at the last minute of cupcake -- design this better;
- // Don't reuse the attention light -- make another one.
- if (false) {
- Log.d(TAG, "pulseBreathingLight mAttentionLightOn=" + mAttentionLightOn
- + " mPulsing=" + mPulsing);
- }
- if (!mAttentionLightOn && !mPulsing) {
- mPulsing = true;
- setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
- LIGHT_FLASH_HARDWARE, 7, 0, 0);
- mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
- }
- }
- }
-
- private Handler mH = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- synchronized (this) {
- if (false) {
- Log.d(TAG, "pulse cleanup handler firing mPulsing=" + mPulsing);
- }
- if (mPulsing) {
- mPulsing = false;
- setLight_native(mNativePointer, LIGHT_ID_ATTENTION,
- mAttentionLightOn ? 0xffffffff : 0,
- LIGHT_FLASH_NONE, 0, 0, 0);
- }
- }
- }
- };
-
private final Runnable mVibrationRunnable = new Runnable() {
public void run() {
synchronized (mVibrations) {
@@ -452,7 +327,7 @@ public class HardwareService extends IHardwareService.Stub {
// duration is saved for delay() at top of loop
duration = pattern[index++];
if (duration > 0) {
- HardwareService.this.vibratorOn(duration);
+ VibratorService.this.vibratorOn(duration);
}
} else {
if (repeat < 0) {
@@ -490,21 +365,13 @@ public class HardwareService extends IHardwareService.Stub {
}
};
- private static native int init_native();
- private static native void finalize_native(int ptr);
-
- private static native void setLight_native(int ptr, int light, int color, int mode,
- int onMS, int offMS, int brightnessMode);
+ private Handler mH = new Handler();
private final Context mContext;
private final PowerManager.WakeLock mWakeLock;
- private final IBatteryStats mBatteryStats;
-
volatile VibrateThread mThread;
- private int mNativePointer;
-
native static void vibratorOn(long milliseconds);
native static void vibratorOff();
}
diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java
index 07826a6..ae00438 100644
--- a/services/java/com/android/server/ViewServer.java
+++ b/services/java/com/android/server/ViewServer.java
@@ -16,7 +16,7 @@
package com.android.server;
-import android.util.Log;
+import android.util.Slog;
import java.net.ServerSocket;
import java.net.Socket;
@@ -45,7 +45,7 @@ class ViewServer implements Runnable {
private static final String LOG_TAG = "ViewServer";
private static final String VALUE_PROTOCOL_VERSION = "2";
- private static final String VALUE_SERVER_VERSION = "2";
+ private static final String VALUE_SERVER_VERSION = "3";
// Protocol commands
// Returns the protocol version
@@ -129,7 +129,7 @@ class ViewServer implements Runnable {
mServer = null;
return true;
} catch (IOException e) {
- Log.w(LOG_TAG, "Could not close the view server");
+ Slog.w(LOG_TAG, "Could not close the view server");
}
}
return false;
@@ -191,7 +191,7 @@ class ViewServer implements Runnable {
}
if (!result) {
- Log.w(LOG_TAG, "An error occured with the command: " + command);
+ Slog.w(LOG_TAG, "An error occured with the command: " + command);
}
} finally {
if (in != null) {
@@ -199,7 +199,7 @@ class ViewServer implements Runnable {
}
}
} catch (Exception e) {
- Log.w(LOG_TAG, "Connection error: ", e);
+ Slog.w(LOG_TAG, "Connection error: ", e);
} finally {
if (client != null) {
try {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 0933677..124da4e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -23,7 +23,7 @@ import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
import android.app.WallpaperInfo;
-import android.backup.BackupManager;
+import android.app.backup.BackupManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -46,7 +46,7 @@ import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
-import android.util.Log;
+import android.util.Slog;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.WindowManager;
@@ -65,8 +65,12 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.service.wallpaper.ImageWallpaper;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
+import com.android.server.DevicePolicyManagerService.ActiveAdmin;
+import com.android.server.DevicePolicyManagerService.MyPackageMonitor;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -122,6 +126,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
final Context mContext;
final IWindowManager mIWindowManager;
+ final MyPackageMonitor mMonitor;
int mWidth = -1;
int mHeight = -1;
@@ -150,6 +155,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperConnection mWallpaperConnection;
long mLastDiedTime;
+ boolean mWallpaperUpdating;
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
@@ -165,6 +171,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
if (mWallpaperConnection == this) {
+ mLastDiedTime = SystemClock.uptimeMillis();
mService = IWallpaperService.Stub.asInterface(service);
attachServiceLocked(this);
// XXX should probably do saveSettingsLocked() later
@@ -181,10 +188,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mService = null;
mEngine = null;
if (mWallpaperConnection == this) {
- Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
- if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
- < SystemClock.uptimeMillis()) {
- Log.w(TAG, "Reverting to built-in wallpaper!");
+ Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
+ if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
+ > SystemClock.uptimeMillis()) {
+ Slog.w(TAG, "Reverting to built-in wallpaper!");
bindWallpaperComponentLocked(null);
}
}
@@ -205,11 +212,92 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ class MyPackageMonitor extends PackageMonitor {
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ synchronized (mLock) {
+ if (mWallpaperComponent != null &&
+ mWallpaperComponent.getPackageName().equals(packageName)) {
+ mWallpaperUpdating = false;
+ ComponentName comp = mWallpaperComponent;
+ clearWallpaperComponentLocked();
+ bindWallpaperComponentLocked(comp);
+ }
+ }
+ }
+
+ @Override
+ public void onPackageUpdateStarted(String packageName, int uid) {
+ synchronized (mLock) {
+ if (mWallpaperComponent != null &&
+ mWallpaperComponent.getPackageName().equals(packageName)) {
+ mWallpaperUpdating = true;
+ }
+ }
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ return doPackagesChanged(doit);
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ doPackagesChanged(true);
+ }
+
+ boolean doPackagesChanged(boolean doit) {
+ boolean changed = false;
+ synchronized (mLock) {
+ if (mWallpaperComponent != null) {
+ int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ changed = true;
+ if (doit) {
+ Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
+ clearWallpaperLocked();
+ }
+ }
+ }
+ if (mNextWallpaperComponent != null) {
+ int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ mNextWallpaperComponent = null;
+ }
+ }
+ if (mWallpaperComponent != null
+ && isPackageModified(mWallpaperComponent.getPackageName())) {
+ try {
+ mContext.getPackageManager().getServiceInfo(
+ mWallpaperComponent, 0);
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
+ clearWallpaperLocked();
+ }
+ }
+ if (mNextWallpaperComponent != null
+ && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+ try {
+ mContext.getPackageManager().getServiceInfo(
+ mNextWallpaperComponent, 0);
+ } catch (NameNotFoundException e) {
+ mNextWallpaperComponent = null;
+ }
+ }
+ }
+ return changed;
+ }
+ }
+
public WallpaperManagerService(Context context) {
- if (DEBUG) Log.v(TAG, "WallpaperService startup");
+ if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
WALLPAPER_DIR.mkdirs();
loadSettingsLocked();
mWallpaperObserver.startWatching();
@@ -222,16 +310,16 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public void systemReady() {
- if (DEBUG) Log.v(TAG, "systemReady");
+ if (DEBUG) Slog.v(TAG, "systemReady");
synchronized (mLock) {
try {
bindWallpaperComponentLocked(mNextWallpaperComponent);
} catch (RuntimeException e) {
- Log.w(TAG, "Failure starting previous wallpaper", e);
+ Slog.w(TAG, "Failure starting previous wallpaper", e);
try {
bindWallpaperComponentLocked(null);
} catch (RuntimeException e2) {
- Log.w(TAG, "Failure starting default wallpaper", e2);
+ Slog.w(TAG, "Failure starting default wallpaper", e2);
clearWallpaperComponentLocked();
}
}
@@ -239,18 +327,28 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public void clearWallpaper() {
- if (DEBUG) Log.v(TAG, "clearWallpaper");
+ if (DEBUG) Slog.v(TAG, "clearWallpaper");
synchronized (mLock) {
- File f = WALLPAPER_FILE;
- if (f.exists()) {
- f.delete();
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- bindWallpaperComponentLocked(null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ clearWallpaperLocked();
+ }
+ }
+
+ public void clearWallpaperLocked() {
+ File f = WALLPAPER_FILE;
+ if (f.exists()) {
+ f.delete();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(null);
+ } catch (IllegalArgumentException e) {
+ // This can happen if the default wallpaper component doesn't
+ // exist. This should be a system configuration problem, but
+ // let's not let it crash the system and just live with no
+ // wallpaper.
+ Slog.e(TAG, "Default wallpaper component not found!", e);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -308,7 +406,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
- Log.w(TAG, "Error getting wallpaper", e);
+ Slog.w(TAG, "Error getting wallpaper", e);
}
return null;
}
@@ -324,7 +422,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public ParcelFileDescriptor setWallpaper(String name) {
- if (DEBUG) Log.v(TAG, "setWallpaper");
+ if (DEBUG) Slog.v(TAG, "setWallpaper");
checkPermission(android.Manifest.permission.SET_WALLPAPER);
synchronized (mLock) {
@@ -351,13 +449,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mName = name;
return fd;
} catch (FileNotFoundException e) {
- Log.w(TAG, "Error setting wallpaper", e);
+ Slog.w(TAG, "Error setting wallpaper", e);
}
return null;
}
public void setWallpaperComponent(ComponentName name) {
- if (DEBUG) Log.v(TAG, "setWallpaperComponent name=" + name);
+ if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
@@ -370,19 +468,19 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
void bindWallpaperComponentLocked(ComponentName componentName) {
- if (DEBUG) Log.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
+ if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
// Has the component changed?
if (mWallpaperConnection != null) {
if (mWallpaperComponent == null) {
if (componentName == null) {
- if (DEBUG) Log.v(TAG, "bindWallpaperComponentLocked: still using default");
+ if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
// Still using default wallpaper.
return;
}
} else if (mWallpaperComponent.equals(componentName)) {
// Changing to same wallpaper.
- if (DEBUG) Log.v(TAG, "same wallpaper");
+ if (DEBUG) Slog.v(TAG, "same wallpaper");
return;
}
}
@@ -394,14 +492,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (defaultComponent != null) {
// See if there is a default wallpaper component specified
componentName = ComponentName.unflattenFromString(defaultComponent);
- if (DEBUG) Log.v(TAG, "Use default component walpaper:" + componentName);
+ if (DEBUG) Slog.v(TAG, "Use default component wallpaper:" + componentName);
}
if (componentName == null) {
// Fall back to static image wallpaper
componentName = mImageWallpaperComponent;
//clearWallpaperComponentLocked();
//return;
- if (DEBUG) Log.v(TAG, "Using image wallpaper");
+ if (DEBUG) Slog.v(TAG, "Using image wallpaper");
}
}
ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
@@ -440,7 +538,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
// Bind the service!
- if (DEBUG) Log.v(TAG, "Binding to:" + componentName);
+ if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
WallpaperConnection newConn = new WallpaperConnection(wi);
intent.setComponent(componentName);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
@@ -461,7 +559,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mWallpaperConnection = newConn;
mLastDiedTime = SystemClock.uptimeMillis();
try {
- if (DEBUG) Log.v(TAG, "Adding window token: " + newConn.mToken);
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken);
mIWindowManager.addWindowToken(newConn.mToken,
WindowManager.LayoutParams.TYPE_WALLPAPER);
} catch (RemoteException e) {
@@ -483,7 +581,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
mContext.unbindService(mWallpaperConnection);
try {
- if (DEBUG) Log.v(TAG, "Removing window token: "
+ if (DEBUG) Slog.v(TAG, "Removing window token: "
+ mWallpaperConnection.mToken);
mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
} catch (RemoteException e) {
@@ -498,8 +596,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
WindowManager.LayoutParams.TYPE_WALLPAPER, false,
mWidth, mHeight);
} catch (RemoteException e) {
- Log.w(TAG, "Failed attaching wallpaper; clearing", e);
- bindWallpaperComponentLocked(null);
+ Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
+ if (!mWallpaperUpdating) {
+ bindWallpaperComponentLocked(null);
+ }
}
}
@@ -566,7 +666,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
private void loadSettingsLocked() {
- if (DEBUG) Log.v(TAG, "loadSettingsLocked");
+ if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
JournaledFile journal = makeJournaledFile();
FileInputStream stream = null;
@@ -592,25 +692,25 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
: null;
if (DEBUG) {
- Log.v(TAG, "mWidth:" + mWidth);
- Log.v(TAG, "mHeight:" + mHeight);
- Log.v(TAG, "mName:" + mName);
- Log.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
+ Slog.v(TAG, "mWidth:" + mWidth);
+ Slog.v(TAG, "mHeight:" + mHeight);
+ Slog.v(TAG, "mName:" + mName);
+ Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
}
}
}
} while (type != XmlPullParser.END_DOCUMENT);
success = true;
} catch (NullPointerException e) {
- Log.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
- Log.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (XmlPullParserException e) {
- Log.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (IOException e) {
- Log.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (IndexOutOfBoundsException e) {
- Log.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(TAG, "failed parsing " + file + " " + e);
}
try {
if (stream != null) {
@@ -628,27 +728,33 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
void settingsRestored() {
- if (DEBUG) Log.v(TAG, "settingsRestored");
+ if (DEBUG) Slog.v(TAG, "settingsRestored");
boolean success = false;
synchronized (mLock) {
loadSettingsLocked();
if (mNextWallpaperComponent != null &&
!mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
- // We can't restore live wallpapers, so just go with the default
- bindWallpaperComponentLocked(null);
+ try {
+ bindWallpaperComponentLocked(mNextWallpaperComponent);
+ } catch (IllegalArgumentException e) {
+ // No such live wallpaper or other failure; fall back to the default
+ // live wallpaper (since the profile being restored indicated that the
+ // user had selected a live rather than static one).
+ bindWallpaperComponentLocked(null);
+ }
success = true;
} else {
// If there's a wallpaper name, we use that. If that can't be loaded, then we
// use the default.
if ("".equals(mName)) {
- if (DEBUG) Log.v(TAG, "settingsRestored: name is empty");
+ if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
success = true;
} else {
- if (DEBUG) Log.v(TAG, "settingsRestored: attempting to restore named resource");
+ if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
success = restoreNamedResourceLocked();
}
- if (DEBUG) Log.v(TAG, "settingsRestored: success=" + success);
+ if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
bindWallpaperComponentLocked(mImageWallpaperComponent);
}
@@ -656,7 +762,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
if (!success) {
- Log.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
+ Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
mName = "";
WALLPAPER_FILE.delete();
}
@@ -693,12 +799,15 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
Resources r = c.getResources();
resId = r.getIdentifier(resName, null, null);
if (resId == 0) {
- Log.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
+ Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
+ " ident=" + ident);
return false;
}
res = r.openRawResource(resId);
+ if (WALLPAPER_FILE.exists()) {
+ WALLPAPER_FILE.delete();
+ }
fos = new FileOutputStream(WALLPAPER_FILE);
byte[] buffer = new byte[32768];
@@ -708,14 +817,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
// mWallpaperObserver will notice the close and send the change broadcast
- Log.v(TAG, "Restored wallpaper: " + resName);
+ Slog.v(TAG, "Restored wallpaper: " + resName);
return true;
} catch (NameNotFoundException e) {
- Log.e(TAG, "Package name " + pkg + " not found");
+ Slog.e(TAG, "Package name " + pkg + " not found");
} catch (Resources.NotFoundException e) {
- Log.e(TAG, "Resource not found: " + resId);
+ Slog.e(TAG, "Resource not found: " + resId);
} catch (IOException e) {
- Log.e(TAG, "IOException while restoring wallpaper ", e);
+ Slog.e(TAG, "IOException while restoring wallpaper ", e);
} finally {
if (res != null) {
try {
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 68bf4fb..be1d1c4 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -29,13 +29,16 @@ import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
+import android.os.ServiceManager;
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 android.util.Slog;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -52,16 +55,6 @@ public class Watchdog extends Thread {
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
@@ -107,16 +100,16 @@ public class Watchdog extends Thread {
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,
+ Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
+ Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
- Settings.Gservices.MEMCHECK_SYSTEM_HARD_THRESHOLD,
+ Settings.Secure.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,
+ Settings.Secure.MEMCHECK_PHONE_ENABLED,
+ Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
- Settings.Gservices.MEMCHECK_PHONE_HARD_THRESHOLD,
+ Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
final Calendar mCalendar = Calendar.getInstance();
@@ -171,11 +164,11 @@ public class Watchdog extends Thread {
}
void retrieveSettings(ContentResolver resolver) {
- mSoftThreshold = Settings.Gservices.getInt(
+ mSoftThreshold = Settings.Secure.getInt(
resolver, mSoftSetting, mSoftThreshold);
- mHardThreshold = Settings.Gservices.getInt(
+ mHardThreshold = Settings.Secure.getInt(
resolver, mHardSetting, mHardThreshold);
- mEnabled = Settings.Gservices.getInt(
+ mEnabled = Settings.Secure.getInt(
resolver, mEnabledSetting, 0) != 0;
}
@@ -188,7 +181,7 @@ public class Watchdog extends Thread {
} else {
mState = STATE_HARD;
}
- EventLog.writeEvent(EVENT_LOG_PROC_PSS_TAG, mProcessName, pid, mLastPss);
+ EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
if (mState == STATE_OK) {
// Memory is good, don't recover.
@@ -197,7 +190,7 @@ public class Watchdog extends Thread {
if (mState == STATE_HARD) {
// Memory is really bad, kill right now.
- EventLog.writeEvent(EVENT_LOG_HARD_RESET_TAG, mProcessName, pid,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
mHardThreshold, mLastPss);
return mEnabled;
}
@@ -212,7 +205,7 @@ public class Watchdog extends Thread {
} else {
skipReason = shouldWeBeBrutalLocked(curTime);
}
- EventLog.writeEvent(EVENT_LOG_SOFT_RESET_TAG, mProcessName, pid,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
if (skipReason != null) {
mNeedScheduledCheck = true;
@@ -239,7 +232,7 @@ public class Watchdog extends Thread {
// 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.");
+ if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
logGlobalMemory();
}
} break;
@@ -249,7 +242,7 @@ public class Watchdog extends Thread {
// 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.");
+ if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
checkMemory();
}
@@ -257,7 +250,7 @@ public class Watchdog extends Thread {
// 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.");
+ if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
logGlobalMemory();
}
@@ -265,8 +258,8 @@ public class Watchdog extends Thread {
// See if we should force a reboot.
int rebootInterval = mReqRebootInterval >= 0
- ? mReqRebootInterval : Settings.Gservices.getInt(
- mResolver, Settings.Gservices.REBOOT_INTERVAL,
+ ? mReqRebootInterval : Settings.Secure.getInt(
+ mResolver, Settings.Secure.REBOOT_INTERVAL,
REBOOT_DEFAULT_INTERVAL);
if (mRebootInterval != rebootInterval) {
mRebootInterval = rebootInterval;
@@ -276,8 +269,8 @@ public class Watchdog extends Thread {
}
// See if we should check memory conditions.
- long memCheckInterval = Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_INTERVAL,
+ long memCheckInterval = Settings.Secure.getLong(
+ mResolver, Settings.Secure.MEMCHECK_INTERVAL,
MEMCHECK_DEFAULT_INTERVAL) * 1000;
if ((mLastMemCheckTime+memCheckInterval) < now) {
// It is now time to collect pss information. This
@@ -285,17 +278,17 @@ public class Watchdog extends Thread {
// 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.");
+ if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
collectMemory();
mHavePss = true;
- long memCheckRealtimeInterval = Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_LOG_REALTIME_INTERVAL,
+ long memCheckRealtimeInterval = Settings.Secure.getLong(
+ mResolver, Settings.Secure.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.");
+ if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
collectGlobalMemory();
mHaveGlobalPss = true;
}
@@ -325,7 +318,7 @@ public class Watchdog extends Thread {
final class CheckupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
- if (localLOGV) Log.v(TAG, "Alarm went off, checking memory.");
+ if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
checkMemory();
}
}
@@ -333,7 +326,7 @@ public class Watchdog extends Thread {
final class RebootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
- if (localLOGV) Log.v(TAG, "Alarm went off, checking reboot.");
+ if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
checkReboot(true);
}
}
@@ -348,7 +341,7 @@ public class Watchdog extends Thread {
mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
- EventLog.writeEvent(EVENT_LOG_REQUESTED_REBOOT_TAG,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
mReqRecheckInterval, mReqRebootStartTime,
mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
@@ -478,8 +471,8 @@ public class Watchdog extends Thread {
long curTime;
long nextTime = 0;
- long recheckInterval = Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
+ long recheckInterval = Settings.Secure.getLong(
+ mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
mSystemMemMonitor.retrieveSettings(mResolver);
@@ -504,7 +497,7 @@ public class Watchdog extends Thread {
if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
mPhonePss)) {
// Just kill the phone process and let it restart.
- Log.i(TAG, "Watchdog is killing the phone process");
+ Slog.i(TAG, "Watchdog is killing the phone process");
Process.killProcess(mPhonePid);
}
} else {
@@ -521,25 +514,25 @@ public class Watchdog extends Thread {
} 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");
+ if (localLOGV) Slog.v(TAG, "Computing next time range");
computeMemcheckTimesLocked(nextTime);
nextTime = mMemcheckExecStartTime;
}
if (localLOGV) {
mCalendar.setTimeInMillis(nextTime);
- Log.v(TAG, "Next Alarm Time: " + mCalendar);
+ Slog.v(TAG, "Next Alarm Time: " + mCalendar);
}
}
}
if (needScheduledCheck) {
- if (localLOGV) Log.v(TAG, "Scheduling next memcheck alarm for "
+ if (localLOGV) Slog.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!");
+ if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
mAlarm.remove(mCheckupIntent);
}
}
@@ -561,21 +554,21 @@ public class Watchdog extends Thread {
void logGlobalMemory() {
PssStats stats = mPssStats;
mActivity.collectPss(stats);
- EventLog.writeEvent(EVENT_LOG_PSS_STATS_TAG,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
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,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
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,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
(int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
(int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
(int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
@@ -589,35 +582,35 @@ public class Watchdog extends Thread {
mVMStatSizes[i] -= mPrevVMStatSizes[i];
mPrevVMStatSizes[i] = v;
}
- EventLog.writeEvent(EVENT_LOG_VMSTAT_TAG, dur,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, 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,
+ : Settings.Secure.getInt(
+ mResolver, Settings.Secure.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!");
+ if (localLOGV) Slog.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,
+ : Settings.Secure.getLong(
+ mResolver, Settings.Secure.REBOOT_START_TIME,
REBOOT_DEFAULT_START_TIME);
long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
- : Settings.Gservices.getLong(
- mResolver, Settings.Gservices.REBOOT_WINDOW,
+ : Settings.Secure.getLong(
+ mResolver, Settings.Secure.REBOOT_WINDOW,
REBOOT_DEFAULT_WINDOW)) * 1000;
long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
- : Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
+ : Settings.Secure.getLong(
+ mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
retrieveBrutalityAmount();
@@ -635,7 +628,7 @@ public class Watchdog extends Thread {
(now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
if (fromAlarm && rebootWindowMillis <= 0) {
// No reboot window -- just immediately reboot.
- EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
(int)rebootIntervalMillis, (int)rebootStartTime*1000,
(int)rebootWindowMillis, "");
rebootSystem("Checkin scheduled forced");
@@ -649,7 +642,7 @@ public class Watchdog extends Thread {
now, rebootStartTime);
} else if (now < (realStartTime+rebootWindowMillis)) {
String doit = shouldWeBeBrutalLocked(now);
- EventLog.writeEvent(EVENT_LOG_SCHEDULED_REBOOT_TAG, now,
+ EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
(int)rebootInterval, (int)rebootStartTime*1000,
(int)rebootWindowMillis, doit != null ? doit : "");
if (doit == null) {
@@ -673,7 +666,7 @@ public class Watchdog extends Thread {
}
}
- if (localLOGV) Log.v(TAG, "Scheduling next reboot alarm for "
+ if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
+ ((realStartTime-now)/1000/60) + "m from now");
mAlarm.remove(mRebootIntent);
mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
@@ -683,12 +676,9 @@ public class Watchdog extends Thread {
* 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);
- }
+ Slog.i(TAG, "Rebooting system because: " + reason);
+ PowerManagerService pms = (PowerManagerService) ServiceManager.getService("power");
+ pms.reboot(reason);
}
/**
@@ -698,12 +688,12 @@ public class Watchdog extends Thread {
*/
void retrieveBrutalityAmount() {
mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
- : Settings.Gservices.getInt(
- mResolver, Settings.Gservices.MEMCHECK_MIN_SCREEN_OFF,
+ : Settings.Secure.getInt(
+ mResolver, Settings.Secure.MEMCHECK_MIN_SCREEN_OFF,
MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000;
mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
- : Settings.Gservices.getInt(
- mResolver, Settings.Gservices.MEMCHECK_MIN_ALARM,
+ : Settings.Secure.getInt(
+ mResolver, Settings.Secure.MEMCHECK_MIN_ALARM,
MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
}
@@ -747,11 +737,11 @@ public class Watchdog extends Thread {
mMemcheckLastTime = curTime;
- long memcheckExecStartTime = Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_EXEC_START_TIME,
+ long memcheckExecStartTime = Settings.Secure.getLong(
+ mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME,
MEMCHECK_DEFAULT_EXEC_START_TIME);
- long memcheckExecEndTime = Settings.Gservices.getLong(
- mResolver, Settings.Gservices.MEMCHECK_EXEC_END_TIME,
+ long memcheckExecEndTime = Settings.Secure.getLong(
+ mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME,
MEMCHECK_DEFAULT_EXEC_END_TIME);
mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
@@ -767,11 +757,11 @@ public class Watchdog extends Thread {
if (localLOGV) {
mCalendar.setTimeInMillis(curTime);
- Log.v(TAG, "Current Time: " + mCalendar);
+ Slog.v(TAG, "Current Time: " + mCalendar);
mCalendar.setTimeInMillis(mMemcheckExecStartTime);
- Log.v(TAG, "Start Check Time: " + mCalendar);
+ Slog.v(TAG, "Start Check Time: " + mCalendar);
mCalendar.setTimeInMillis(mMemcheckExecEndTime);
- Log.v(TAG, "End Check Time: " + mCalendar);
+ Slog.v(TAG, "End Check Time: " + mCalendar);
}
}
@@ -814,19 +804,14 @@ public class Watchdog extends Thread {
// 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 {
+ while (timeout > 0 && !mForceKillSystem) {
try {
- wait(timeout);
+ wait(timeout); // notifyAll() is called when mForceKillSystem is set
} 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");
- }
+ Log.wtf(TAG, e);
}
timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
- } while (timeout > 0 && !mForceKillSystem);
+ }
if (mCompleted && !mForceKillSystem) {
// The monitors have returned.
@@ -835,22 +820,30 @@ public class Watchdog extends Thread {
}
// 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.
+ // First collect stack traces from all threads of the system process.
+ // 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);
+ EventLog.writeEvent(EventLogTags.WATCHDOG, name);
- // Wait a bit longer before killing so we can make sure that the stacks are captured.
- try {
- Thread.sleep(10*1000);
- } catch (InterruptedException e) {
- }
+ ArrayList pids = new ArrayList();
+ pids.add(Process.myPid());
+ if (mPhonePid > 0) pids.add(mPhonePid);
+ File stack = ActivityManagerService.dumpStackTraces(pids);
+
+ // Give some extra time to make sure the stack traces get written.
+ // The system's been hanging for a minute, another second or two won't hurt much.
+ SystemClock.sleep(2000);
+
+ mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
// Only kill the process if the debugger is not attached.
if (!Debug.isDebuggerConnected()) {
- Log.i(TAG, "Watchdog is killing the system process");
+ Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
Process.killProcess(Process.myPid());
+ System.exit(10);
+ } else {
+ Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
}
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 3a08e4d..c0a4491 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -22,6 +22,12 @@ 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 static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothA2dp;
@@ -40,6 +46,9 @@ import android.net.wifi.WifiStateTracker;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.ConnectivityManager;
+import android.net.InterfaceConfiguration;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
import android.net.NetworkUtils;
@@ -47,6 +56,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -54,7 +64,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
-import android.util.Log;
+import android.util.Slog;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -67,10 +77,12 @@ import java.util.Set;
import java.util.regex.Pattern;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.net.UnknownHostException;
import com.android.internal.app.IBatteryStats;
-import android.backup.IBackupManager;
+import android.app.backup.IBackupManager;
import com.android.server.am.BatteryStatsService;
+import com.android.internal.R;
/**
* WifiService handles remote WiFi operation requests by implementing
@@ -84,9 +96,11 @@ public class WifiService extends IWifiManager.Stub {
private static final boolean DBG = false;
private static final Pattern scanResultPattern = Pattern.compile("\t+");
private final WifiStateTracker mWifiStateTracker;
+ /* TODO: fetch a configurable interface */
+ private static final String SOFTAP_IFACE = "wl0.1";
private Context mContext;
- private int mWifiState;
+ private int mWifiApState;
private AlarmManager mAlarmManager;
private PendingIntent mIdleIntent;
@@ -95,6 +109,8 @@ public class WifiService extends IWifiManager.Stub {
private boolean mDeviceIdle;
private int mPluggedType;
+ private enum DriverAction {DRIVER_UNLOAD, NO_DRIVER_UNLOAD};
+
// true if the user enabled Wifi while in airplane mode
private boolean mAirplaneModeOverwridden;
@@ -112,9 +128,14 @@ public class WifiService extends IWifiManager.Stub {
private final IBatteryStats mBatteryStats;
+ private INetworkManagementService nwService;
+ ConnectivityManager mCm;
+ private WifiWatchdogService mWifiWatchdogService = null;
+ private String[] mWifiRegexs;
+
/**
- * 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
+ * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
+ * Settings.Secure 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.
@@ -139,11 +160,16 @@ public class WifiService extends IWifiManager.Stub {
// 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 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 static final int MESSAGE_UPDATE_STATE = 5;
+ private static final int MESSAGE_START_ACCESS_POINT = 6;
+ private static final int MESSAGE_STOP_ACCESS_POINT = 7;
+ private static final int MESSAGE_SET_CHANNELS = 8;
+
private final WifiHandler mWifiHandler;
@@ -164,6 +190,12 @@ public class WifiService extends IWifiManager.Stub {
*/
private int mLastEnableUid = Process.myUid();
+ /*
+ * Last UID that asked to enable WIFI AP.
+ */
+ private int mLastApEnableUid = Process.myUid();
+
+
/**
* Number of allowed radio frequency channels in various regulatory domains.
* This list is sufficient for 802.11b/g networks (2.4GHz range).
@@ -179,6 +211,9 @@ public class WifiService extends IWifiManager.Stub {
mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ nwService = INetworkManagementService.Stub.asInterface(b);
+
mScanResultCache = new LinkedHashMap<String, ScanResult>(
SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
/*
@@ -194,8 +229,8 @@ public class WifiService extends IWifiManager.Stub {
wifiThread.start();
mWifiHandler = new WifiHandler(wifiThread.getLooper());
- mWifiState = WIFI_STATE_DISABLED;
- boolean wifiEnabled = getPersistedWifiEnabled();
+ mWifiStateTracker.setWifiState(WIFI_STATE_DISABLED);
+ mWifiApState = WIFI_AP_STATE_DISABLED;
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -204,21 +239,6 @@ public class WifiService extends IWifiManager.Stub {
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() {
@@ -226,12 +246,102 @@ public class WifiService extends IWifiManager.Stub {
public void onReceive(Context context, Intent intent) {
// clear our flag indicating the user has overwridden airplane mode
mAirplaneModeOverwridden = false;
+ // on airplane disable, restore Wifi if the saved state indicates so
+ if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
+ persistWifiEnabled(true);
+ }
updateWifiState();
}
},
new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
- setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ ArrayList<String> available = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ ArrayList<String> active = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ updateTetherState(available, active);
+
+ }
+ },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ }
+
+ /**
+ * Check if Wi-Fi needs to be enabled and start
+ * if needed
+ *
+ * This function is used only at boot time
+ */
+ public void startWifi() {
+ /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
+ boolean wifiEnabled = !isAirplaneModeOn()
+ && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
+ Slog.i(TAG, "WifiService starting up with Wi-Fi " +
+ (wifiEnabled ? "enabled" : "disabled"));
+ setWifiEnabled(wifiEnabled);
+ }
+
+ private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
+
+ boolean wifiTethered = false;
+ boolean wifiAvailable = false;
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mWifiRegexs = mCm.getTetherableWifiRegexs();
+
+ for (String intf : available) {
+ for (String regex : mWifiRegexs) {
+ if (intf.matches(regex)) {
+
+ InterfaceConfiguration ifcg = null;
+ try {
+ ifcg = service.getInterfaceConfig(intf);
+ if (ifcg != null) {
+ /* IP/netmask: 192.168.43.1/255.255.255.0 */
+ ifcg.ipAddr = (192 << 24) + (168 << 16) + (43 << 8) + 1;
+ ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
+ ifcg.interfaceFlags = "up";
+
+ service.setInterfaceConfig(intf, ifcg);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Error configuring interface " + intf + ", :" + e);
+ try {
+ nwService.stopAccessPoint();
+ } catch (Exception ee) {
+ Slog.e(TAG, "Could not stop AP, :" + ee);
+ }
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, 0, DriverAction.DRIVER_UNLOAD);
+ return;
+ }
+
+ if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ Slog.e(TAG, "Error tethering "+intf);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private boolean testAndClearWifiSavedState() {
+ final ContentResolver cr = mContext.getContentResolver();
+ int wifiSavedState = 0;
+ try {
+ wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
+ if(wifiSavedState == 1)
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
+ } catch (Settings.SettingNotFoundException e) {
+ ;
+ }
+ return (wifiSavedState == 1);
}
private boolean getPersistedWifiEnabled() {
@@ -259,9 +369,8 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean pingSupplicant() {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- return WifiNative.pingCommand();
- }
+
+ return mWifiStateTracker.ping();
}
/**
@@ -270,20 +379,19 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean startScan(boolean forceActive) {
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(forceActive);
+
+ switch (mWifiStateTracker.getSupplicantState()) {
+ case DISCONNECTED:
+ case INACTIVE:
+ case SCANNING:
+ case DORMANT:
+ break;
+ default:
+ mWifiStateTracker.setScanResultHandling(
+ WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
+ break;
}
+ return mWifiStateTracker.scan(forceActive);
}
/**
@@ -321,8 +429,9 @@ public class WifiService extends IWifiManager.Stub {
*/
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
+ final int wifiState = mWifiStateTracker.getWifiState();
- if (mWifiState == eventualWifiState) {
+ if (wifiState == eventualWifiState) {
return true;
}
if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
@@ -336,26 +445,38 @@ public class WifiService extends IWifiManager.Stub {
* Avoid doing a disable when the current Wifi state is UNKNOWN
* TODO: Handle driver load fail and supplicant lost as seperate states
*/
- if (mWifiState == WIFI_STATE_UNKNOWN && !enable) {
+ if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
+ return false;
+ }
+
+ /**
+ * Fail Wifi if AP is enabled
+ * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
+ * WIFI_STATE_FAILED
+ */
+ if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
+ setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
if (enable) {
- if (!WifiNative.loadDriver()) {
- Log.e(TAG, "Failed to load Wi-Fi driver.");
+ if (!mWifiStateTracker.loadDriver()) {
+ Slog.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
- if (!WifiNative.startSupplicant()) {
- WifiNative.unloadDriver();
- Log.e(TAG, "Failed to start supplicant daemon.");
+ if (!mWifiStateTracker.startSupplicant()) {
+ mWifiStateTracker.unloadDriver();
+ Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
+
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
+
} else {
mContext.unregisterReceiver(mReceiver);
@@ -363,22 +484,27 @@ public class WifiService extends IWifiManager.Stub {
mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
boolean failedToStopSupplicantOrUnloadDriver = false;
- if (!WifiNative.stopSupplicant()) {
- Log.e(TAG, "Failed to stop supplicant daemon.");
+
+ if (!mWifiStateTracker.stopSupplicant()) {
+ Slog.e(TAG, "Failed to stop supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
- // We must reset the interface before we unload the driver
- mWifiStateTracker.resetInterface(false);
+ /**
+ * Reset connections and disable interface
+ * before we unload the driver
+ */
+ mWifiStateTracker.resetConnections(true);
- if (!WifiNative.unloadDriver()) {
- Log.e(TAG, "Failed to unload Wi-Fi driver.");
+ if (!mWifiStateTracker.unloadDriver()) {
+ Slog.e(TAG, "Failed to unload Wi-Fi driver.");
if (!failedToStopSupplicantOrUnloadDriver) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
}
+
if (failedToStopSupplicantOrUnloadDriver) {
return false;
}
@@ -390,12 +516,11 @@ public class WifiService extends IWifiManager.Stub {
persistWifiEnabled(enable);
}
setWifiEnabledState(eventualWifiState, uid);
-
return true;
}
private void setWifiEnabledState(int wifiState, int uid) {
- final int previousWifiState = mWifiState;
+ final int previousWifiState = mWifiStateTracker.getWifiState();
long ident = Binder.clearCallingIdentity();
try {
@@ -410,7 +535,7 @@ public class WifiService extends IWifiManager.Stub {
}
// Update state
- mWifiState = wifiState;
+ mWifiStateTracker.setWifiState(wifiState);
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
@@ -447,7 +572,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public int getWifiEnabledState() {
enforceAccessPermission();
- return mWifiState;
+ return mWifiStateTracker.getWifiState();
}
/**
@@ -456,9 +581,8 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean disconnect() {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- return WifiNative.disconnectCommand();
- }
+
+ return mWifiStateTracker.disconnect();
}
/**
@@ -467,9 +591,8 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean reconnect() {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- return WifiNative.reconnectCommand();
- }
+
+ return mWifiStateTracker.reconnectCommand();
}
/**
@@ -478,9 +601,204 @@ public class WifiService extends IWifiManager.Stub {
*/
public boolean reassociate() {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- return WifiNative.reassociateCommand();
+
+ return mWifiStateTracker.reassociate();
+ }
+
+ /**
+ * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
+ * @param wifiConfig SSID, security and channel details as
+ * part of WifiConfiguration
+ * @param enabled, true to enable and false to disable
+ * @return {@code true} if the start operation was
+ * started or is already in the queue.
+ */
+ public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
+ enforceChangePermission();
+ if (mWifiHandler == null) return false;
+
+ synchronized (mWifiHandler) {
+
+ long ident = Binder.clearCallingIdentity();
+ sWakeLock.acquire();
+ Binder.restoreCallingIdentity(ident);
+
+ mLastApEnableUid = Binder.getCallingUid();
+ sendAccessPointMessage(enabled, wifiConfig, Binder.getCallingUid());
+ }
+
+ return true;
+ }
+
+ public WifiConfiguration getWifiApConfiguration() {
+ final ContentResolver cr = mContext.getContentResolver();
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ int authType;
+ try {
+ wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
+ if (wifiConfig.SSID == null)
+ return null;
+ authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
+ wifiConfig.allowedKeyManagement.set(authType);
+ wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
+ return wifiConfig;
+ } catch (Settings.SettingNotFoundException e) {
+ Slog.e(TAG,"AP settings not found, returning");
+ return null;
+ }
+ }
+
+ private void persistApConfiguration(WifiConfiguration wifiConfig) {
+ final ContentResolver cr = mContext.getContentResolver();
+ boolean isWpa;
+ if (wifiConfig == null)
+ return;
+ Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
+ isWpa = wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK);
+ Settings.Secure.putInt(cr,
+ Settings.Secure.WIFI_AP_SECURITY,
+ isWpa ? KeyMgmt.WPA_PSK : KeyMgmt.NONE);
+ if (isWpa)
+ Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
+ }
+
+ /**
+ * Enables/disables Wi-Fi AP synchronously. The driver is loaded
+ * and soft access point configured as a single operation.
+ * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
+ * @param uid The UID of the process making the request.
+ * @param wifiConfig The WifiConfiguration for AP
+ * @return {@code true} if the operation succeeds (or if the existing state
+ * is the same as the requested state)
+ */
+ private boolean setWifiApEnabledBlocking(boolean enable,
+ int uid, WifiConfiguration wifiConfig) {
+ final int eventualWifiApState = enable ? WIFI_AP_STATE_ENABLED : WIFI_AP_STATE_DISABLED;
+
+ if (mWifiApState == eventualWifiApState) {
+ /* Configuration changed on a running access point */
+ if(enable && (wifiConfig != null)) {
+ try {
+ persistApConfiguration(wifiConfig);
+ nwService.setAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName(),
+ SOFTAP_IFACE);
+ return true;
+ } catch(Exception e) {
+ Slog.e(TAG, "Exception in nwService during AP restart");
+ try {
+ nwService.stopAccessPoint();
+ } catch (Exception ee) {
+ Slog.e(TAG, "Could not stop AP, :" + ee);
+ }
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Fail AP if Wifi is enabled
+ */
+ if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) && enable) {
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
+ return false;
+ }
+
+ setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING :
+ WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD);
+
+ if (enable) {
+
+ /* Use default config if there is no existing config */
+ if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
+ wifiConfig = new WifiConfiguration();
+ wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
+ wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+ }
+ persistApConfiguration(wifiConfig);
+
+ if (!mWifiStateTracker.loadDriver()) {
+ Slog.e(TAG, "Failed to load Wi-Fi driver for AP mode");
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
+ return false;
+ }
+
+ try {
+ nwService.startAccessPoint(wifiConfig, mWifiStateTracker.getInterfaceName(),
+ SOFTAP_IFACE);
+ } catch(Exception e) {
+ Slog.e(TAG, "Exception in startAccessPoint()");
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
+ return false;
+ }
+
+ } else {
+
+ try {
+ nwService.stopAccessPoint();
+ } catch(Exception e) {
+ Slog.e(TAG, "Exception in stopAccessPoint()");
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.DRIVER_UNLOAD);
+ return false;
+ }
+
+ if (!mWifiStateTracker.unloadDriver()) {
+ Slog.e(TAG, "Failed to unload Wi-Fi driver for AP mode");
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
+ return false;
+ }
}
+
+ setWifiApEnabledState(eventualWifiApState, uid, DriverAction.NO_DRIVER_UNLOAD);
+ return true;
+ }
+
+ /**
+ * see {@link WifiManager#getWifiApState()}
+ * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
+ */
+ public int getWifiApEnabledState() {
+ enforceAccessPermission();
+ return mWifiApState;
+ }
+
+ private void setWifiApEnabledState(int wifiAPState, int uid, DriverAction flag) {
+ final int previousWifiApState = mWifiApState;
+
+ /**
+ * Unload the driver if going to a failed state
+ */
+ if ((mWifiApState == WIFI_AP_STATE_FAILED) && (flag == DriverAction.DRIVER_UNLOAD)) {
+ mWifiStateTracker.unloadDriver();
+ }
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (wifiAPState == WIFI_AP_STATE_ENABLED) {
+ mBatteryStats.noteWifiOn(uid);
+ } else if (wifiAPState == WIFI_AP_STATE_DISABLED) {
+ mBatteryStats.noteWifiOff(uid);
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ // Update state
+ mWifiApState = wifiAPState;
+
+ // Broadcast
+ final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiAPState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
+ mContext.sendStickyBroadcast(intent);
}
/**
@@ -490,15 +808,15 @@ public class WifiService extends IWifiManager.Stub {
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();
- }
+ listStr = mWifiStateTracker.listNetworks();
+
List<WifiConfiguration> networks =
new ArrayList<WifiConfiguration>();
if (listStr == null)
@@ -522,11 +840,10 @@ public class WifiService extends IWifiManager.Stub {
config.status = WifiConfiguration.Status.DISABLED;
else
config.status = WifiConfiguration.Status.ENABLED;
- } else
+ } else {
config.status = WifiConfiguration.Status.ENABLED;
- synchronized (mWifiStateTracker) {
- readNetworkVariables(config);
}
+ readNetworkVariables(config);
networks.add(config);
}
@@ -540,7 +857,7 @@ public class WifiService extends IWifiManager.Stub {
* The caller must hold the synchronization monitor.
* @param config the {@link WifiConfiguration} object to be filled in.
*/
- private static void readNetworkVariables(WifiConfiguration config) {
+ private void readNetworkVariables(WifiConfiguration config) {
int netId = config.networkId;
if (netId < 0)
@@ -553,21 +870,21 @@ public class WifiService extends IWifiManager.Stub {
*/
String value;
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.ssidVarName);
if (!TextUtils.isEmpty(value)) {
- config.SSID = value;
+ config.SSID = removeDoubleQuotes(value);
} else {
config.SSID = null;
}
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.bssidVarName);
if (!TextUtils.isEmpty(value)) {
config.BSSID = value;
} else {
config.BSSID = null;
}
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.priorityVarName);
config.priority = -1;
if (!TextUtils.isEmpty(value)) {
try {
@@ -576,7 +893,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.hiddenSSIDVarName);
config.hiddenSSID = false;
if (!TextUtils.isEmpty(value)) {
try {
@@ -585,7 +902,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.wepTxKeyIdxVarName);
config.wepTxKeyIndex = -1;
if (!TextUtils.isEmpty(value)) {
try {
@@ -599,7 +916,7 @@ public class WifiService extends IWifiManager.Stub {
* 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]);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.wepKeyVarNames[i]);
if (!TextUtils.isEmpty(value)) {
config.wepKeys[i] = value;
} else {
@@ -611,14 +928,14 @@ public class WifiService extends IWifiManager.Stub {
* 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);
+ value = mWifiStateTracker.getNetworkVariable(netId, WifiConfiguration.pskVarName);
if (!TextUtils.isEmpty(value)) {
config.preSharedKey = value;
} else {
config.preSharedKey = null;
}
- value = WifiNative.getNetworkVariableCommand(config.networkId,
+ value = mWifiStateTracker.getNetworkVariable(config.networkId,
WifiConfiguration.Protocol.varName);
if (!TextUtils.isEmpty(value)) {
String vals[] = value.split(" ");
@@ -631,7 +948,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(config.networkId,
+ value = mWifiStateTracker.getNetworkVariable(config.networkId,
WifiConfiguration.KeyMgmt.varName);
if (!TextUtils.isEmpty(value)) {
String vals[] = value.split(" ");
@@ -644,7 +961,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(config.networkId,
+ value = mWifiStateTracker.getNetworkVariable(config.networkId,
WifiConfiguration.AuthAlgorithm.varName);
if (!TextUtils.isEmpty(value)) {
String vals[] = value.split(" ");
@@ -657,7 +974,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(config.networkId,
+ value = mWifiStateTracker.getNetworkVariable(config.networkId,
WifiConfiguration.PairwiseCipher.varName);
if (!TextUtils.isEmpty(value)) {
String vals[] = value.split(" ");
@@ -670,7 +987,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- value = WifiNative.getNetworkVariableCommand(config.networkId,
+ value = mWifiStateTracker.getNetworkVariable(config.networkId,
WifiConfiguration.GroupCipher.varName);
if (!TextUtils.isEmpty(value)) {
String vals[] = value.split(" ");
@@ -685,21 +1002,32 @@ public class WifiService extends IWifiManager.Stub {
for (WifiConfiguration.EnterpriseField field :
config.enterpriseFields) {
- value = WifiNative.getNetworkVariableCommand(netId,
+ value = mWifiStateTracker.getNetworkVariable(netId,
field.varName());
if (!TextUtils.isEmpty(value)) {
+ if (field != config.eap) value = removeDoubleQuotes(value);
field.setValue(value);
}
}
}
+ private static String removeDoubleQuotes(String string) {
+ if (string.length() <= 2) return "";
+ return string.substring(1, string.length() - 1);
+ }
+
+ private static String convertToQuotedString(String string) {
+ return "\"" + string + "\"";
+ }
+
/**
* 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) {
+ public int addOrUpdateNetwork(WifiConfiguration config) {
enforceChangePermission();
+
/*
* If the supplied networkId is -1, we create a new empty
* network configuration. Otherwise, the networkId should
@@ -707,57 +1035,47 @@ public class WifiService extends IWifiManager.Stub {
*/
int netId = config.networkId;
boolean newNetwork = netId == -1;
- boolean doReconfig;
- int currentPriority;
+ boolean doReconfig = false;
// 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) {
+ synchronized (mWifiStateTracker) {
+ if (newNetwork) {
+ netId = mWifiStateTracker.addNetwork();
+ if (netId < 0) {
+ if (DBG) {
+ Slog.d(TAG, "Failed to add a network!");
+ }
+ return -1;
}
+ doReconfig = true;
}
- doReconfig = currentPriority != config.priority;
+ mNeedReconfig = mNeedReconfig || doReconfig;
}
- mNeedReconfig = mNeedReconfig || doReconfig;
setVariables: {
/*
* Note that if a networkId for a non-existent network
- * was supplied, then the first setNetworkVariableCommand()
+ * was supplied, then the first setNetworkVariable()
* 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)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.ssidVarName,
+ convertToQuotedString(config.SSID))) {
if (DBG) {
- Log.d(TAG, "failed to set SSID: "+config.SSID);
+ Slog.d(TAG, "failed to set SSID: "+config.SSID);
}
break setVariables;
}
if (config.BSSID != null &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.bssidVarName,
- config.BSSID)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.bssidVarName,
+ config.BSSID)) {
if (DBG) {
- Log.d(TAG, "failed to set BSSID: "+config.BSSID);
+ Slog.d(TAG, "failed to set BSSID: "+config.BSSID);
}
break setVariables;
}
@@ -765,13 +1083,13 @@ public class WifiService extends IWifiManager.Stub {
String allowedKeyManagementString =
makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
if (config.allowedKeyManagement.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.KeyMgmt.varName,
- allowedKeyManagementString)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.KeyMgmt.varName,
+ allowedKeyManagementString)) {
if (DBG) {
- Log.d(TAG, "failed to set key_mgmt: "+
- allowedKeyManagementString);
+ Slog.d(TAG, "failed to set key_mgmt: "+
+ allowedKeyManagementString);
}
break setVariables;
}
@@ -779,13 +1097,13 @@ public class WifiService extends IWifiManager.Stub {
String allowedProtocolsString =
makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
if (config.allowedProtocols.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.Protocol.varName,
- allowedProtocolsString)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.Protocol.varName,
+ allowedProtocolsString)) {
if (DBG) {
- Log.d(TAG, "failed to set proto: "+
- allowedProtocolsString);
+ Slog.d(TAG, "failed to set proto: "+
+ allowedProtocolsString);
}
break setVariables;
}
@@ -793,13 +1111,13 @@ public class WifiService extends IWifiManager.Stub {
String allowedAuthAlgorithmsString =
makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
if (config.allowedAuthAlgorithms.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.AuthAlgorithm.varName,
- allowedAuthAlgorithmsString)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.AuthAlgorithm.varName,
+ allowedAuthAlgorithmsString)) {
if (DBG) {
- Log.d(TAG, "failed to set auth_alg: "+
- allowedAuthAlgorithmsString);
+ Slog.d(TAG, "failed to set auth_alg: "+
+ allowedAuthAlgorithmsString);
}
break setVariables;
}
@@ -807,13 +1125,13 @@ public class WifiService extends IWifiManager.Stub {
String allowedPairwiseCiphersString =
makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings);
if (config.allowedPairwiseCiphers.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.PairwiseCipher.varName,
- allowedPairwiseCiphersString)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.PairwiseCipher.varName,
+ allowedPairwiseCiphersString)) {
if (DBG) {
- Log.d(TAG, "failed to set pairwise: "+
- allowedPairwiseCiphersString);
+ Slog.d(TAG, "failed to set pairwise: "+
+ allowedPairwiseCiphersString);
}
break setVariables;
}
@@ -821,13 +1139,13 @@ public class WifiService extends IWifiManager.Stub {
String allowedGroupCiphersString =
makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
if (config.allowedGroupCiphers.cardinality() != 0 &&
- !WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.GroupCipher.varName,
- allowedGroupCiphersString)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.GroupCipher.varName,
+ allowedGroupCiphersString)) {
if (DBG) {
- Log.d(TAG, "failed to set group: "+
- allowedGroupCiphersString);
+ Slog.d(TAG, "failed to set group: "+
+ allowedGroupCiphersString);
}
break setVariables;
}
@@ -835,12 +1153,12 @@ public class WifiService extends IWifiManager.Stub {
// 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)) {
+ !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.pskVarName,
+ config.preSharedKey)) {
if (DBG) {
- Log.d(TAG, "failed to set psk: "+config.preSharedKey);
+ Slog.d(TAG, "failed to set psk: "+config.preSharedKey);
}
break setVariables;
}
@@ -851,14 +1169,14 @@ public class WifiService extends IWifiManager.Stub {
// 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 (!mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.wepKeyVarNames[i],
+ config.wepKeys[i])) {
if (DBG) {
- Log.d(TAG,
- "failed to set wep_key"+i+": " +
- config.wepKeys[i]);
+ Slog.d(TAG,
+ "failed to set wep_key"+i+": " +
+ config.wepKeys[i]);
}
break setVariables;
}
@@ -868,37 +1186,37 @@ public class WifiService extends IWifiManager.Stub {
}
if (hasSetKey) {
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.wepTxKeyIdxVarName,
- Integer.toString(config.wepTxKeyIndex))) {
+ if (!mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.wepTxKeyIdxVarName,
+ Integer.toString(config.wepTxKeyIndex))) {
if (DBG) {
- Log.d(TAG,
- "failed to set wep_tx_keyidx: "+
- config.wepTxKeyIndex);
+ Slog.d(TAG,
+ "failed to set wep_tx_keyidx: "+
+ config.wepTxKeyIndex);
}
break setVariables;
}
}
- if (!WifiNative.setNetworkVariableCommand(
- netId,
- WifiConfiguration.priorityVarName,
- Integer.toString(config.priority))) {
+ if (!mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.priorityVarName,
+ Integer.toString(config.priority))) {
if (DBG) {
- Log.d(TAG, config.SSID + ": failed to set priority: "
- +config.priority);
+ Slog.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 (config.hiddenSSID && !mWifiStateTracker.setNetworkVariable(
+ netId,
+ WifiConfiguration.hiddenSSIDVarName,
+ Integer.toString(config.hiddenSSID ? 1 : 0))) {
if (DBG) {
- Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
- config.hiddenSSID);
+ Slog.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
+ config.hiddenSSID);
}
break setVariables;
}
@@ -907,18 +1225,22 @@ public class WifiService extends IWifiManager.Stub {
: config.enterpriseFields) {
String varName = field.varName();
String value = field.value();
- if ((value != null) && !WifiNative.setNetworkVariableCommand(
- netId,
- varName,
- value)) {
- if (DBG) {
- Log.d(TAG, config.SSID + ": failed to set " + varName +
- ": " + value);
+ if (value != null) {
+ if (field != config.eap) {
+ value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
+ }
+ if (!mWifiStateTracker.setNetworkVariable(
+ netId,
+ varName,
+ value)) {
+ if (DBG) {
+ Slog.d(TAG, config.SSID + ": failed to set " + varName +
+ ": " + value);
+ }
+ break setVariables;
}
- break setVariables;
}
}
-
return netId;
}
@@ -931,9 +1253,9 @@ public class WifiService extends IWifiManager.Stub {
if (newNetwork) {
removeNetwork(netId);
if (DBG) {
- Log.d(TAG,
- "Failed to set a network variable, removed network: "
- + netId);
+ Slog.d(TAG,
+ "Failed to set a network variable, removed network: "
+ + netId);
}
}
return -1;
@@ -972,7 +1294,7 @@ public class WifiService extends IWifiManager.Stub {
// 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);
+ Slog.w(TAG, "Failed to look-up a string: " + string);
}
return -1;
@@ -1000,15 +1322,13 @@ public class WifiService extends IWifiManager.Stub {
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- String ifname = mWifiStateTracker.getInterfaceName();
- NetworkUtils.enableInterface(ifname);
- boolean result = WifiNative.enableNetworkCommand(netId, disableOthers);
- if (!result) {
- NetworkUtils.disableInterface(ifname);
- }
- return result;
+ String ifname = mWifiStateTracker.getInterfaceName();
+ NetworkUtils.enableInterface(ifname);
+ boolean result = mWifiStateTracker.enableNetwork(netId, disableOthers);
+ if (!result) {
+ NetworkUtils.disableInterface(ifname);
}
+ return result;
}
/**
@@ -1020,9 +1340,7 @@ public class WifiService extends IWifiManager.Stub {
public boolean disableNetwork(int netId) {
enforceChangePermission();
- synchronized (mWifiStateTracker) {
- return WifiNative.disableNetworkCommand(netId);
- }
+ return mWifiStateTracker.disableNetwork(netId);
}
/**
@@ -1046,9 +1364,8 @@ public class WifiService extends IWifiManager.Stub {
public List<ScanResult> getScanResults() {
enforceAccessPermission();
String reply;
- synchronized (mWifiStateTracker) {
- reply = WifiNative.scanResultsCommand();
- }
+
+ reply = mWifiStateTracker.scanResults();
if (reply == null) {
return null;
}
@@ -1076,7 +1393,7 @@ public class WifiService extends IWifiManager.Stub {
if (scanResult != null) {
scanList.add(scanResult);
} else if (DBG) {
- Log.w(TAG, "misformatted scan result for: " + line);
+ Slog.w(TAG, "misformatted scan result for: " + line);
}
}
lineBeg = lineEnd + 1;
@@ -1163,7 +1480,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
} else {
- Log.w(TAG, "Misformatted scan result text with " +
+ Slog.w(TAG, "Misformatted scan result text with " +
result.length + " fields: " + line);
}
}
@@ -1196,11 +1513,12 @@ public class WifiService extends IWifiManager.Stub {
public boolean saveConfiguration() {
boolean result;
enforceChangePermission();
+
synchronized (mWifiStateTracker) {
- result = WifiNative.saveConfigCommand();
+ result = mWifiStateTracker.saveConfig();
if (result && mNeedReconfig) {
mNeedReconfig = false;
- result = WifiNative.reloadConfigCommand();
+ result = mWifiStateTracker.reloadConfig();
if (result) {
Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION);
@@ -1234,9 +1552,10 @@ public class WifiService extends IWifiManager.Stub {
* {@code numChannels} is outside the valid range.
*/
public boolean setNumAllowedChannels(int numChannels, boolean persist) {
- Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
+ Slog.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
" with persist set to "+persist);
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
@@ -1254,13 +1573,28 @@ public class WifiService extends IWifiManager.Stub {
return false;
}
+ if (mWifiHandler == null) return false;
+
+ Message.obtain(mWifiHandler,
+ MESSAGE_SET_CHANNELS, numChannels, (persist ? 1 : 0)).sendToTarget();
+
+ return true;
+ }
+
+ /**
+ * sets the number of allowed radio frequency channels synchronously
+ * @param numChannels the number of allowed channels. Must be greater than 0
+ * and less than or equal to 16.
+ * @param persist {@code true} if the setting should be remembered.
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ private boolean setNumAllowedChannelsBlocking(int numChannels, boolean persist) {
if (persist) {
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
- numChannels);
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ numChannels);
}
- mWifiStateTracker.setNumAllowedChannels(numChannels);
- return true;
+ return mWifiStateTracker.setNumAllowedChannels(numChannels);
}
/**
@@ -1272,18 +1606,17 @@ public class WifiService extends IWifiManager.Stub {
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);
- }
+
+ /*
+ * 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 = mWifiStateTracker.getNumAllowedChannels();
+ if (numChannels < 0) {
+ numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ -1);
}
return numChannels;
}
@@ -1313,19 +1646,20 @@ public class WifiService extends IWifiManager.Stub {
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);
+ long idleMillis =
+ Settings.Secure.getLong(mContext.getContentResolver(),
+ Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
int stayAwakeConditions =
- Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
+ Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
if (action.equals(Intent.ACTION_SCREEN_ON)) {
- Log.d(TAG, "ACTION_SCREEN_ON");
+ Slog.d(TAG, "ACTION_SCREEN_ON");
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
mWifiStateTracker.enableRssiPolling(true);
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- Log.d(TAG, "ACTION_SCREEN_OFF");
+ Slog.d(TAG, "ACTION_SCREEN_OFF");
mScreenOff = true;
mWifiStateTracker.enableRssiPolling(false);
/*
@@ -1342,21 +1676,21 @@ public class WifiService extends IWifiManager.Stub {
// as long as we would if connected (below)
// TODO - fix the race conditions and switch back to the immediate turn-off
long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
- Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
+ Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
// // do not keep Wifi awake when screen is off if Wifi is not associated
// mDeviceIdle = true;
// updateWifiState();
} else {
long triggerTime = System.currentTimeMillis() + idleMillis;
- Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
+ Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
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)) {
- Log.d(TAG, "got ACTION_DEVICE_IDLE");
+ Slog.d(TAG, "got ACTION_DEVICE_IDLE");
mDeviceIdle = true;
} else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
/*
@@ -1367,11 +1701,11 @@ public class WifiService extends IWifiManager.Stub {
* the already-set timer.
*/
int pluggedType = intent.getIntExtra("plugged", 0);
- Log.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
+ Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
!shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
long triggerTime = System.currentTimeMillis() + idleMillis;
- Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
+ Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
mPluggedType = pluggedType;
return;
@@ -1449,7 +1783,18 @@ public class WifiService extends IWifiManager.Stub {
Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
}
+ private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) {
+ Message.obtain(mWifiHandler,
+ (enable ? MESSAGE_START_ACCESS_POINT : MESSAGE_STOP_ACCESS_POINT),
+ uid, 0, wifiConfig).sendToTarget();
+ }
+
private void updateWifiState() {
+ // send a message so it's all serialized
+ Message.obtain(mWifiHandler, MESSAGE_UPDATE_STATE, 0, 0).sendToTarget();
+ }
+
+ private void doUpdateWifiState() {
boolean wifiEnabled = getPersistedWifiEnabled();
boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
boolean lockHeld = mLocks.hasLocks();
@@ -1463,29 +1808,33 @@ public class WifiService extends IWifiManager.Stub {
}
synchronized (mWifiHandler) {
- if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) {
+ if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLING) && !airplaneMode) {
return;
}
+
+ /* Disable tethering when airplane mode is enabled */
+ if (airplaneMode &&
+ (mWifiApState == WIFI_AP_STATE_ENABLING || mWifiApState == WIFI_AP_STATE_ENABLED)) {
+ sWakeLock.acquire();
+ sendAccessPointMessage(false, null, mLastApEnableUid);
+ }
+
if (wifiShouldBeEnabled) {
if (wifiShouldBeStarted) {
sWakeLock.acquire();
sendEnableMessage(true, false, mLastEnableUid);
sWakeLock.acquire();
sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
- } else {
+ } else if (!mWifiStateTracker.isDriverStopped()) {
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.
+ * We are assuming that ConnectivityService can make
+ * a transition to cellular data within wakeLockTimeout time.
+ * The wakelock is released by the delayed message.
*/
sDriverStopWakeLock.acquire();
mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
@@ -1546,6 +1895,9 @@ public class WifiService extends IWifiManager.Stub {
case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
+ if (mWifiWatchdogService == null) {
+ mWifiWatchdogService = new WifiWatchdogService(mContext, mWifiStateTracker);
+ }
sWakeLock.release();
break;
@@ -1555,10 +1907,15 @@ public class WifiService extends IWifiManager.Stub {
sWakeLock.release();
break;
+ case MESSAGE_UPDATE_STATE:
+ doUpdateWifiState();
+ break;
+
case MESSAGE_DISABLE_WIFI:
// a non-zero msg.arg1 value means the "enabled" setting
// should be persisted
setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
+ mWifiWatchdogService = null;
sWakeLock.release();
break;
@@ -1568,12 +1925,27 @@ public class WifiService extends IWifiManager.Stub {
break;
case MESSAGE_RELEASE_WAKELOCK:
- synchronized (sDriverStopWakeLock) {
- if (sDriverStopWakeLock.isHeld()) {
- sDriverStopWakeLock.release();
- }
- }
+ sDriverStopWakeLock.release();
break;
+
+ case MESSAGE_START_ACCESS_POINT:
+ setWifiApEnabledBlocking(true,
+ msg.arg1,
+ (WifiConfiguration) msg.obj);
+ sWakeLock.release();
+ break;
+
+ case MESSAGE_STOP_ACCESS_POINT:
+ setWifiApEnabledBlocking(false,
+ msg.arg1,
+ (WifiConfiguration) msg.obj);
+ sWakeLock.release();
+ break;
+
+ case MESSAGE_SET_CHANNELS:
+ setNumAllowedChannelsBlocking(msg.arg1, msg.arg2 == 1);
+ break;
+
}
}
}
@@ -1587,7 +1959,7 @@ public class WifiService extends IWifiManager.Stub {
+ ", uid=" + Binder.getCallingUid());
return;
}
- pw.println("Wi-Fi is " + stateName(mWifiState));
+ pw.println("Wi-Fi is " + stateName(mWifiStateTracker.getWifiState()));
pw.println("Stay-awake conditions: " +
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
@@ -1720,7 +2092,7 @@ public class WifiService extends IWifiManager.Stub {
}
private boolean acquireWifiLockLocked(WifiLock wifiLock) {
- Log.d(TAG, "acquireWifiLockLocked: " + wifiLock);
+ Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
mLocks.addLock(wifiLock);
@@ -1758,7 +2130,7 @@ public class WifiService extends IWifiManager.Stub {
WifiLock wifiLock = mLocks.removeLock(lock);
- Log.d(TAG, "releaseWifiLockLocked: " + wifiLock);
+ Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
hadLock = (wifiLock != null);
@@ -1815,7 +2187,7 @@ public class WifiService extends IWifiManager.Stub {
}
public void binderDied() {
- Log.e(TAG, "Multicaster binderDied");
+ Slog.e(TAG, "Multicaster binderDied");
synchronized (mMulticasters) {
int i = mMulticasters.indexOf(this);
if (i != -1) {
@@ -1833,6 +2205,19 @@ public class WifiService extends IWifiManager.Stub {
}
}
+ public void initializeMulticastFiltering() {
+ enforceMulticastChangePermission();
+
+ synchronized (mMulticasters) {
+ // if anybody had requested filters be off, leave off
+ if (mMulticasters.size() != 0) {
+ return;
+ } else {
+ mWifiStateTracker.startPacketFiltering();
+ }
+ }
+ }
+
public void acquireMulticastLock(IBinder binder, String tag) {
enforceMulticastChangePermission();
@@ -1843,9 +2228,7 @@ public class WifiService extends IWifiManager.Stub {
// our new size == 1 (first call), but this function won't
// be called often and by making the stopPacket call each
// time we're less fragile and self-healing.
- synchronized (mWifiStateTracker) {
- WifiNative.stopPacketFiltering();
- }
+ mWifiStateTracker.stopPacketFiltering();
}
int uid = Binder.getCallingUid();
@@ -1877,13 +2260,12 @@ public class WifiService extends IWifiManager.Stub {
private void removeMulticasterLocked(int i, int uid)
{
Multicaster removed = mMulticasters.remove(i);
+
if (removed != null) {
removed.unlinkDeathRecipient();
}
if (mMulticasters.size() == 0) {
- synchronized (mWifiStateTracker) {
- WifiNative.startPacketFiltering();
- }
+ mWifiStateTracker.startPacketFiltering();
}
Long ident = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index 9443a95..87f8a6e 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -34,7 +34,7 @@ import android.os.Message;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Config;
-import android.util.Log;
+import android.util.Slog;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -89,6 +89,8 @@ public class WifiWatchdogService {
*/
private WifiWatchdogHandler mHandler;
+ private ContentObserver mContentObserver;
+
/**
* The current watchdog state. Only written from the main thread!
*/
@@ -132,7 +134,7 @@ public class WifiWatchdogService {
ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false,
- new ContentObserver(mHandler) {
+ mContentObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
if (isWatchdogEnabled()) {
@@ -249,7 +251,6 @@ public class WifiWatchdogService {
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);
}
@@ -272,6 +273,16 @@ public class WifiWatchdogService {
}
/**
+ * Unregister broadcasts and quit the watchdog thread
+ */
+ private void quit() {
+ unregisterForWifiBroadcasts();
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ mHandler.removeAllActions();
+ mHandler.getLooper().quit();
+ }
+
+ /**
* Waits for the main watchdog thread to create the handler.
*/
private void waitForHandlerCreation() {
@@ -281,7 +292,7 @@ public class WifiWatchdogService {
// Wait for the handler to be set by the other thread
wait();
} catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting on handler.");
+ Slog.e(TAG, "Interrupted while waiting on handler.");
}
}
}
@@ -293,11 +304,11 @@ public class WifiWatchdogService {
* Logs with the current thread.
*/
private static void myLogV(String message) {
- Log.v(TAG, "(" + Thread.currentThread().getName() + ") " + message);
+ Slog.v(TAG, "(" + Thread.currentThread().getName() + ") " + message);
}
private static void myLogD(String message) {
- Log.d(TAG, "(" + Thread.currentThread().getName() + ") " + message);
+ Slog.d(TAG, "(" + Thread.currentThread().getName() + ") " + message);
}
/**
@@ -364,7 +375,7 @@ public class WifiWatchdogService {
}
if (V) {
- Log.v(TAG, (dnsAlive ? " +" : " Ignored: -"));
+ Slog.v(TAG, (dnsAlive ? " +" : " Ignored: -"));
}
if (shouldCancel()) return false;
@@ -372,7 +383,7 @@ public class WifiWatchdogService {
try {
Thread.sleep(pingDelay);
} catch (InterruptedException e) {
- Log.w(TAG, "Interrupted while pausing between pings", e);
+ Slog.w(TAG, "Interrupted while pausing between pings", e);
}
}
@@ -383,11 +394,11 @@ public class WifiWatchdogService {
if (DnsPinger.isDnsReachable(dns, getPingTimeoutMs())) {
successCounter++;
if (V) {
- Log.v(TAG, " +");
+ Slog.v(TAG, " +");
}
} else {
if (V) {
- Log.v(TAG, " -");
+ Slog.v(TAG, " -");
}
}
@@ -396,13 +407,13 @@ public class WifiWatchdogService {
try {
Thread.sleep(pingDelay);
} catch (InterruptedException e) {
- Log.w(TAG, "Interrupted while pausing between pings", e);
+ Slog.w(TAG, "Interrupted while pausing between pings", e);
}
}
int packetLossPercentage = 100 * (numPings - successCounter) / numPings;
if (D) {
- Log.d(TAG, packetLossPercentage
+ Slog.d(TAG, packetLossPercentage
+ "% packet loss (acceptable is " + acceptableLoss + "%)");
}
@@ -544,7 +555,7 @@ public class WifiWatchdogService {
if (ssid == null) {
// It's still null, give up
if (V) {
- Log.v(TAG, " Invalid SSID, returning false");
+ Slog.v(TAG, " Invalid SSID, returning false");
}
return false;
}
@@ -559,7 +570,7 @@ public class WifiWatchdogService {
if (TextUtils.isEmpty(bssid)) {
// It's still null, give up
if (V) {
- Log.v(TAG, " Invalid BSSID, returning false");
+ Slog.v(TAG, " Invalid BSSID, returning false");
}
return false;
}
@@ -567,7 +578,7 @@ public class WifiWatchdogService {
if (!isOnWatchList(ssid)) {
if (V) {
- Log.v(TAG, " SSID not on watch list, returning false");
+ Slog.v(TAG, " SSID not on watch list, returning false");
}
return false;
}
@@ -667,7 +678,7 @@ public class WifiWatchdogService {
// Make sure we are not sleeping
if (mState == WatchdogState.SLEEP) {
if (V) {
- Log.v(TAG, " Sleeping (in " + mSsid + "), so returning");
+ Slog.v(TAG, " Sleeping (in " + mSsid + "), so returning");
}
return;
}
@@ -681,7 +692,7 @@ public class WifiWatchdogService {
mNumApsChecked++;
if (mNumApsChecked > getMaxApChecks()) {
if (V) {
- Log.v(TAG, " Passed the max attempts (" + getMaxApChecks()
+ Slog.v(TAG, " Passed the max attempts (" + getMaxApChecks()
+ "), going to sleep for " + mSsid);
}
mHandler.sleep(mSsid);
@@ -692,7 +703,7 @@ public class WifiWatchdogService {
boolean isApAlive = checkDnsConnectivity();
if (V) {
- Log.v(TAG, " Is it alive: " + isApAlive);
+ Slog.v(TAG, " Is it alive: " + isApAlive);
}
// Take action based on results
@@ -739,6 +750,8 @@ public class WifiWatchdogService {
// Black list this "bad" AP, this will cause an attempt to connect to another
blacklistAp(ap.bssid);
+ // Initiate an association to an alternate AP
+ mWifiStateTracker.reassociate();
}
private void blacklistAp(String bssid) {
@@ -751,7 +764,7 @@ public class WifiWatchdogService {
if (!mWifiStateTracker.addToBlacklist(bssid)) {
// There's a known bug where this method returns failure on success
- //Log.e(TAG, "Blacklisting " + bssid + " failed");
+ //Slog.e(TAG, "Blacklisting " + bssid + " failed");
}
if (D) {
@@ -778,7 +791,7 @@ public class WifiWatchdogService {
// Make sure we are not sleeping
if (mState == WatchdogState.SLEEP) {
if (V) {
- Log.v(TAG, " handleBackgroundCheckAp: Sleeping (in " + mSsid + "), so returning");
+ Slog.v(TAG, " handleBackgroundCheckAp: Sleeping (in " + mSsid + "), so returning");
}
return;
}
@@ -805,7 +818,7 @@ public class WifiWatchdogService {
boolean isApAlive = backgroundCheckDnsConnectivity();
if (V && !isApAlive) {
- Log.v(TAG, " handleBackgroundCheckAp: Is it alive: " + isApAlive);
+ Slog.v(TAG, " handleBackgroundCheckAp: Is it alive: " + isApAlive);
}
if (shouldCancel()) {
@@ -849,7 +862,7 @@ public class WifiWatchdogService {
*/
if (!mWifiStateTracker.clearBlacklist()) {
// There's a known bug where this method returns failure on success
- //Log.e(TAG, "Clearing blacklist failed");
+ //Slog.e(TAG, "Clearing blacklist failed");
}
if (V) {
@@ -893,7 +906,7 @@ public class WifiWatchdogService {
// If we're sleeping, don't do anything
if (mState == WatchdogState.SLEEP) {
- Log.v(TAG, " Sleeping (in " + mSsid + "), so returning");
+ Slog.v(TAG, " Sleeping (in " + mSsid + "), so returning");
return;
}
@@ -901,7 +914,7 @@ public class WifiWatchdogService {
setIdleState(false);
if (V) {
- Log.v(TAG, " Set state to IDLE");
+ Slog.v(TAG, " Set state to IDLE");
}
}
@@ -1103,9 +1116,6 @@ public class WifiWatchdogService {
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));
@@ -1139,15 +1149,9 @@ public class WifiWatchdogService {
}
}
- private void handleSupplicantConnectionChanged(boolean connected) {
- if (!connected) {
- onDisconnected();
- }
- }
-
private void handleWifiStateChanged(int wifiState) {
if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
- onDisconnected();
+ quit();
} else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
onEnabled();
}
@@ -1243,13 +1247,13 @@ public class WifiWatchdogService {
} catch (SocketException e) {
if (V) {
- Log.v(TAG, "DnsPinger.isReachable received SocketException", e);
+ Slog.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);
+ Slog.v(TAG, "DnsPinger.isReachable is unable to resolve the DNS host", e);
}
return false;
@@ -1258,13 +1262,13 @@ public class WifiWatchdogService {
} catch (IOException e) {
if (V) {
- Log.v(TAG, "DnsPinger.isReachable got an IOException", e);
+ Slog.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);
+ Slog.d(TAG, "DnsPinger.isReachable got an unknown exception", e);
}
return false;
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d209cfa..205e308 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -43,9 +43,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.policy.impl.PhoneWindowManager;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
+import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.KeyInputQueue.QueuedEvent;
import com.android.server.am.BatteryStatsService;
@@ -84,7 +86,7 @@ import android.os.TokenWatcher;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.Gravity;
@@ -134,16 +136,19 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
+ static final boolean DEBUG_RESIZE = 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_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
+ static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
+ static final boolean DEBUG_FREEZE = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;
@@ -153,8 +158,6 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean BLUR = true;
static final boolean localLOGV = DEBUG;
- static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
-
/** How long to wait for subsequent key repeats, in milliseconds */
static final int KEY_REPEAT_DELAY = 50;
@@ -194,7 +197,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final int INJECT_FAILED = 0;
static final int INJECT_SUCCEEDED = 1;
static final int INJECT_NO_PERMISSION = -1;
-
+
static final int UPDATE_FOCUS_NORMAL = 0;
static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
@@ -310,13 +313,13 @@ public class WindowManagerService extends IWindowManager.Stub
* animation. It will be used for the next exit animation.
*/
AppWindowToken mLastEnterAnimToken;
-
+
/**
* These were the layout params used to retrieve the last enter animation.
* They will be used for the next exit animation.
*/
LayoutParams mLastEnterAnimParams;
-
+
/**
* Z-ordered (bottom-most first) list of all Window objects.
*/
@@ -365,6 +368,8 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mSafeMode;
boolean mDisplayEnabled = false;
boolean mSystemBooted = false;
+ int mInitialDisplayWidth = 0;
+ int mInitialDisplayHeight = 0;
int mRotation = 0;
int mRequestedRotation = 0;
int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -375,10 +380,18 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mLayoutNeeded = true;
boolean mAnimationPending = false;
boolean mDisplayFrozen = false;
+ boolean mWaitingForConfig = false;
boolean mWindowsFreezingScreen = false;
long mFreezeGcPending = 0;
int mAppsFreezingScreen = 0;
+ int mLayoutSeq = 0;
+
+ // State while inside of layoutAndPlaceSurfacesLocked().
+ boolean mFocusMayChange;
+
+ Configuration mCurConfiguration = new Configuration();
+
// 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.
@@ -423,7 +436,7 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
-
+
// If non-null, this is the currently visible window that is associated
// with the wallpaper.
WindowState mWallpaperTarget = null;
@@ -448,7 +461,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final long WALLPAPER_TIMEOUT = 150;
// Time we wait after a timeout before trying to wait again.
static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
-
+
AppWindowToken mFocusedApp = null;
PowerManagerService mPowerManager;
@@ -464,7 +477,7 @@ public class WindowManagerService extends IWindowManager.Stub
Session mHoldingScreenOn;
boolean mTurnOnScreen;
-
+
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -551,8 +564,10 @@ public class WindowManagerService extends IWindowManager.Stub
public void run() {
Looper.prepare();
+ WindowManagerPolicyThread.set(this, Looper.myLooper());
+
//Looper.myLooper().setMessageLogging(new LogPrinter(
- // Log.VERBOSE, "WindowManagerPolicy"));
+ // Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
mPolicy.init(mContext, mService, mPM);
@@ -571,7 +586,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (MEASURE_LATENCY) {
lt = new LatencyTimer(100, 1000);
}
-
+
mContext = context;
mHaveInputMethods = haveInputMethods;
mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -635,7 +650,7 @@ public class WindowManagerService extends IWindowManager.Stub
// The window manager only throws security exceptions, so let's
// log all others.
if (!(e instanceof SecurityException)) {
- Log.e(TAG, "Window Manager Crash", e);
+ Slog.e(TAG, "Window Manager Crash", e);
}
throw e;
}
@@ -643,7 +658,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void placeWindowAfter(Object pos, WindowState window) {
final int i = mWindows.indexOf(pos);
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding window " + window + " at "
+ (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
mWindows.add(i+1, window);
@@ -651,7 +666,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void placeWindowBefore(Object pos, WindowState window) {
final int i = mWindows.indexOf(pos);
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding window " + window + " at "
+ i + " of " + mWindows.size() + " (before " + pos + ")");
mWindows.add(i, window);
@@ -708,7 +723,7 @@ public class WindowManagerService extends IWindowManager.Stub
//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.
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding window " + win + " at "
+ (newIdx+1) + " of " + N);
localmWindows.add(newIdx+1, win);
@@ -716,7 +731,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
} else {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Figuring out where to add app window "
+ client.asBinder() + " (token=" + token + ")");
// Figure out where the window should go, based on the
@@ -729,7 +744,7 @@ public class WindowManagerService extends IWindowManager.Stub
i--;
break;
}
-
+
// We haven't reached the token yet; if this token
// is not going to the bottom and has windows, we can
// use it as an anchor for when we do reach the token.
@@ -790,7 +805,7 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
}
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding window " + win + " at "
+ i + " of " + N);
localmWindows.add(i, win);
@@ -807,7 +822,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
if (i < 0) i = 0;
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding window " + win + " at "
+ i + " of " + N);
localmWindows.add(i, win);
@@ -891,10 +906,10 @@ public class WindowManagerService extends IWindowManager.Stub
i--;
w = (WindowState)localmWindows.get(i);
- //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
+ //Slog.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
// + Integer.toHexString(w.mAttrs.flags));
if (canBeImeTarget(w)) {
- //Log.i(TAG, "Putting input method here!");
+ //Slog.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
@@ -916,7 +931,7 @@ public class WindowManagerService extends IWindowManager.Stub
mUpcomingInputMethodTarget = w;
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target="
+ w + " willMove=" + willMove);
if (willMove && w != null) {
@@ -950,7 +965,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (highestTarget != null) {
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG, "mNextAppTransition="
+ mNextAppTransition + " " + highestTarget
+ " animating=" + highestTarget.isAnimating()
+ " layer=" + highestTarget.mAnimLayer
@@ -975,13 +990,18 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- //Log.i(TAG, "Placing input method @" + (i+1));
+ //Slog.i(TAG, "Placing input method @" + (i+1));
if (w != null) {
if (willMove) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
- + mInputMethodTarget + " to " + w, e);
+ if (DEBUG_INPUT_METHOD) {
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.w(TAG, "Moving IM target from "
+ + mInputMethodTarget + " to " + w, e);
+ }
mInputMethodTarget = w;
if (w.mAppToken != null) {
setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
@@ -992,10 +1012,15 @@ public class WindowManagerService extends IWindowManager.Stub
return i+1;
}
if (willMove) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
- + mInputMethodTarget + " to null", e);
+ if (DEBUG_INPUT_METHOD) {
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.w(TAG, "Moving IM target from "
+ + mInputMethodTarget + " to null", e);
+ }
mInputMethodTarget = null;
setInputMethodAnimLayerAdjustment(0);
}
@@ -1006,7 +1031,7 @@ public class WindowManagerService extends IWindowManager.Stub
int pos = findDesiredInputMethodWindowIndexLocked(true);
if (pos >= 0) {
win.mTargetAppToken = mInputMethodTarget.mAppToken;
- if (DEBUG_WINDOW_MOVEMENT) Log.v(
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(
TAG, "Adding input method window " + win + " at " + pos);
mWindows.add(pos, win);
moveInputMethodDialogsLocked(pos+1);
@@ -1018,19 +1043,19 @@ public class WindowManagerService extends IWindowManager.Stub
}
void setInputMethodAnimLayerAdjustment(int adj) {
- if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
+ if (DEBUG_LAYERS) Slog.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
+ if (DEBUG_LAYERS) Slog.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
+ if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + cw
+ " anim layer: " + cw.mAnimLayer);
}
}
@@ -1039,7 +1064,7 @@ public class WindowManagerService extends IWindowManager.Stub
di --;
imw = mInputMethodDialogs.get(di);
imw.mAnimLayer = imw.mLayer + adj;
- if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
+ if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw
+ " anim layer: " + imw.mAnimLayer);
}
}
@@ -1048,7 +1073,7 @@ public class WindowManagerService extends IWindowManager.Stub
int wpos = mWindows.indexOf(win);
if (wpos >= 0) {
if (wpos < interestingPos) interestingPos--;
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing at " + wpos + ": " + win);
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing at " + wpos + ": " + win);
mWindows.remove(wpos);
int NC = win.mChildWindows.size();
while (NC > 0) {
@@ -1057,7 +1082,7 @@ public class WindowManagerService extends IWindowManager.Stub
int cpos = mWindows.indexOf(cw);
if (cpos >= 0) {
if (cpos < interestingPos) interestingPos--;
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing child at "
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing child at "
+ cpos + ": " + cw);
mWindows.remove(cpos);
}
@@ -1073,7 +1098,7 @@ public class WindowManagerService extends IWindowManager.Stub
// this case should be rare, so it shouldn't be that big a deal.
int wpos = mWindows.indexOf(win);
if (wpos >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "ReAdd removing from " + wpos
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "ReAdd removing from " + wpos
+ ": " + win);
mWindows.remove(wpos);
reAddWindowLocked(wpos, win);
@@ -1084,7 +1109,7 @@ public class WindowManagerService extends IWindowManager.Stub
int N = mWindows.size();
while (N > 0) {
N--;
- Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
+ Slog.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
}
}
@@ -1092,12 +1117,12 @@ public class WindowManagerService extends IWindowManager.Stub
ArrayList<WindowState> dialogs = mInputMethodDialogs;
final int N = dialogs.size();
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
+ if (DEBUG_INPUT_METHOD) Slog.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);
+ Slog.v(TAG, "Window list w/pos=" + pos);
logWindowList(" ");
}
@@ -1109,14 +1134,14 @@ public class WindowManagerService extends IWindowManager.Stub
pos++;
}
}
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
+ if (DEBUG_INPUT_METHOD) Slog.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:");
+ Slog.v(TAG, "Final window list:");
logWindowList(" ");
}
return;
@@ -1126,7 +1151,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.mTargetAppToken = null;
reAddWindowToListInOrderLocked(win);
if (DEBUG_INPUT_METHOD) {
- Log.v(TAG, "No IM target, final list:");
+ Slog.v(TAG, "No IM target, final list:");
logWindowList(" ");
}
}
@@ -1185,18 +1210,18 @@ public class WindowManagerService extends IWindowManager.Stub
if (imWin != null) {
if (DEBUG_INPUT_METHOD) {
- Log.v(TAG, "Moving IM from " + imPos);
+ Slog.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 + ":");
+ Slog.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 + ":");
+ Slog.v(TAG, "List after moving IM to " + imPos + ":");
logWindowList(" ");
}
if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
@@ -1209,12 +1234,12 @@ public class WindowManagerService extends IWindowManager.Stub
// because they aren't currently associated with a focus window.
if (imWin != null) {
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
+ if (DEBUG_INPUT_METHOD) Slog.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:");
+ Slog.v(TAG, "List with no IM target:");
logWindowList(" ");
}
if (DN > 0) moveInputMethodDialogsLocked(-1);;
@@ -1236,7 +1261,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final boolean isWallpaperVisible(WindowState wallpaperTarget) {
- if (DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper vis: target obscured="
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target obscured="
+ (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
+ " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
? wallpaperTarget.mAppToken.animation : null)
@@ -1248,16 +1273,16 @@ public class WindowManagerService extends IWindowManager.Stub
|| mUpperWallpaperTarget != null
|| mLowerWallpaperTarget != null;
}
-
+
static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
-
+
int adjustWallpaperWindowsLocked() {
int changed = 0;
-
+
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
-
+
// First find top-most window that has asked to be on top of the
// wallpaper; all wallpapers go behind it.
final ArrayList localmWindows = mWindows;
@@ -1283,19 +1308,19 @@ public class WindowManagerService extends IWindowManager.Stub
// If this window's app token is hidden and not animating,
// it is of no interest to us.
if (w.mAppToken.hidden && w.mAppToken.animation == null) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Skipping hidden or animating token: " + w);
topCurW = null;
continue;
}
}
- if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay="
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": readyfordisplay="
+ w.isReadyForDisplay() + " drawpending=" + w.mDrawPending
+ " commitdrawpending=" + w.mCommitDrawPending);
if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
&& (mWallpaperTarget == w
|| (!w.mDrawPending && !w.mCommitDrawPending))) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Found wallpaper activity: #" + i + "=" + w);
foundW = w;
foundI = i;
@@ -1305,7 +1330,7 @@ public class WindowManagerService extends IWindowManager.Stub
// The current wallpaper target is animating, so we'll
// look behind it for another possible target and figure
// out what is going on below.
- if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w
+ ": token animating, looking behind.");
continue;
}
@@ -1323,29 +1348,29 @@ public class WindowManagerService extends IWindowManager.Stub
// enough (we'll just wait until whatever transition is pending
// executes).
if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper not changing: waiting for app anim in current target");
return 0;
}
if (foundW != null && foundW.mAppToken != null) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper not changing: waiting for app anim in found target");
return 0;
}
}
-
+
if (mWallpaperTarget != foundW) {
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "New wallpaper target: " + foundW
+ Slog.v(TAG, "New wallpaper target: " + foundW
+ " oldTarget: " + mWallpaperTarget);
}
-
+
mLowerWallpaperTarget = null;
mUpperWallpaperTarget = null;
-
+
WindowState oldW = mWallpaperTarget;
mWallpaperTarget = foundW;
-
+
// Now what is happening... if the current and new targets are
// animating, then we are in our super special mode!
if (foundW != null && oldW != null) {
@@ -1354,36 +1379,36 @@ public class WindowManagerService extends IWindowManager.Stub
boolean foundAnim = foundW.mAnimation != null
|| (foundW.mAppToken != null && foundW.mAppToken.animation != null);
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "New animation: " + foundAnim
+ Slog.v(TAG, "New animation: " + foundAnim
+ " old animation: " + oldAnim);
}
if (foundAnim && oldAnim) {
int oldI = localmWindows.indexOf(oldW);
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "New i: " + foundI + " old i: " + oldI);
+ Slog.v(TAG, "New i: " + foundI + " old i: " + oldI);
}
if (oldI >= 0) {
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "Animating wallpapers: old#" + oldI
+ Slog.v(TAG, "Animating wallpapers: old#" + oldI
+ "=" + oldW + "; new#" + foundI
+ "=" + foundW);
}
-
+
// Set the new target correctly.
if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) {
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "Old wallpaper still the target.");
+ Slog.v(TAG, "Old wallpaper still the target.");
}
mWallpaperTarget = oldW;
}
-
+
// Now set the upper and lower wallpaper targets
// correctly, and make sure that we are positioning
// the wallpaper below the lower.
if (foundI > oldI) {
// The new target is on top of the old one.
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "Found target above old target.");
+ Slog.v(TAG, "Found target above old target.");
}
mUpperWallpaperTarget = foundW;
mLowerWallpaperTarget = oldW;
@@ -1392,7 +1417,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
// The new target is below the old one.
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "Found target below old target.");
+ Slog.v(TAG, "Found target below old target.");
}
mUpperWallpaperTarget = oldW;
mLowerWallpaperTarget = foundW;
@@ -1400,7 +1425,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
} else if (mLowerWallpaperTarget != null) {
// Is it time to stop animating?
boolean lowerAnimating = mLowerWallpaperTarget.mAnimation != null
@@ -1411,31 +1436,31 @@ public class WindowManagerService extends IWindowManager.Stub
&& mUpperWallpaperTarget.mAppToken.animation != null);
if (!lowerAnimating || !upperAnimating) {
if (DEBUG_WALLPAPER) {
- Log.v(TAG, "No longer animating wallpaper targets!");
+ Slog.v(TAG, "No longer animating wallpaper targets!");
}
mLowerWallpaperTarget = null;
mUpperWallpaperTarget = null;
}
}
-
+
boolean visible = foundW != null;
if (visible) {
// The window is visible to the compositor... but is it visible
// to the user? That is what the wallpaper cares about.
visible = isWallpaperVisible(foundW);
- if (DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper visibility: " + visible);
-
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
+
// If the wallpaper target is animating, we may need to copy
// its layer adjustment. Only do this if we are not transfering
// between two wallpaper targets.
mWallpaperAnimLayerAdjustment =
(mLowerWallpaperTarget == null && foundW.mAppToken != null)
? foundW.mAppToken.animLayerAdjustment : 0;
-
+
final int maxLayer = mPolicy.getMaxWallpaperLayer()
* TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
-
+
// Now w is the window we are supposed to be behind... but we
// need to be sure to also be behind any of its attached windows,
// AND any starting window associated with it, AND below the
@@ -1454,9 +1479,9 @@ public class WindowManagerService extends IWindowManager.Stub
foundI--;
}
} else {
- if (DEBUG_WALLPAPER) Log.v(TAG, "No wallpaper target");
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
}
-
+
if (foundW == null && topCurW != null) {
// There is no wallpaper target, so it goes at the bottom.
// We will assume it is the same place as last time, if known.
@@ -1467,7 +1492,7 @@ public class WindowManagerService extends IWindowManager.Stub
// what is below it for later.
foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
}
-
+
if (visible) {
if (mWallpaperTarget.mWallpaperX >= 0) {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
@@ -1478,7 +1503,7 @@ public class WindowManagerService extends IWindowManager.Stub
mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
}
}
-
+
// Start stepping backwards from here, ensuring that our wallpaper windows
// are correctly placed.
int curTokenIndex = mWallpaperTokens.size();
@@ -1492,33 +1517,33 @@ public class WindowManagerService extends IWindowManager.Stub
// correct size.
mLayoutNeeded = true;
}
-
+
int curWallpaperIndex = token.windows.size();
while (curWallpaperIndex > 0) {
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
-
+
if (visible) {
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
-
+
// First, make sure the client has the current visibility
// state.
if (wallpaper.mWallpaperVisible != visible) {
wallpaper.mWallpaperVisible = visible;
try {
- if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Slog.v(TAG,
"Setting visibility of wallpaper " + wallpaper
+ ": " + visible);
wallpaper.mClient.dispatchAppVisibility(visible);
} catch (RemoteException e) {
}
}
-
+
wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mAnimLayer);
-
+
// First, if this window is at the current index, then all
// is well.
if (wallpaper == foundW) {
@@ -1527,35 +1552,35 @@ public class WindowManagerService extends IWindowManager.Stub
? (WindowState)localmWindows.get(foundI-1) : null;
continue;
}
-
+
// The window didn't match... the current wallpaper window,
// wherever it is, is in the wrong place, so make sure it is
// not in the list.
int oldIndex = localmWindows.indexOf(wallpaper);
if (oldIndex >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Wallpaper removing at "
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
+ oldIndex + ": " + wallpaper);
localmWindows.remove(oldIndex);
if (oldIndex < foundI) {
foundI--;
}
}
-
+
// Now stick it in.
- if (DEBUG_WALLPAPER || DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+ if (DEBUG_WALLPAPER || DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
"Moving wallpaper " + wallpaper
+ " from " + oldIndex + " to " + foundI);
-
+
localmWindows.add(foundI, wallpaper);
changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
}
}
-
+
return changed;
}
void setWallpaperAnimLayerAdjustmentLocked(int adj) {
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
"Setting wallpaper layer adj to " + adj);
mWallpaperAnimLayerAdjustment = adj;
int curTokenIndex = mWallpaperTokens.size();
@@ -1567,7 +1592,7 @@ public class WindowManagerService extends IWindowManager.Stub
curWallpaperIndex--;
WindowState wallpaper = token.windows.get(curWallpaperIndex);
wallpaper.mAnimLayer = wallpaper.mLayer + adj;
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+ wallpaper + " anim layer: " + wallpaper.mAnimLayer);
}
}
@@ -1583,7 +1608,7 @@ public class WindowManagerService extends IWindowManager.Stub
int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
changed = wallpaperWin.mXOffset != offset;
if (changed) {
- if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper "
+ wallpaperWin + " x: " + offset);
wallpaperWin.mXOffset = offset;
}
@@ -1592,13 +1617,13 @@ public class WindowManagerService extends IWindowManager.Stub
wallpaperWin.mWallpaperXStep = wpxs;
rawChanged = true;
}
-
+
float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
offset = availh > 0 ? -(int)(availh*wpy+.5f) : 0;
if (wallpaperWin.mYOffset != offset) {
- if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper "
+ wallpaperWin + " y: " + offset);
changed = true;
wallpaperWin.mYOffset = offset;
@@ -1608,10 +1633,10 @@ public class WindowManagerService extends IWindowManager.Stub
wallpaperWin.mWallpaperYStep = wpys;
rawChanged = true;
}
-
+
if (rawChanged) {
try {
- if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ " y=" + wallpaperWin.mWallpaperY);
if (sync) {
@@ -1626,15 +1651,15 @@ public class WindowManagerService extends IWindowManager.Stub
if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY)
< start) {
try {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Waiting for offset complete...");
mWindowMap.wait(WALLPAPER_TIMEOUT);
} catch (InterruptedException e) {
}
- if (DEBUG_WALLPAPER) Log.v(TAG, "Offset complete!");
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
if ((start+WALLPAPER_TIMEOUT)
< SystemClock.uptimeMillis()) {
- Log.i(TAG, "Timeout waiting for wallpaper to offset: "
+ Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
+ wallpaperWin);
mLastWallpaperTimeoutTime = start;
}
@@ -1645,10 +1670,10 @@ public class WindowManagerService extends IWindowManager.Stub
} catch (RemoteException e) {
}
}
-
+
return changed;
}
-
+
void wallpaperOffsetsComplete(IBinder window) {
synchronized (mWindowMap) {
if (mWaitingOnWallpaper != null &&
@@ -1658,13 +1683,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
boolean updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
-
+
boolean changed = false;
-
+
WindowState target = mWallpaperTarget;
if (target != null) {
if (target.mWallpaperX >= 0) {
@@ -1678,7 +1703,7 @@ public class WindowManagerService extends IWindowManager.Stub
mLastWallpaperY = changingTarget.mWallpaperY;
}
}
-
+
int curTokenIndex = mWallpaperTokens.size();
while (curTokenIndex > 0) {
curTokenIndex--;
@@ -1695,15 +1720,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
return changed;
}
-
+
void updateWallpaperVisibilityLocked() {
final boolean visible = isWallpaperVisible(mWallpaperTarget);
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
-
+
int curTokenIndex = mWallpaperTokens.size();
while (curTokenIndex > 0) {
curTokenIndex--;
@@ -1714,7 +1739,7 @@ public class WindowManagerService extends IWindowManager.Stub
// correct size.
mLayoutNeeded = true;
}
-
+
int curWallpaperIndex = token.windows.size();
while (curWallpaperIndex > 0) {
curWallpaperIndex--;
@@ -1722,11 +1747,11 @@ public class WindowManagerService extends IWindowManager.Stub
if (visible) {
updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
}
-
+
if (wallpaper.mWallpaperVisible != visible) {
wallpaper.mWallpaperVisible = visible;
try {
- if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Slog.v(TAG,
"Updating visibility of wallpaper " + wallpaper
+ ": " + visible);
wallpaper.mClient.dispatchAppVisibility(visible);
@@ -1736,7 +1761,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
void sendPointerToWallpaperLocked(WindowState srcWin,
MotionEvent pointer, long eventTime) {
int curTokenIndex = mWallpaperTokens.size();
@@ -1769,11 +1794,37 @@ public class WindowManagerService extends IWindowManager.Stub
}
wallpaper.mClient.dispatchPointer(ev, eventTime, false);
} catch (RemoteException e) {
- Log.w(TAG, "Failure sending pointer to wallpaper", e);
+ Slog.w(TAG, "Failure sending pointer to wallpaper", e);
}
}
}
}
+
+ void dispatchPointerElsewhereLocked(WindowState srcWin, WindowState relWin,
+ MotionEvent pointer, long eventTime, boolean skipped) {
+ if (relWin != null) {
+ mPolicy.dispatchedPointerEventLw(pointer, relWin.mFrame.left, relWin.mFrame.top);
+ } else {
+ mPolicy.dispatchedPointerEventLw(pointer, 0, 0);
+ }
+
+ // If we sent an initial down to the wallpaper, then continue
+ // sending events until the final up.
+ if (mSendingPointersToWallpaper) {
+ if (skipped) {
+ Slog.i(TAG, "Sending skipped pointer to wallpaper!");
+ }
+ sendPointerToWallpaperLocked(relWin, pointer, eventTime);
+
+ // If we are on top of the wallpaper, then the wallpaper also
+ // gets to see this movement.
+ } else if (srcWin != null
+ && pointer.getAction() == MotionEvent.ACTION_DOWN
+ && mWallpaperTarget == srcWin
+ && srcWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
+ sendPointerToWallpaperLocked(relWin, pointer, eventTime);
+ }
+ }
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
@@ -1794,25 +1845,27 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDisplay == null) {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = wm.getDefaultDisplay();
+ mInitialDisplayWidth = mDisplay.getWidth();
+ mInitialDisplayHeight = mDisplay.getHeight();
mQueue.setDisplay(mDisplay);
reportNewConfig = true;
}
if (mWindowMap.containsKey(client.asBinder())) {
- Log.w(TAG, "Window " + client + " is already added");
+ Slog.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);
+ attachedWindow = windowForClientLocked(null, attrs.token, false);
if (attachedWindow == null) {
- Log.w(TAG, "Attempted to add window with token that is not a window: "
+ Slog.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: "
+ Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
}
@@ -1823,17 +1876,17 @@ public class WindowManagerService extends IWindowManager.Stub
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 "
+ Slog.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 "
+ Slog.w(TAG, "Attempted to add input method window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
if (attrs.type == TYPE_WALLPAPER) {
- Log.w(TAG, "Attempted to add wallpaper window with unknown token "
+ Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
@@ -1843,29 +1896,29 @@ public class WindowManagerService extends IWindowManager.Stub
&& attrs.type <= LAST_APPLICATION_WINDOW) {
AppWindowToken atoken = token.appWindowToken;
if (atoken == null) {
- Log.w(TAG, "Attempted to add window with non-application token "
+ Slog.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 "
+ Slog.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(
+ if (localLOGV) Slog.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 "
+ Slog.w(TAG, "Attempted to add input method window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
} else if (attrs.type == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
- Log.w(TAG, "Attempted to add wallpaper window with bad token "
+ Slog.w(TAG, "Attempted to add wallpaper window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
@@ -1876,7 +1929,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
- Log.w(TAG, "Adding window client " + client.asBinder()
+ Slog.w(TAG, "Adding window client " + client.asBinder()
+ " that is dead, aborting.");
return WindowManagerImpl.ADD_APP_EXITING;
}
@@ -1961,9 +2014,13 @@ public class WindowManagerService extends IWindowManager.Stub
mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
}
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "New client " + client.asBinder()
+ ": window=" + win);
+
+ if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {
+ reportNewConfig = true;
+ }
}
// sendNewConfiguration() checks caller permissions so we must call it with
@@ -1973,14 +2030,6 @@ public class WindowManagerService extends IWindowManager.Stub
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 (updateOrientationFromAppTokensUnchecked(null, null) != null) {
- sendNewConfiguration();
- }
- }
}
Binder.restoreCallingIdentity(origId);
@@ -1989,7 +2038,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return;
}
@@ -1999,7 +2048,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void removeWindowLocked(Session session, WindowState win) {
- if (localLOGV || DEBUG_FOCUS) Log.v(
+ if (localLOGV || DEBUG_FOCUS) Slog.v(
TAG, "Remove " + win + " client="
+ Integer.toHexString(System.identityHashCode(
win.mClient.asBinder()))
@@ -2007,7 +2056,7 @@ public class WindowManagerService extends IWindowManager.Stub
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_APP_TRANSITIONS) Log.v(
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Remove " + win + ": mSurface=" + win.mSurface
+ " mExiting=" + win.mExiting
+ " isAnimating=" + win.isAnimating()
@@ -2022,7 +2071,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 (win.mSurface != null && !mDisplayFrozen && mPolicy.isScreenOn()) {
// If we are not currently running the exit animation, we
// need to see about starting one.
if (wasVisible=win.isWinVisibleLw()) {
@@ -2038,7 +2087,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (win.mExiting || win.isAnimating()) {
// The exit animation is running... wait for it!
- //Log.i(TAG, "*** Running exit animation...");
+ //Slog.i(TAG, "*** Running exit animation...");
win.mExiting = true;
win.mRemoveOnExit = true;
mLayoutNeeded = true;
@@ -2057,8 +2106,9 @@ public class WindowManagerService extends IWindowManager.Stub
// Removing a visible window will effect the computed orientation
// So just update orientation if needed.
if (wasVisible && computeForcedAppOrientationLocked()
- != mForcedAppOrientation) {
- mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
+ != mForcedAppOrientation
+ && updateOrientationFromAppTokensLocked()) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
@@ -2079,15 +2129,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (false) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
- Log.w(TAG, "Removing window " + win, e);
+ Slog.w(TAG, "Removing window " + win, e);
}
-
+
mPolicy.removeWindowLw(win);
win.removeLocked();
mWindowMap.remove(win.mClient.asBinder());
mWindows.remove(win);
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Final remove of window: " + win);
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
if (mInputMethodWindow == win) {
mInputMethodWindow = null;
@@ -2101,7 +2151,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (atoken != null) {
atoken.allAppWindows.remove(win);
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "**** Removing window " + win + ": count="
+ token.windows.size());
if (token.windows.size() == 0) {
@@ -2124,7 +2174,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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
+ Slog.v(TAG, "Schedule remove starting " + token
+ ": no more real windows");
}
Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
@@ -2138,7 +2188,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
}
-
+
if (!mInLayout) {
assignLayersLocked();
mLayoutNeeded = true;
@@ -2149,21 +2199,30 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private static void logSurface(WindowState w, String msg, RuntimeException where) {
+ String str = " SURFACE " + Integer.toHexString(w.hashCode())
+ + ": " + msg + " / " + w.mAttrs.getTitle();
+ if (where != null) {
+ Slog.i(TAG, str, where);
+ } else {
+ Slog.i(TAG, str);
+ }
+ }
+
private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
- WindowState w = windowForClientLocked(session, client);
+ WindowState w = windowForClientLocked(session, client, false);
if ((w != null) && (w.mSurface != null)) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
Surface.openTransaction();
try {
- if (SHOW_TRANSACTIONS) Log.i(
- TAG, " SURFACE " + w.mSurface
- + ": transparentRegionHint=" + region);
+ if (SHOW_TRANSACTIONS) logSurface(w,
+ "transparentRegionHint=" + region, null);
w.mSurface.setTransparentRegionHint(region);
} finally {
- if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION");
Surface.closeTransaction();
}
}
@@ -2179,7 +2238,7 @@ public class WindowManagerService extends IWindowManager.Stub
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
- WindowState w = windowForClientLocked(session, client);
+ WindowState w = windowForClientLocked(session, client, false);
if (w != null) {
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
@@ -2197,7 +2256,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void getWindowDisplayFrame(Session session, IWindow client,
Rect outDisplayFrame) {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
outDisplayFrame.setEmpty();
return;
@@ -2218,7 +2277,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
void wallpaperCommandComplete(IBinder window, Bundle result) {
synchronized (mWindowMap) {
if (mWaitingOnWallpaper != null &&
@@ -2228,7 +2287,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
public Bundle sendWindowWallpaperCommandLocked(WindowState window,
String action, int x, int y, int z, Bundle extras, boolean sync) {
if (window == mWallpaperTarget || window == mLowerWallpaperTarget
@@ -2251,27 +2310,27 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
if (doWait) {
// XXX Need to wait for result.
}
}
-
+
return null;
}
-
+
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) {
+ Configuration outConfig, Surface outSurface) {
boolean displayed = false;
boolean inTouchMode;
- Configuration newConfig = null;
+ boolean configChanged;
long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
@@ -2289,7 +2348,7 @@ public class WindowManagerService extends IWindowManager.Stub
attrChanges = win.mAttrs.copyFrom(attrs);
}
- if (DEBUG_LAYOUT) Log.v(TAG, "Relayout " + win + ": " + win.mAttrs);
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs);
if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
win.mAlpha = attrs.alpha;
@@ -2319,7 +2378,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
&& (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
-
+
win.mRelayoutCalled = true;
final int oldVisibility = win.mViewVisibility;
win.mViewVisibility = viewVisibility;
@@ -2337,13 +2396,30 @@ public class WindowManagerService extends IWindowManager.Stub
if (oldVisibility == View.GONE) {
win.mEnterAnimationPending = true;
}
- if (displayed && win.mSurface != null && !win.mDrawPending
- && !win.mCommitDrawPending && !mDisplayFrozen) {
- applyEnterAnimationLocked(win);
- }
- if (displayed && (win.mAttrs.flags
- & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
- win.mTurnOnScreen = true;
+ if (displayed) {
+ if (win.mSurface != null && !win.mDrawPending
+ && !win.mCommitDrawPending && !mDisplayFrozen
+ && mPolicy.isScreenOn()) {
+ applyEnterAnimationLocked(win);
+ }
+ if ((win.mAttrs.flags
+ & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
+ "Relayout window turning screen on: " + win);
+ win.mTurnOnScreen = true;
+ }
+ int diff = 0;
+ if (win.mConfiguration != mCurConfiguration
+ && (win.mConfiguration == null
+ || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0)) {
+ win.mConfiguration = mCurConfiguration;
+ if (DEBUG_CONFIGURATION) {
+ Slog.i(TAG, "Window " + win + " visible with new config: "
+ + win.mConfiguration + " / 0x"
+ + Integer.toHexString(diff));
+ }
+ outConfig.setTo(mCurConfiguration);
+ }
}
if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
// To change the format, we need to re-build the surface.
@@ -2356,7 +2432,7 @@ public class WindowManagerService extends IWindowManager.Stub
outSurface.copyFrom(surface);
win.mReportDestroySurface = false;
win.mSurfacePendingDestroy = false;
- if (SHOW_TRANSACTIONS) Log.i(TAG,
+ if (SHOW_TRANSACTIONS) Slog.i(TAG,
" OUT SURFACE " + outSurface + ": copied");
} else {
// For some reason there isn't a surface. Clear the
@@ -2364,7 +2440,7 @@ public class WindowManagerService extends IWindowManager.Stub
outSurface.release();
}
} catch (Exception e) {
- Log.w(TAG, "Exception thrown when creating surface for client "
+ Slog.w(TAG, "Exception thrown when creating surface for client "
+ client + " (" + win.mAttrs.getTitle() + ")",
e);
Binder.restoreCallingIdentity(origId);
@@ -2386,14 +2462,15 @@ public class WindowManagerService extends IWindowManager.Stub
// to provide the correct semantics while starting.
final int mask =
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+ | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs;
sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask);
}
} else {
win.mEnterAnimationPending = false;
if (win.mSurface != null) {
- if (DEBUG_VISIBILITY) Log.i(TAG, "Relayout invis " + win
+ if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
+ ": mExiting=" + win.mExiting
+ " mSurfacePendingDestroy=" + win.mSurfacePendingDestroy);
// If we are not currently running the exit animation, we
@@ -2429,7 +2506,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
if (win.mSurface == null || (win.getAttrs().flags
& WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0
|| win.mSurfacePendingDestroy) {
@@ -2439,9 +2516,9 @@ public class WindowManagerService extends IWindowManager.Stub
// destroyed at this point.
win.mSurfacePendingDestroy = false;
outSurface.release();
- if (DEBUG_VISIBILITY) Log.i(TAG, "Releasing surface in: " + win);
+ if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
} else if (win.mSurface != null) {
- if (DEBUG_VISIBILITY) Log.i(TAG,
+ if (DEBUG_VISIBILITY) Slog.i(TAG,
"Keeping surface, will report destroy: " + win);
win.mReportDestroySurface = true;
outSurface.copyFrom(win.mSurface);
@@ -2481,7 +2558,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (assignLayers) {
assignLayersLocked();
}
- newConfig = updateOrientationFromAppTokensLocked(null, null);
+ configChanged = updateOrientationFromAppTokensLocked();
performLayoutAndPlaceSurfacesLocked();
if (displayed && win.mIsWallpaper) {
updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
@@ -2493,7 +2570,7 @@ public class WindowManagerService extends IWindowManager.Stub
outFrame.set(win.mFrame);
outContentInsets.set(win.mContentInsets);
outVisibleInsets.set(win.mVisibleInsets);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Relayout given client " + client.asBinder()
+ ", requestedWidth=" + requestedWidth
+ ", requestedHeight=" + requestedHeight
@@ -2501,13 +2578,13 @@ public class WindowManagerService extends IWindowManager.Stub
+ "\nRelayout returning frame=" + outFrame
+ ", surface=" + outSurface);
- if (localLOGV || DEBUG_FOCUS) Log.v(
+ if (localLOGV || DEBUG_FOCUS) Slog.v(
TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
inTouchMode = mInTouchMode;
}
- if (newConfig != null) {
+ if (configChanged) {
sendNewConfiguration();
}
@@ -2520,7 +2597,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void finishDrawingWindow(Session session, IWindow client) {
final long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(session, client);
+ WindowState win = windowForClientLocked(session, client, false);
if (win != null && win.finishDrawingLocked()) {
if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
@@ -2533,7 +2610,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
- if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
+ if (DEBUG_ANIM) Slog.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) {
@@ -2545,7 +2622,7 @@ public class WindowManagerService extends IWindowManager.Stub
if ((resId&0xFF000000) == 0x01000000) {
packageName = "android";
}
- if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
+ if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
+ packageName);
return AttributeCache.instance().get(packageName, resId,
com.android.internal.R.styleable.WindowAnimation);
@@ -2554,13 +2631,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
- if (DEBUG_ANIM) Log.v(TAG, "Loading animations: params package="
+ if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: params package="
+ packageName + " resId=0x" + Integer.toHexString(resId));
if (packageName != null) {
if ((resId&0xFF000000) == 0x01000000) {
packageName = "android";
}
- if (DEBUG_ANIM) Log.v(TAG, "Loading animations: picked package="
+ if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
+ packageName);
return AttributeCache.instance().get(packageName, resId,
com.android.internal.R.styleable.WindowAnimation);
@@ -2590,7 +2667,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()) {
int anim = mPolicy.selectAnimationLw(win, transit);
int attr = -1;
Animation a = null;
@@ -2615,15 +2692,18 @@ public class WindowManagerService extends IWindowManager.Stub
a = loadAnimation(win.mAttrs, attr);
}
}
- if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: win=" + win
+ if (DEBUG_ANIM) Slog.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();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.v(TAG, "Loaded animation " + a + " for " + win, e);
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.v(TAG, "Loaded animation " + a + " for " + win, e);
}
win.setAnimation(a);
win.mAnimationIsEntrance = isEntrance;
@@ -2673,11 +2753,11 @@ public class WindowManagerService extends IWindowManager.Stub
// 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) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()) {
Animation a;
if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
a = new FadeInOutAnimation(enter);
- if (DEBUG_ANIM) Log.v(TAG,
+ if (DEBUG_ANIM) Slog.v(TAG,
"applying FadeInOutAnimation for a window in compatibility mode");
} else if (mNextAppTransitionPackage != null) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -2737,16 +2817,19 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
- if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
+ if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: wtoken=" + wtoken
+ " anim=" + a
+ " animAttr=0x" + Integer.toHexString(animAttr)
+ " transit=" + transit);
}
if (a != null) {
if (DEBUG_ANIM) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
}
wtoken.setAnimation(a);
}
@@ -2771,20 +2854,20 @@ public class WindowManagerService extends IWindowManager.Stub
continue;
}
if (tokens.get(v) != wtoken.token) {
- Log.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
+ Slog.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);
+ Slog.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);
+ Slog.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m);
}
m--;
}
@@ -2804,7 +2887,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + permission;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
return false;
}
@@ -2825,7 +2908,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
WindowToken wtoken = mTokenMap.get(token);
if (wtoken != null) {
- Log.w(TAG, "Attempted to add existing input method token: " + token);
+ Slog.w(TAG, "Attempted to add existing input method token: " + token);
return;
}
wtoken = new WindowToken(token, type, true);
@@ -2885,7 +2968,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
} else {
- Log.w(TAG, "Attempted to remove non-existing token: " + token);
+ Slog.w(TAG, "Attempted to remove non-existing token: " + token);
}
}
Binder.restoreCallingIdentity(origId);
@@ -2901,7 +2984,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken != null) {
- Log.w(TAG, "Attempted to add existing app token: " + token);
+ Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
wtoken = new AppWindowToken(token);
@@ -2909,7 +2992,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.appFullscreen = fullscreen;
wtoken.requestedOrientation = requestedOrientation;
mAppTokens.add(addPos, wtoken);
- if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
+ if (localLOGV) Slog.v(TAG, "Adding new app token: " + wtoken);
mTokenMap.put(token.asBinder(), wtoken);
mTokenList.add(wtoken);
@@ -2930,7 +3013,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token);
if (wtoken == null) {
- Log.w(TAG, "Attempted to set group id of non-existing app token: " + token);
+ Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
return;
}
wtoken.groupId = groupId;
@@ -2947,7 +3030,7 @@ public class WindowManagerService extends IWindowManager.Stub
// app window. No point in continuing further.
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- if (!wtoken.isVisibleLw()) {
+ if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
continue;
}
int req = wtoken.mAttrs.screenOrientation;
@@ -2962,62 +3045,62 @@ public class WindowManagerService extends IWindowManager.Stub
}
public int getOrientationFromAppTokensLocked() {
- int pos = mAppTokens.size() - 1;
- int curGroup = 0;
- int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- boolean findingBehind = false;
- boolean haveGroup = false;
- boolean lastFullscreen = false;
- while (pos >= 0) {
- AppWindowToken wtoken = mAppTokens.get(pos);
- pos--;
- // if we're about to tear down this window and not seek for
- // the behind activity, don't use it for orientation
- if (!findingBehind
- && (!wtoken.hidden && wtoken.hiddenRequested)) {
+ int pos = mAppTokens.size() - 1;
+ int curGroup = 0;
+ int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean findingBehind = false;
+ boolean haveGroup = false;
+ boolean lastFullscreen = false;
+ while (pos >= 0) {
+ AppWindowToken wtoken = mAppTokens.get(pos);
+ pos--;
+ // if we're about to tear down this window and not seek for
+ // the behind activity, don't use it for orientation
+ if (!findingBehind
+ && (!wtoken.hidden && wtoken.hiddenRequested)) {
+ continue;
+ }
+
+ if (!haveGroup) {
+ // We ignore any hidden applications on the top.
+ if (wtoken.hiddenRequested || wtoken.willBeHidden) {
continue;
}
-
- 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, and the last app was
- // full screen, then we'll stick with the
- // user's orientation.
- if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
- && lastFullscreen) {
- return lastOrientation;
- }
- }
- int or = wtoken.requestedOrientation;
- // If this application is fullscreen, and didn't explicitly say
- // to use the orientation behind it, then just take whatever
- // orientation it has and ignores whatever is under it.
- lastFullscreen = wtoken.appFullscreen;
- if (lastFullscreen
- && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
- 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;
- }
- findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
- }
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ 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, and the last app was
+ // full screen, then we'll stick with the
+ // user's orientation.
+ if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
+ && lastFullscreen) {
+ return lastOrientation;
+ }
+ }
+ int or = wtoken.requestedOrientation;
+ // If this application is fullscreen, and didn't explicitly say
+ // to use the orientation behind it, then just take whatever
+ // orientation it has and ignores whatever is under it.
+ lastFullscreen = wtoken.appFullscreen;
+ if (lastFullscreen
+ && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ 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;
+ }
+ findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
+ }
+ return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
public Configuration updateOrientationFromAppTokens(
@@ -3026,82 +3109,85 @@ public class WindowManagerService extends IWindowManager.Stub
"updateOrientationFromAppTokens()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
- Configuration config;
- long ident = Binder.clearCallingIdentity();
- config = updateOrientationFromAppTokensUnchecked(currentConfig,
- freezeThisOneIfNeeded);
- Binder.restoreCallingIdentity(ident);
- return config;
- }
- Configuration updateOrientationFromAppTokensUnchecked(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- Configuration config;
+ Configuration config = null;
+ long ident = Binder.clearCallingIdentity();
+
synchronized(mWindowMap) {
- config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
- if (config != null) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
+ if (updateOrientationFromAppTokensLocked()) {
+ if (freezeThisOneIfNeeded != null) {
+ AppWindowToken wtoken = findAppWindowToken(
+ freezeThisOneIfNeeded);
+ if (wtoken != null) {
+ startAppFreezingScreenLocked(wtoken,
+ ActivityInfo.CONFIG_ORIENTATION);
+ }
+ }
+ config = computeNewConfigurationLocked();
+
+ } else if (currentConfig != null) {
+ // No obvious action we need to take, but if our current
+ // state mismatches the activity maanager's, update it
+ mTempConfiguration.setToDefaults();
+ if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (currentConfig.diff(mTempConfiguration) != 0) {
+ mWaitingForConfig = true;
+ mLayoutNeeded = true;
+ startFreezingDisplayLocked();
+ config = new Configuration(mTempConfiguration);
+ }
+ }
}
}
+
+ Binder.restoreCallingIdentity(ident);
return config;
}
/*
+ * Determine the new desired orientation of the display, returning
+ * a non-null new Configuration if it has changed from the current
+ * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL
+ * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
+ * SCREEN. This will typically be done for you if you call
+ * sendNewConfiguration().
+ *
* 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)
*/
- Configuration updateOrientationFromAppTokensLocked(
- Configuration appConfig, IBinder freezeThisOneIfNeeded) {
+ boolean updateOrientationFromAppTokensLocked() {
+ if (mDisplayFrozen) {
+ // If the display is frozen, some activities may be in the middle
+ // of restarting, and thus have removed their old window. If the
+ // window has the flag to hide the lock screen, then the lock screen
+ // can re-appear and inflict its own orientation on us. Keep the
+ // orientation stable until this all settles down.
+ return false;
+ }
+
boolean changed = false;
long ident = Binder.clearCallingIdentity();
try {
int req = computeForcedAppOrientationLocked();
if (req != mForcedAppOrientation) {
- changed = true;
mForcedAppOrientation = req;
//send a message to Policy indicating orientation change to take
//action like disabling/enabling sensors etc.,
mPolicy.setCurrentOrientationLw(req);
- }
-
- if (changed) {
- changed = setRotationUncheckedLocked(
- WindowManagerPolicy.USE_LAST_ROTATION,
- mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
- if (changed) {
- if (freezeThisOneIfNeeded != null) {
- AppWindowToken wtoken = findAppWindowToken(
- freezeThisOneIfNeeded);
- if (wtoken != null) {
- startAppFreezingScreenLocked(wtoken,
- ActivityInfo.CONFIG_ORIENTATION);
- }
- }
- return computeNewConfigurationLocked();
+ if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION,
+ mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)) {
+ changed = true;
}
}
- // No obvious action we need to take, but if our current
- // state mismatches the activity maanager's, update it
- if (appConfig != null) {
- mTempConfiguration.setToDefaults();
- if (computeNewConfigurationLocked(mTempConfiguration)) {
- if (appConfig.diff(mTempConfiguration) != 0) {
- return new Configuration(mTempConfiguration);
- }
- }
- }
+ return changed;
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- return null;
}
int computeForcedAppOrientationLocked() {
@@ -3112,6 +3198,19 @@ public class WindowManagerService extends IWindowManager.Stub
return req;
}
+ public void setNewConfiguration(Configuration config) {
+ if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+ "setNewConfiguration()")) {
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+ }
+
+ synchronized(mWindowMap) {
+ mCurConfiguration = new Configuration(config);
+ mWaitingForConfig = false;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppOrientation()")) {
@@ -3121,7 +3220,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken == null) {
- Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
+ Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
return;
}
@@ -3149,19 +3248,19 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
boolean changed = false;
if (token == null) {
- if (DEBUG_FOCUS) Log.v(TAG, "Clearing focused app, was " + mFocusedApp);
+ if (DEBUG_FOCUS) Slog.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);
+ Slog.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);
+ if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp);
mKeyWaiter.tickle();
}
@@ -3180,10 +3279,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- if (DEBUG_APP_TRANSITIONS) Log.v(
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Prepare app transition: transit=" + transit
+ " mNextAppTransition=" + mNextAppTransition);
- if (!mDisplayFrozen) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()) {
if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
|| mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
mNextAppTransition = transit;
@@ -3219,7 +3318,7 @@ public class WindowManagerService extends IWindowManager.Stub
mNextAppTransitionExit = exitAnim;
}
}
-
+
public void executeAppTransition() {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"executeAppTransition()")) {
@@ -3230,7 +3329,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_APP_TRANSITIONS) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
- Log.w(TAG, "Execute app transition: mNextAppTransition="
+ Slog.w(TAG, "Execute app transition: mNextAppTransition="
+ mNextAppTransition, e);
}
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -3251,20 +3350,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- if (DEBUG_STARTING_WINDOW) Log.v(
+ if (DEBUG_STARTING_WINDOW) Slog.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);
+ Slog.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) {
+ if (mDisplayFrozen || !mPolicy.isScreenOn()) {
return;
}
@@ -3283,7 +3382,7 @@ public class WindowManagerService extends IWindowManager.Stub
// shown immediately without any more transitions.
mSkipAppTransitionAnimation = true;
}
- if (DEBUG_STARTING_WINDOW) Log.v(TAG,
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
"Moving existing starting from " + ttoken
+ " to " + wtoken);
final long origId = Binder.clearCallingIdentity();
@@ -3300,7 +3399,7 @@ public class WindowManagerService extends IWindowManager.Stub
startingWindow.mToken = wtoken;
startingWindow.mRootToken = wtoken;
startingWindow.mAppToken = wtoken;
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
"Removing starting window: " + startingWindow);
mWindows.remove(startingWindow);
ttoken.windows.remove(startingWindow);
@@ -3345,7 +3444,7 @@ public class WindowManagerService extends IWindowManager.Stub
} 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,
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
"Moving pending starting from " + ttoken
+ " to " + wtoken);
wtoken.startingData = ttoken.startingData;
@@ -3387,7 +3486,7 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
}
-
+
mStartingIconInTransition = true;
wtoken.startingData = new StartingData(
pkg, theme, nonLocalizedLabel,
@@ -3411,7 +3510,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
wtoken = findAppWindowToken(token);
if (wtoken == null) {
- Log.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
+ Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
return;
}
wtoken.willBeHidden = true;
@@ -3431,7 +3530,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken.hidden == visible) {
final int N = wtoken.allAppWindows.size();
boolean changed = false;
- if (DEBUG_APP_TRANSITIONS) Log.v(
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
+ " performLayout=" + performLayout);
@@ -3458,7 +3557,7 @@ public class WindowManagerService extends IWindowManager.Stub
delayed = true;
}
- //Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
+ //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());
//win.dump(" ");
if (visible) {
if (!win.isVisibleNow()) {
@@ -3493,7 +3592,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
+ ": hidden=" + wtoken.hidden + " hiddenRequested="
+ wtoken.hiddenRequested);
@@ -3524,14 +3623,17 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
wtoken = findAppWindowToken(token);
if (wtoken == null) {
- Log.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
+ Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
return;
}
if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.v(TAG, "setAppVisibility(" + token + ", " + visible
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.v(TAG, "setAppVisibility(" + token + ", " + visible
+ "): mNextAppTransition=" + mNextAppTransition
+ " hidden=" + wtoken.hidden
+ " hiddenRequested=" + wtoken.hiddenRequested, e);
@@ -3539,14 +3641,15 @@ public class WindowManagerService extends IWindowManager.Stub
// 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_UNSET) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()
+ && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
// Already in requested state, don't do anything more.
if (wtoken.hiddenRequested != visible) {
return;
}
wtoken.hiddenRequested = !visible;
- if (DEBUG_APP_TRANSITIONS) Log.v(
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Setting dummy animation on: " + wtoken);
wtoken.setDummyAnimation();
mOpeningApps.remove(wtoken);
@@ -3557,14 +3660,14 @@ public class WindowManagerService extends IWindowManager.Stub
mOpeningApps.add(wtoken);
wtoken.startingDisplayed = false;
wtoken.startingMoved = false;
-
+
// If the token is currently hidden (should be the
// common case), then we need to set up to wait for
// its windows to be ready.
if (wtoken.hidden) {
wtoken.allDrawn = false;
wtoken.waitingToShow = true;
-
+
if (wtoken.clientHidden) {
// In the case where we are making an app visible
// but holding off for a transition, we still need
@@ -3578,7 +3681,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
} else {
mClosingApps.add(wtoken);
-
+
// If the token is currently visible (should be the
// common case), then set up to wait for it to be hidden.
if (!wtoken.hidden) {
@@ -3598,7 +3701,7 @@ public class WindowManagerService extends IWindowManager.Stub
void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
boolean unfreezeSurfaceNow, boolean force) {
if (wtoken.freezingScreen) {
- if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + wtoken
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
+ " force=" + force);
final int N = wtoken.allAppWindows.size();
boolean unfrozeWindows = false;
@@ -3613,7 +3716,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
if (force || unfrozeWindows) {
- if (DEBUG_ORIENTATION) Log.v(TAG, "No longer freezing: " + wtoken);
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
wtoken.freezingScreen = false;
mAppsFreezingScreen--;
}
@@ -3622,9 +3725,7 @@ public class WindowManagerService extends IWindowManager.Stub
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
- if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
- stopFreezingDisplayLocked();
- }
+ stopFreezingDisplayLocked();
}
}
}
@@ -3632,9 +3733,12 @@ public class WindowManagerService extends IWindowManager.Stub
public void startAppFreezingScreenLocked(AppWindowToken wtoken,
int configChanges) {
if (DEBUG_ORIENTATION) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.i(TAG, "Set freezing of " + wtoken.appToken
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.i(TAG, "Set freezing of " + wtoken.appToken
+ ": hidden=" + wtoken.hidden + " freezing="
+ wtoken.freezingScreen, e);
}
@@ -3664,14 +3768,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- if (configChanges == 0 && !mDisplayFrozen) {
- if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
+ if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOn()) {
+ if (DEBUG_ORIENTATION) Slog.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);
+ Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
return;
}
final long origId = Binder.clearCallingIdentity();
@@ -3692,7 +3796,7 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_ORIENTATION) Log.v(TAG, "Clear freezing of " + token
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
+ ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
unsetAppFreezingScreenLocked(wtoken, true, force);
Binder.restoreCallingIdentity(origId);
@@ -3714,7 +3818,7 @@ public class WindowManagerService extends IWindowManager.Stub
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);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_UNSET, true);
wtoken.inPendingTransaction = false;
mOpeningApps.remove(wtoken);
@@ -3726,7 +3830,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.waitingToHide = true;
delayed = true;
}
- if (DEBUG_APP_TRANSITIONS) Log.v(
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Removing app " + wtoken + " delayed=" + delayed
+ " animation=" + wtoken.animation
+ " animating=" + wtoken.animating);
@@ -3751,13 +3855,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
unsetAppFreezingScreenLocked(wtoken, true, true);
if (mFocusedApp == wtoken) {
- if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
+ if (DEBUG_FOCUS) Slog.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);
+ Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
}
if (!delayed && wtoken != null) {
@@ -3767,7 +3871,7 @@ public class WindowManagerService extends IWindowManager.Stub
Binder.restoreCallingIdentity(origId);
if (startingToken != null) {
- if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Schedule remove starting "
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting "
+ startingToken + ": app token removed");
Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
mH.sendMessage(m);
@@ -3778,13 +3882,13 @@ public class WindowManagerService extends IWindowManager.Stub
final int NW = token.windows.size();
for (int i=0; i<NW; i++) {
WindowState win = token.windows.get(i);
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Tmp removing app window " + win);
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
mWindows.remove(win);
int j = win.mChildWindows.size();
while (j > 0) {
j--;
WindowState cwin = (WindowState)win.mChildWindows.get(j);
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
"Tmp removing child window " + cwin);
mWindows.remove(cwin);
}
@@ -3794,13 +3898,13 @@ public class WindowManagerService extends IWindowManager.Stub
void dumpAppTokensLocked() {
for (int i=mAppTokens.size()-1; i>=0; i--) {
- Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
+ Slog.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));
+ Slog.v(TAG, " #" + i + ": " + mWindows.get(i));
}
}
@@ -3822,10 +3926,10 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 @ "
+ if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
+ tokenPos + " -- " + wtoken.token);
if (wtoken.sendingToBottom) {
- if (DEBUG_REORDER) Log.v(TAG,
+ if (DEBUG_REORDER) Slog.v(TAG,
"Skipping token -- currently sending to bottom");
tokenPos--;
continue;
@@ -3841,7 +3945,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (cwin.mSubLayer >= 0) {
for (int pos=NW-1; pos>=0; pos--) {
if (mWindows.get(pos) == cwin) {
- if (DEBUG_REORDER) Log.v(TAG,
+ if (DEBUG_REORDER) Slog.v(TAG,
"Found child win @" + (pos+1));
return pos+1;
}
@@ -3850,7 +3954,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
for (int pos=NW-1; pos>=0; pos--) {
if (mWindows.get(pos) == win) {
- if (DEBUG_REORDER) Log.v(TAG, "Found win @" + (pos+1));
+ if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1));
return pos+1;
}
}
@@ -3867,19 +3971,19 @@ public class WindowManagerService extends IWindowManager.Stub
for (int j=0; j<NCW; j++) {
WindowState cwin = (WindowState)win.mChildWindows.get(j);
if (!added && cwin.mSubLayer >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Re-adding child window at "
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
+ index + ": " + cwin);
mWindows.add(index, win);
index++;
added = true;
}
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Re-adding window at "
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
+ index + ": " + cwin);
mWindows.add(index, cwin);
index++;
}
if (!added) {
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Re-adding window at "
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
+ index + ": " + win);
mWindows.add(index, win);
index++;
@@ -3902,26 +4006,26 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- if (DEBUG_REORDER) Log.v(TAG, "Initial app tokens:");
+ if (DEBUG_REORDER) Slog.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: "
+ Slog.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) Slog.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) Slog.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) Slog.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) Slog.v(TAG, "Final window list:");
if (DEBUG_REORDER) dumpWindowsLocked();
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
mLayoutNeeded = true;
@@ -3940,7 +4044,7 @@ public class WindowManagerService extends IWindowManager.Stub
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: "
+ Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
+ token + " (" + wtoken + ")");
i--;
N--;
@@ -4022,7 +4126,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
moveAppWindowsLocked(tokens, mAppTokens.size());
}
@@ -4055,7 +4159,7 @@ public class WindowManagerService extends IWindowManager.Stub
pos++;
}
}
-
+
if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
moveAppWindowsLocked(tokens, 0);
}
@@ -4140,7 +4244,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
static float fixScale(float scale) {
if (scale < 0) scale = 0;
else if (scale > 20) scale = 20;
@@ -4315,23 +4419,24 @@ public class WindowManagerService extends IWindowManager.Stub
final int N = mWindows.size();
for (int i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+ if (w.isVisibleLw() && !w.mObscured
+ && (w.mOrientationChanging || !w.isDrawnLw())) {
return;
}
}
mDisplayEnabled = true;
if (false) {
- Log.i(TAG, "ENABLING SCREEN!");
+ Slog.i(TAG, "ENABLING SCREEN!");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
this.dump(null, pw, null);
- Log.i(TAG, sw.toString());
+ Slog.i(TAG, sw.toString());
}
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
- //Log.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
+ //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
@@ -4339,7 +4444,7 @@ public class WindowManagerService extends IWindowManager.Stub
data.recycle();
}
} catch (RemoteException ex) {
- Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
+ Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
}
@@ -4368,7 +4473,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setRotationUnchecked(int rotation,
boolean alwaysSendConfiguration, int animFlags) {
- if(DEBUG_ORIENTATION) Log.v(TAG,
+ if(DEBUG_ORIENTATION) Slog.v(TAG,
"alwaysSendConfiguration set to "+alwaysSendConfiguration);
long origId = Binder.clearCallingIdentity();
@@ -4377,20 +4482,21 @@ public class WindowManagerService extends IWindowManager.Stub
changed = setRotationUncheckedLocked(rotation, animFlags);
}
- if (changed) {
- sendNewConfiguration();
- synchronized(mWindowMap) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- }
- } else if (alwaysSendConfiguration) {
- //update configuration ignoring orientation change
+ if (changed || alwaysSendConfiguration) {
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
}
+ /**
+ * Apply a new rotation to the screen, respecting the requests of
+ * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply
+ * re-evaluate the desired rotation.
+ *
+ * Returns null if the rotation has been changed. In this case YOU
+ * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
+ */
public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
boolean changed;
if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
@@ -4399,14 +4505,14 @@ public class WindowManagerService extends IWindowManager.Stub
mRequestedRotation = rotation;
mLastRotationFlags = animFlags;
}
- if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation);
rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
mRotation, mDisplayEnabled);
- if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation);
changed = mDisplayEnabled && mRotation != rotation;
if (changed) {
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Rotation changed to " + rotation
+ " from " + mRotation
+ " (forceApp=" + mForcedAppOrientation
@@ -4416,8 +4522,10 @@ public class WindowManagerService extends IWindowManager.Stub
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
2000);
+ mWaitingForConfig = true;
+ mLayoutNeeded = true;
startFreezingDisplayLocked();
- Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
+ Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
mQueue.setOrientation(rotation);
if (mDisplayEnabled) {
Surface.setOrientation(0, rotation, animFlags);
@@ -4501,7 +4609,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
return mViewServer.start();
} catch (IOException e) {
- Log.w(TAG, "View server did not start");
+ Slog.w(TAG, "View server did not start");
}
}
return false;
@@ -4511,7 +4619,7 @@ public class WindowManagerService extends IWindowManager.Stub
mViewServer = new ViewServer(this, port);
return mViewServer.start();
} catch (IOException e) {
- Log.w(TAG, "View server did not start");
+ Slog.w(TAG, "View server did not start");
}
return false;
}
@@ -4656,7 +4764,7 @@ public class WindowManagerService extends IWindowManager.Stub
index = parameters.length();
}
final String code = parameters.substring(0, index);
- int hashCode = "ffffffff".equals(code) ? -1 : Integer.parseInt(code, 16);
+ int hashCode = (int) Long.parseLong(code, 16);
// Extract the command's parameter after the window description
if (index < parameters.length()) {
@@ -4686,7 +4794,7 @@ public class WindowManagerService extends IWindowManager.Stub
reply.readException();
} catch (Exception e) {
- Log.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
+ Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
success = false;
} finally {
if (data != null) {
@@ -4750,8 +4858,13 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
mQueue.getInputConfiguration(config);
- final int dw = mDisplay.getWidth();
- final int dh = mDisplay.getHeight();
+
+ // Use the effective "visual" dimensions based on current rotation
+ final boolean rotated = (mRotation == Surface.ROTATION_90
+ || mRotation == Surface.ROTATION_270);
+ final int dw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
+ final int dh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
+
int orientation = Configuration.ORIENTATION_SQUARE;
if (dw < dh) {
orientation = Configuration.ORIENTATION_PORTRAIT;
@@ -4759,7 +4872,7 @@ public class WindowManagerService extends IWindowManager.Stub
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
config.orientation = orientation;
-
+
DisplayMetrics dm = new DisplayMetrics();
mDisplay.getMetrics(dm);
CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
@@ -4794,7 +4907,7 @@ public class WindowManagerService extends IWindowManager.Stub
mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
} else {
mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
-
+
// If this screen is wider than normal HVGA, or taller
// than FWVGA, then for old apps we want to run in size
// compatibility mode.
@@ -4802,7 +4915,7 @@ public class WindowManagerService extends IWindowManager.Stub
mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
}
}
-
+
// Is this a long screen?
if (((longSize*3)/5) >= (shortSize-1)) {
// Anything wider than WVGA (5:3) is considering to be long.
@@ -4813,7 +4926,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
config.screenLayout = mScreenLayout;
-
+
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
mPolicy.adjustConfigurationLw(config);
@@ -4884,7 +4997,7 @@ public class WindowManagerService extends IWindowManager.Stub
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
- if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
+ if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Slog.v(TAG,
"dispatchPointer " + ev);
if (MEASURE_LATENCY) {
@@ -4893,7 +5006,7 @@ public class WindowManagerService extends IWindowManager.Stub
Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
ev, true, false, pid, uid);
-
+
if (MEASURE_LATENCY) {
lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
}
@@ -4915,13 +5028,10 @@ public class WindowManagerService extends IWindowManager.Stub
// pointer without actually pressing down. All other cases should
// be atypical, so let's log them.
if (action != MotionEvent.ACTION_MOVE) {
- Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
+ Slog.w(TAG, "No window to dispatch pointer action " + ev.getAction());
}
synchronized (mWindowMap) {
- if (mSendingPointersToWallpaper) {
- Log.i(TAG, "Sending skipped pointer to wallpaper!");
- sendPointerToWallpaperLocked(null, ev, ev.getEventTime());
- }
+ dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
}
if (qev != null) {
mQueue.recycleEvent(qev);
@@ -4931,10 +5041,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
synchronized (mWindowMap) {
- if (mSendingPointersToWallpaper) {
- Log.i(TAG, "Sending skipped pointer to wallpaper!");
- sendPointerToWallpaperLocked(null, ev, ev.getEventTime());
- }
+ dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
}
if (qev != null) {
mQueue.recycleEvent(qev);
@@ -4947,14 +5054,14 @@ public class WindowManagerService extends IWindowManager.Stub
final long eventTime = ev.getEventTime();
final long eventTimeNano = ev.getEventTimeNano();
-
- //Log.i(TAG, "Sending " + ev + " to " + target);
+
+ //Slog.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 "
+ Slog.w(TAG, "Permission denied: injecting pointer event from pid "
+ pid + " uid " + uid + " to window " + target
+ " owned by uid " + target.mSession.mUid);
if (qev != null) {
@@ -4964,7 +5071,7 @@ public class WindowManagerService extends IWindowManager.Stub
return INJECT_NO_PERMISSION;
}
}
-
+
if (MEASURE_LATENCY) {
lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
}
@@ -5003,7 +5110,7 @@ public class WindowManagerService extends IWindowManager.Stub
//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");
+ if (DEBUG_INPUT) Slog.v(TAG, "Sending cancel for invalid ACTION_MOVE");
//note that the subsequent invalid moves will not get here
mFatTouch = true;
}
@@ -5059,16 +5166,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (!target.isVisibleLw()) {
// During this motion dispatch, the target window has become
// invisible.
- if (mSendingPointersToWallpaper) {
- sendPointerToWallpaperLocked(null, ev, eventTime);
- }
+ dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), false);
if (qev != null) {
mQueue.recycleEvent(qev);
}
ev.recycle();
return INJECT_SUCCEEDED;
}
-
+
if (qev != null && action == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(target,
KeyWaiter.RETURN_PENDING_POINTER, qev);
@@ -5085,7 +5190,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
out.mClient.dispatchPointer(oev, eventTime, false);
} catch (android.os.RemoteException e) {
- Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
+ Slog.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
}
oev.offsetLocation((float)frame.left, (float)frame.top);
out = out.mNextOutsideTouch;
@@ -5093,15 +5198,9 @@ public class WindowManagerService extends IWindowManager.Stub
mKeyWaiter.mOutsideTouchTargets = null;
}
}
-
- // If we are on top of the wallpaper, then the wallpaper also
- // gets to see this movement.
- if ((mWallpaperTarget == target &&
- target.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD)
- || mSendingPointersToWallpaper) {
- sendPointerToWallpaperLocked(null, ev, eventTime);
- }
-
+
+ dispatchPointerElsewhereLocked(target, null, ev, ev.getEventTime(), false);
+
final Rect frame = target.mFrame;
ev.offsetLocation(-(float)frame.left, -(float)frame.top);
mKeyWaiter.bindTargetWindowLocked(target);
@@ -5112,9 +5211,9 @@ public class WindowManagerService extends IWindowManager.Stub
// dispatch the event.
try {
if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
- Log.v(TAG, "Delivering pointer " + qev + " to " + target);
+ Slog.v(TAG, "Delivering pointer " + qev + " to " + target);
}
-
+
if (MEASURE_LATENCY) {
lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
}
@@ -5126,7 +5225,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
- Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
+ Slog.i(TAG, "WINDOW DIED during motion dispatch: " + target);
mKeyWaiter.mMotionTarget = null;
try {
removeWindow(target.mSession, target.mClient);
@@ -5142,13 +5241,13 @@ public class WindowManagerService extends IWindowManager.Stub
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
ev, false, false, pid, uid);
if (focusObj == null) {
- Log.w(TAG, "No focus window, dropping trackball: " + ev);
+ Slog.w(TAG, "No focus window, dropping trackball: " + ev);
if (qev != null) {
mQueue.recycleEvent(qev);
}
@@ -5169,7 +5268,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mContext.checkPermission(
android.Manifest.permission.INJECT_EVENTS, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission denied: injecting key event from pid "
+ Slog.w(TAG, "Permission denied: injecting key event from pid "
+ pid + " uid " + uid + " to window " + focus
+ " owned by uid " + focus.mSession.mUid);
if (qev != null) {
@@ -5198,7 +5297,7 @@ public class WindowManagerService extends IWindowManager.Stub
focus.mClient.dispatchTrackball(ev, eventTime, true);
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
- Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
+ Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
try {
removeWindow(focus.mSession, focus.mClient);
} catch (java.util.NoSuchElementException ex) {
@@ -5214,12 +5313,12 @@ public class WindowManagerService extends IWindowManager.Stub
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
private int dispatchKey(KeyEvent event, int pid, int uid) {
- if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
+ if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
null, false, false, pid, uid);
if (focusObj == null) {
- Log.w(TAG, "No focus window, dropping: " + event);
+ Slog.w(TAG, "No focus window, dropping: " + event);
return INJECT_FAILED;
}
if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
@@ -5235,17 +5334,17 @@ public class WindowManagerService extends IWindowManager.Stub
if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
return INJECT_SUCCEEDED;
}
-
+
WindowState focus = (WindowState)focusObj;
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.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 "
+ Slog.w(TAG, "Permission denied: injecting key event from pid "
+ pid + " uid " + uid + " to window " + focus
+ " owned by uid " + focus.mSession.mUid);
return INJECT_NO_PERMISSION;
@@ -5262,13 +5361,13 @@ public class WindowManagerService extends IWindowManager.Stub
try {
if (DEBUG_INPUT || DEBUG_FOCUS) {
- Log.v(TAG, "Delivering key " + event.getKeyCode()
+ Slog.v(TAG, "Delivering key " + event.getKeyCode()
+ " to " + focus);
}
focus.mClient.dispatchKey(event);
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
- Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
+ Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
try {
removeWindow(focus.mSession, focus.mClient);
} catch (java.util.NoSuchElementException ex) {
@@ -5465,7 +5564,6 @@ public class WindowManagerService extends IWindowManager.Stub
curFocus = mCurrentFocus;
// cache the paused state at ctor time as well
if (theFocus == null || theFocus.mToken == null) {
- Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
focusPaused = false;
} else {
focusPaused = theFocus.mToken.paused;
@@ -5478,7 +5576,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ " fin=" + finished + " gfw=" + gotFirstWindow
+ " ed=" + eventDispatching + " tts=" + timeToSwitch
+ " wf=" + wasFrozen + " fp=" + focusPaused
- + " mcf=" + mCurrentFocus + "}}";
+ + " mcf=" + curFocus + "}}";
}
};
private DispatchState mDispatchState = null;
@@ -5529,7 +5627,7 @@ public class WindowManagerService extends IWindowManager.Stub
// it may change before we lock. Thus we must check it again.
WindowState targetWin = mLastWin;
boolean targetIsNew = targetWin == null;
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "waitForLastKey: mFinished=" + mFinished +
", mLastWin=" + mLastWin);
if (targetIsNew) {
@@ -5538,12 +5636,12 @@ public class WindowManagerService extends IWindowManager.Stub
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
+ if (DEBUG_INPUT) Slog.v(TAG, "Skipping: " + nextKey
+ " " + nextMotion);
return null;
}
if (target == CONSUMED_EVENT_TOKEN) {
- if (DEBUG_INPUT) Log.v(TAG, "Consumed: " + nextKey
+ if (DEBUG_INPUT) Slog.v(TAG, "Consumed: " + nextKey
+ " " + nextMotion);
return target;
}
@@ -5567,7 +5665,7 @@ public class WindowManagerService extends IWindowManager.Stub
// If event dispatching is disabled, then we
// just consume the events.
if (!mEventDispatching) {
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"Skipping event; dispatching disabled: "
+ nextKey + " " + nextMotion);
return null;
@@ -5583,14 +5681,14 @@ public class WindowManagerService extends IWindowManager.Stub
// 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,
+ if (DEBUG_INPUT) Slog.v(TAG,
"Skipping event; no focused app: "
+ nextKey + " " + nextMotion);
return null;
}
}
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Waiting for last key in " + mLastBinder
+ " target=" + targetWin
+ " mFinished=" + mFinished
@@ -5611,7 +5709,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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);
+ doFinishedKeyLocked(false);
continue;
}
long switchTimeout = mTimeToSwitch - now;
@@ -5623,10 +5721,10 @@ public class WindowManagerService extends IWindowManager.Stub
try {
// after that continue
// processing keys, so we don't get stuck.
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Waiting for key dispatch: " + curTimeout);
wait(curTimeout);
- if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
+ if (DEBUG_INPUT) Slog.v(TAG, "Finished waiting @"
+ SystemClock.uptimeMillis() + " startTime="
+ startTime + " switchTime=" + mTimeToSwitch
+ " target=" + targetWin + " mLW=" + mLastWin
@@ -5649,12 +5747,13 @@ public class WindowManagerService extends IWindowManager.Stub
if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
IApplicationToken at = null;
synchronized (this) {
- Log.w(TAG, "Key dispatching timed out sending to " +
+ Slog.w(TAG, "Key dispatching timed out sending to " +
(targetWin != null ? targetWin.mAttrs.getTitle()
- : "<null>"));
+ : "<null>: no window ready for key dispatch"));
// NOSHIP debugging
- Log.w(TAG, "Dispatch state: " + mDispatchState);
- Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
+ Slog.w(TAG, "Previous dispatch state: " + mDispatchState);
+ Slog.w(TAG, "Current dispatch state: " +
+ new DispatchState(nextKey, targetWin));
// END NOSHIP
//dump();
if (targetWin != null) {
@@ -5684,11 +5783,11 @@ public class WindowManagerService extends IWindowManager.Stub
if (abort && (mLastWin == targetWin || targetWin == null)) {
mFinished = true;
if (mLastWin != null) {
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"Window " + mLastWin +
" timed out on key input");
if (mLastWin.mToken.paused) {
- Log.w(TAG, "Un-pausing dispatching to this window");
+ Slog.w(TAG, "Un-pausing dispatching to this window");
mLastWin.mToken.paused = false;
}
}
@@ -5701,7 +5800,7 @@ public class WindowManagerService extends IWindowManager.Stub
return null;
}
} else {
- Log.w(TAG, "Continuing to wait for key to be dispatched");
+ Slog.w(TAG, "Continuing to wait for key to be dispatched");
startTime = SystemClock.uptimeMillis();
}
}
@@ -5720,7 +5819,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int repeatCount = nextKey.getRepeatCount();
final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
-
+
if (!dispatch) {
if (callingUid == 0 ||
mContext.checkPermission(
@@ -5731,7 +5830,7 @@ public class WindowManagerService extends IWindowManager.Stub
nextKey.getMetaState(), down, repeatCount,
nextKey.getFlags());
}
- Log.w(TAG, "Event timeout during app switch: dropping "
+ Slog.w(TAG, "Event timeout during app switch: dropping "
+ nextKey);
return SKIP_TARGET_TOKEN;
}
@@ -5752,7 +5851,7 @@ public class WindowManagerService extends IWindowManager.Stub
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
if (mPolicy.interceptKeyTi(focus,
- keycode, nextKey.getMetaState(), down, repeatCount,
+ keycode, nextKey.getMetaState(), down, repeatCount,
nextKey.getFlags())) {
return CONSUMED_EVENT_TOKEN;
}
@@ -5763,7 +5862,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (!isPointerEvent) {
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
if (!dispatch) {
- Log.w(TAG, "Event timeout during app switch: dropping trackball "
+ Slog.w(TAG, "Event timeout during app switch: dropping trackball "
+ nextMotion);
return SKIP_TARGET_TOKEN;
}
@@ -5784,7 +5883,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
KeyEvent.KEYCODE_UNKNOWN);
if (!dispatch) {
- Log.w(TAG, "Event timeout during app switch: dropping pointer "
+ Slog.w(TAG, "Event timeout during app switch: dropping pointer "
+ nextMotion);
return SKIP_TARGET_TOKEN;
}
@@ -5808,7 +5907,7 @@ public class WindowManagerService extends IWindowManager.Stub
// already down!
// XXX: We should probably send an ACTION_UP to the current
// target.
- Log.w(TAG, "Pointer down received while already down in: "
+ Slog.w(TAG, "Pointer down received while already down in: "
+ mMotionTarget);
mMotionTarget = null;
}
@@ -5824,7 +5923,7 @@ public class WindowManagerService extends IWindowManager.Stub
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);
+ //Slog.i(TAG, "Checking dispatch to: " + child);
final int flags = child.mAttrs.flags;
if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
if (topErrWindow == null) {
@@ -5832,11 +5931,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
if (!child.isVisibleLw()) {
- //Log.i(TAG, "Not visible!");
+ //Slog.i(TAG, "Not visible!");
continue;
}
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
- //Log.i(TAG, "Not touchable!");
+ //Slog.i(TAG, "Not touchable!");
if ((flags & WindowManager.LayoutParams
.FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
child.mNextOutsideTouch = mOutsideTouchTargets;
@@ -5868,12 +5967,12 @@ public class WindowManagerService extends IWindowManager.Stub
(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
if (tmpRect.contains(x, y) || touchFlags == 0) {
- //Log.i(TAG, "Using this target!");
+ //Slog.i(TAG, "Using this target!");
if (!screenWasOff || (flags &
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
mMotionTarget = child;
} else {
- //Log.i(TAG, "Waking, skip!");
+ //Slog.i(TAG, "Waking, skip!");
mMotionTarget = null;
}
break;
@@ -5883,7 +5982,7 @@ public class WindowManagerService extends IWindowManager.Stub
.FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
child.mNextOutsideTouch = mOutsideTouchTargets;
mOutsideTouchTargets = child;
- //Log.i(TAG, "Adding to outside target list: " + child);
+ //Slog.i(TAG, "Adding to outside target list: " + child);
}
}
@@ -5945,7 +6044,7 @@ public class WindowManagerService extends IWindowManager.Stub
releasePendingPointerLocked(s);
s.mPendingPointerMove = pendingMotion;
s.mPendingPointerWindow = win;
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"bindTargetToWindow " + s.mPendingPointerMove);
} else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
releasePendingTrackballLocked(s);
@@ -5956,7 +6055,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void releasePendingPointerLocked(Session s) {
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"releasePendingPointer " + s.mPendingPointerMove);
if (s.mPendingPointerMove != null) {
mQueue.recycleEvent(s.mPendingPointerMove);
@@ -5973,7 +6072,7 @@ public class WindowManagerService extends IWindowManager.Stub
MotionEvent finishedKey(Session session, IWindow client, boolean force,
int returnWhat) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "finishedKey: client=" + client + ", force=" + force);
if (client == null) {
@@ -5983,9 +6082,9 @@ public class WindowManagerService extends IWindowManager.Stub
MotionEvent res = null;
QueuedEvent qev = null;
WindowState win = null;
-
+
synchronized (this) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "finishedKey: client=" + client.asBinder()
+ ", force=" + force + ", last=" + mLastBinder
+ " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
@@ -6003,12 +6102,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (mLastBinder == client.asBinder()) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "finishedKey: last paused="
+ ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
if (mLastWin != null && (!mLastWin.mToken.paused || force
|| !mEventDispatching)) {
- doFinishedKeyLocked(false);
+ doFinishedKeyLocked(true);
} else {
// Make sure to wake up anyone currently waiting to
// dispatch a key, so they can re-evaluate their
@@ -6020,7 +6119,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (qev != null) {
res = (MotionEvent)qev.event;
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"Returning pending motion: " + res);
mQueue.recycleEvent(qev);
if (win != null && returnWhat == RETURN_PENDING_POINTER) {
@@ -6031,11 +6130,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (res != null && returnWhat == RETURN_PENDING_POINTER) {
synchronized (mWindowMap) {
- if ((mWallpaperTarget == win &&
- win.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD)
- || mSendingPointersToWallpaper) {
- sendPointerToWallpaperLocked(win, res, res.getEventTime());
- }
+ dispatchPointerElsewhereLocked(win, win, res, res.getEventTime(), false);
}
}
@@ -6053,7 +6148,7 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
synchronized (this) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "New key dispatch window: win="
+ newWindow.mClient.asBinder()
+ ", last=" + mLastBinder
@@ -6069,7 +6164,7 @@ public class WindowManagerService extends IWindowManager.Stub
mGotFirstWindow = true;
if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Slog.v(TAG,
"New SYSTEM_ERROR window; resetting state");
mLastWin = null;
mLastBinder = null;
@@ -6079,20 +6174,16 @@ public class WindowManagerService extends IWindowManager.Stub
// 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(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Last win layer=" + mLastWin.mLayer
+ ", new win layer=" + newWindow.mLayer);
if (newWindow.mLayer >= mLastWin.mLayer) {
// The new window is above the old; finish pending input to the last
// window and start directing it to the new one.
mLastWin.mToken.paused = false;
- doFinishedKeyLocked(true); // does a notifyAll()
+ doFinishedKeyLocked(false); // does a notifyAll()
+ return;
}
- // Either the new window is lower, so there is no need to wake key waiters,
- // or we just finished key input to the previous window, which implicitly
- // notified the key waiters. In both cases, we don't need to issue the
- // notification here.
- return;
}
// Now that we've put a new window state in place, make the event waiter
@@ -6104,7 +6195,7 @@ public class WindowManagerService extends IWindowManager.Stub
void pauseDispatchingLocked(WindowToken token) {
synchronized (this)
{
- if (DEBUG_INPUT) Log.v(TAG, "Pausing WindowToken " + token);
+ if (DEBUG_INPUT) Slog.v(TAG, "Pausing WindowToken " + token);
token.paused = true;
/*
@@ -6112,11 +6203,11 @@ public class WindowManagerService extends IWindowManager.Stub
mPaused = true;
} else {
if (mLastWin == null) {
- Log.i(TAG, "Key dispatching not paused: no last window.");
+ Slog.i(TAG, "Key dispatching not paused: no last window.");
} else if (mFinished) {
- Log.i(TAG, "Key dispatching not paused: finished last key.");
+ Slog.i(TAG, "Key dispatching not paused: finished last key.");
} else {
- Log.i(TAG, "Key dispatching not paused: window in higher layer.");
+ Slog.i(TAG, "Key dispatching not paused: window in higher layer.");
}
}
*/
@@ -6126,7 +6217,7 @@ public class WindowManagerService extends IWindowManager.Stub
void resumeDispatchingLocked(WindowToken token) {
synchronized (this) {
if (token.paused) {
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Resuming WindowToken " + token
+ ", last=" + mLastBinder
+ " (token=" + (mLastWin != null ? mLastWin.mToken : null)
@@ -6134,7 +6225,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ token.paused);
token.paused = false;
if (mLastWin != null && mLastWin.mToken == token && mFinished) {
- doFinishedKeyLocked(true);
+ doFinishedKeyLocked(false);
} else {
notifyAll();
}
@@ -6154,7 +6245,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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 (DEBUG_INPUT) Slog.v(TAG, "appSwitchComing: " + now);
if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
mTimeToSwitch = now;
}
@@ -6162,14 +6253,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private final void doFinishedKeyLocked(boolean doRecycle) {
+ private final void doFinishedKeyLocked(boolean force) {
if (mLastWin != null) {
releasePendingPointerLocked(mLastWin.mSession);
releasePendingTrackballLocked(mLastWin.mSession);
}
- if (mLastWin == null || !mLastWin.mToken.paused
- || !mLastWin.isVisibleLw()) {
+ if (force || 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;
@@ -6254,7 +6345,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (screenIsOff) {
if (!mPolicy.isWakeRelMovementTq(event.deviceId,
device.classes, event)) {
- //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
+ //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
return false;
}
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
@@ -6271,7 +6362,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (screenIsOff) {
if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
device.classes, event)) {
- //Log.i(TAG, "dropping because screenIsOff and !isWakeKey");
+ //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
return false;
}
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
@@ -6292,7 +6383,7 @@ public class WindowManagerService extends IWindowManager.Stub
case RawInputEvent.CLASS_KEYBOARD:
KeyEvent ke = (KeyEvent)ev.event;
if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
- Log.w(TAG, "Dropping movement key during app switch: "
+ Slog.w(TAG, "Dropping movement key during app switch: "
+ ke.getKeyCode() + ", action=" + ke.getAction());
return FILTER_REMOVE;
}
@@ -6341,7 +6432,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
process();
} catch (Exception e) {
- Log.e(TAG, "Exception in input dispatcher", e);
+ Slog.e(TAG, "Exception in input dispatcher", e);
}
}
}
@@ -6367,7 +6458,7 @@ public class WindowManagerService extends IWindowManager.Stub
while (true) {
long curTime = SystemClock.uptimeMillis();
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Waiting for next key: now=" + curTime
+ ", repeat @ " + nextKeyTime);
@@ -6379,7 +6470,7 @@ public class WindowManagerService extends IWindowManager.Stub
(int)((!configChanged && curTime < nextKeyTime)
? (nextKeyTime-curTime) : 0));
- if (DEBUG_INPUT && ev != null) Log.v(
+ if (DEBUG_INPUT && ev != null) Slog.v(
TAG, "Event: type=" + ev.classType + " data=" + ev.event);
if (MEASURE_LATENCY) {
@@ -6441,7 +6532,7 @@ public class WindowManagerService extends IWindowManager.Stub
lastKeyTime = curTime;
nextKeyTime = lastKeyTime
+ ViewConfiguration.getLongPressTimeout();
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Received key down: first repeat @ "
+ nextKeyTime);
} else {
@@ -6450,7 +6541,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Arbitrary long timeout.
lastKeyTime = curTime;
nextKeyTime = curTime + LONG_WAIT;
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Received key up: ignore repeat @ "
+ nextKeyTime);
}
@@ -6458,7 +6549,7 @@ public class WindowManagerService extends IWindowManager.Stub
mQueue.recycleEvent(ev);
break;
case RawInputEvent.CLASS_TOUCHSCREEN:
- //Log.i(TAG, "Read next event " + ev);
+ //Slog.i(TAG, "Read next event " + ev);
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
break;
case RawInputEvent.CLASS_TRACKBALL:
@@ -6481,7 +6572,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Timeout occurred while key was down. If it is at or
// past the key repeat time, dispatch the repeat.
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Key timeout: repeat=" + nextKeyTime
+ ", now=" + curTime);
if (curTime < nextKeyTime) {
@@ -6491,7 +6582,7 @@ public class WindowManagerService extends IWindowManager.Stub
lastKeyTime = nextKeyTime;
nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
keyRepeatCount++;
- if (DEBUG_INPUT) Log.v(
+ if (DEBUG_INPUT) Slog.v(
TAG, "Key repeat: count=" + keyRepeatCount
+ ", next @ " + nextKeyTime);
KeyEvent newEvent;
@@ -6516,7 +6607,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
} catch (Exception e) {
- Log.e(TAG,
+ Slog.e(TAG,
"Input thread received uncaught exception: " + e, e);
}
}
@@ -6604,7 +6695,7 @@ public class WindowManagerService extends IWindowManager.Stub
} catch (RuntimeException e) {
// Log all 'real' exceptions thrown to the caller
if (!(e instanceof SecurityException)) {
- Log.e(TAG, "Window Session Crash", e);
+ Slog.e(TAG, "Window Session Crash", e);
}
throw e;
}
@@ -6638,10 +6729,10 @@ public class WindowManagerService extends IWindowManager.Stub
public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
boolean insetsPending, Rect outFrame, Rect outContentInsets,
- Rect outVisibleInsets, Surface outSurface) {
+ Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
return relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, insetsPending,
- outFrame, outContentInsets, outVisibleInsets, outSurface);
+ outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface);
}
public void setTransparentRegion(IWindow window, Region region) {
@@ -6659,27 +6750,27 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void finishDrawing(IWindow window) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "IWindow finishDrawing called for " + window);
finishDrawingWindow(this, window);
}
public void finishKey(IWindow window) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "IWindow finishKey called for " + window);
mKeyWaiter.finishedKey(this, window, false,
KeyWaiter.RETURN_NOTHING);
}
public MotionEvent getPendingPointerMove(IWindow window) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.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(
+ if (localLOGV) Slog.v(
TAG, "IWindow getPendingMotionEvent called for " + window);
return mKeyWaiter.finishedKey(this, window, false,
KeyWaiter.RETURN_PENDING_TRACKBALL);
@@ -6703,7 +6794,8 @@ public class WindowManagerService extends IWindowManager.Stub
long ident = Binder.clearCallingIdentity();
try {
return mPolicy.performHapticFeedbackLw(
- windowForClientLocked(this, window), effectId, always);
+ windowForClientLocked(this, window, true),
+ effectId, always);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6714,42 +6806,43 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+ setWindowWallpaperPositionLocked(
+ windowForClientLocked(this, window, true),
x, y, xStep, yStep);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
-
+
public void wallpaperOffsetsComplete(IBinder window) {
WindowManagerService.this.wallpaperOffsetsComplete(window);
}
-
+
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
return sendWindowWallpaperCommandLocked(
- windowForClientLocked(this, window),
+ windowForClientLocked(this, window, true),
action, x, y, z, extras, sync);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
-
+
public void wallpaperCommandComplete(IBinder window, Bundle result) {
WindowManagerService.this.wallpaperCommandComplete(window, result);
}
-
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "First window added to " + this + ", creating SurfaceSession");
mSurfaceSession = new SurfaceSession();
- if (SHOW_TRANSACTIONS) Log.i(
+ if (SHOW_TRANSACTIONS) Slog.i(
TAG, " NEW SURFACE SESSION " + mSurfaceSession);
mSessions.add(this);
}
@@ -6765,15 +6858,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (mNumWindow <= 0 && mClientDead) {
mSessions.remove(this);
if (mSurfaceSession != null) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Last window removed from " + this
+ ", destroying " + mSurfaceSession);
- if (SHOW_TRANSACTIONS) Log.i(
+ if (SHOW_TRANSACTIONS) Slog.i(
TAG, " KILL SURFACE SESSION " + mSurfaceSession);
try {
mSurfaceSession.kill();
} catch (Exception e) {
- Log.w(TAG, "Exception thrown when killing surface session "
+ Slog.w(TAG, "Exception thrown when killing surface session "
+ mSurfaceSession + " in session " + this
+ ": " + e.toString());
}
@@ -6848,11 +6941,21 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState mNextOutsideTouch;
+ int mLayoutSeq = -1;
+
+ Configuration mConfiguration = null;
+
// Actual frame shown on-screen (may be modified by animation)
final Rect mShownFrame = new Rect();
final Rect mLastShownFrame = new Rect();
/**
+ * Set when we have changed the size of the surface, to know that
+ * we must tell them application to resize (and thus redraw itself).
+ */
+ boolean mSurfaceResized;
+
+ /**
* Insets that determine the actually visible area
*/
final Rect mVisibleInsets = new Rect();
@@ -6938,7 +7041,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Wallpaper windows: pixels offset based on above variables.
int mXOffset;
int mYOffset;
-
+
// 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
@@ -6979,6 +7082,12 @@ public class WindowManagerService extends IWindowManager.Stub
// Is this window now (or just being) removed?
boolean mRemoved;
+ // For debugging, this is the last information given to the surface flinger.
+ boolean mSurfaceShown;
+ int mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH;
+ int mSurfaceLayer;
+ float mSurfaceAlpha;
+
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
@@ -6989,7 +7098,7 @@ public class WindowManagerService extends IWindowManager.Stub
mViewVisibility = viewVisibility;
DeathRecipient deathRecipient = new DeathRecipient();
mAlpha = a.alpha;
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")");
try {
@@ -7066,7 +7175,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void attach() {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
@@ -7096,8 +7205,8 @@ public class WindowManagerService extends IWindowManager.Stub
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;
+ w = mAttrs.width == mAttrs.MATCH_PARENT ? pw : mRequestedWidth;
+ h = mAttrs.height== mAttrs.MATCH_PARENT ? ph : mRequestedHeight;
}
final Rect content = mContentFrame;
@@ -7121,7 +7230,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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;
@@ -7149,11 +7258,11 @@ public class WindowManagerService extends IWindowManager.Stub
updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
mDisplay.getHeight(), false);
}
-
+
if (localLOGV) {
//if ("com.google.android.youtube".equals(mAttrs.packageName)
// && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- Log.v(TAG, "Resolving (mRequestedWidth="
+ Slog.v(TAG, "Resolving (mRequestedWidth="
+ mRequestedWidth + ", mRequestedheight="
+ mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
+ "): frame=" + mFrame.toShortString()
@@ -7211,16 +7320,8 @@ public class WindowManagerService extends IWindowManager.Stub
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(
+ if (localLOGV) Slog.v(
TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
mLocalAnimating = false;
@@ -7256,7 +7357,7 @@ public class WindowManagerService extends IWindowManager.Stub
if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
flags |= Surface.SECURE;
}
- if (DEBUG_VISIBILITY) Log.v(
+ if (DEBUG_VISIBILITY) Slog.v(
TAG, "Creating surface in session "
+ mSession.mSurfaceSession + " window " + this
+ " w=" + mFrame.width()
@@ -7277,60 +7378,70 @@ public class WindowManagerService extends IWindowManager.Stub
if (w <= 0) w = 1;
if (h <= 0) h = 1;
+ mSurfaceShown = false;
+ mSurfaceLayer = 0;
+ mSurfaceAlpha = 1;
+ mSurfaceX = 0;
+ mSurfaceY = 0;
+ mSurfaceW = w;
+ mSurfaceH = h;
try {
mSurface = new Surface(
mSession.mSurfaceSession, mSession.mPid,
+ mAttrs.getTitle().toString(),
0, w, h, mAttrs.format, flags);
- if (SHOW_TRANSACTIONS) Log.i(TAG, " CREATE SURFACE "
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " CREATE SURFACE "
+ mSurface + " IN SESSION "
+ mSession.mSurfaceSession
+ ": pid=" + mSession.mPid + " format="
+ mAttrs.format + " flags=0x"
- + Integer.toHexString(flags));
+ + Integer.toHexString(flags)
+ + " / " + this);
} catch (Surface.OutOfResourcesException e) {
- Log.w(TAG, "OutOfResourcesException creating surface");
+ Slog.w(TAG, "OutOfResourcesException creating surface");
reclaimSomeSurfaceMemoryLocked(this, "create");
return null;
} catch (Exception e) {
- Log.e(TAG, "Exception creating surface", e);
+ Slog.e(TAG, "Exception creating surface", e);
return null;
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.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");
+ Slog.i(TAG, ">>> OPEN TRANSACTION");
+ if (SHOW_TRANSACTIONS) logSurface(this,
+ "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" +
+ mFrame.width() + "x" + mFrame.height() + "), layer=" +
+ mAnimLayer + " HIDE", null);
}
Surface.openTransaction();
try {
try {
- mSurface.setPosition(mFrame.left + mXOffset,
- mFrame.top + mYOffset);
+ mSurfaceX = mFrame.left + mXOffset;
+ mSurfaceY = mFrame.top + mYOffset;
+ mSurface.setPosition(mSurfaceX, mSurfaceY);
+ mSurfaceLayer = mAnimLayer;
mSurface.setLayer(mAnimLayer);
+ mSurfaceShown = false;
mSurface.hide();
if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " SURFACE "
- + mSurface + ": DITHER");
+ if (SHOW_TRANSACTIONS) logSurface(this, "DITHER", null);
mSurface.setFlags(Surface.SURFACE_DITHER,
Surface.SURFACE_DITHER);
}
} catch (RuntimeException e) {
- Log.w(TAG, "Error creating surface in " + w, e);
+ Slog.w(TAG, "Error creating surface in " + w, e);
reclaimSomeSurfaceMemoryLocked(this, "create-init");
}
mLastHidden = true;
} finally {
- if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION");
Surface.closeTransaction();
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Created surface " + this);
}
return mSurface;
@@ -7360,7 +7471,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState c = (WindowState)mChildWindows.get(i);
c.mAttachedHidden = true;
}
-
+
if (mReportDestroySurface) {
mReportDestroySurface = false;
mSurfacePendingDestroy = true;
@@ -7371,34 +7482,40 @@ public class WindowManagerService extends IWindowManager.Stub
} catch (RemoteException e) {
}
}
-
+
try {
if (DEBUG_VISIBILITY) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.w(TAG, "Window " + this + " destroying surface "
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.w(TAG, "Window " + this + " destroying surface "
+ mSurface + ", session " + mSession, e);
}
if (SHOW_TRANSACTIONS) {
- RuntimeException ex = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) ex.fillInStackTrace();
- Log.i(TAG, " SURFACE " + mSurface + ": DESTROY ("
- + mAttrs.getTitle() + ")", ex);
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ if (SHOW_TRANSACTIONS) logSurface(this, "DESTROY", e);
}
mSurface.destroy();
} catch (RuntimeException e) {
- Log.w(TAG, "Exception thrown when destroying Window " + this
+ Slog.w(TAG, "Exception thrown when destroying Window " + this
+ " surface " + mSurface + " session " + mSession
+ ": " + e.toString());
}
-
+
+ mSurfaceShown = false;
mSurface = null;
}
}
boolean finishDrawingLocked() {
if (mDrawPending) {
- if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Log.v(
+ if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(
TAG, "finishDrawingLocked: " + mSurface);
mCommitDrawPending = true;
mDrawPending = false;
@@ -7409,7 +7526,7 @@ public class WindowManagerService extends IWindowManager.Stub
// This must be called while inside a transaction.
boolean commitFinishDrawingLocked(long currentTime) {
- //Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
+ //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface);
if (!mCommitDrawPending) {
return false;
}
@@ -7426,16 +7543,19 @@ public class WindowManagerService extends IWindowManager.Stub
// This must be called while inside a transaction.
boolean performShowLocked() {
if (DEBUG_VISIBILITY) {
- RuntimeException e = new RuntimeException();
- if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
- Log.v(TAG, "performShow on " + this
+ RuntimeException e = null;
+ if (!HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.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
+ if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) logSurface(this,
+ "SHOW (performShowLocked)", null);
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
+ " during animation: policyVis=" + mPolicyVisibility
+ " attHidden=" + mAttachedHidden
+ " tok.hiddenRequested="
@@ -7460,24 +7580,26 @@ public class WindowManagerService extends IWindowManager.Stub
while (i > 0) {
i--;
WindowState c = (WindowState)mChildWindows.get(i);
- if (c.mSurface != null && c.mAttachedHidden) {
+ if (c.mAttachedHidden) {
c.mAttachedHidden = false;
- c.performShowLocked();
- // It hadn't been shown, which means layout not
- // performed on it, so now we want to make sure to
- // do a layout. If called from within the transaction
- // loop, this will cause it to restart with a new
- // layout.
- mLayoutNeeded = true;
+ if (c.mSurface != null) {
+ c.performShowLocked();
+ // It hadn't been shown, which means layout not
+ // performed on it, so now we want to make sure to
+ // do a layout. If called from within the transaction
+ // loop, this will cause it to restart with a new
+ // layout.
+ mLayoutNeeded = true;
+ }
}
}
if (mAttrs.type != TYPE_APPLICATION_STARTING
&& mAppToken != null) {
mAppToken.firstWindowDrawn = true;
-
+
if (mAppToken.startingData != null) {
- if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Log.v(TAG,
+ if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG,
"Finish starting " + mToken
+ ": first real window is shown, no animation");
// If this initial window is animating, stop it -- we
@@ -7501,14 +7623,14 @@ public class WindowManagerService extends IWindowManager.Stub
// 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) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()) {
// 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(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Starting animation in " + this +
" @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
" dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
@@ -7520,14 +7642,14 @@ public class WindowManagerService extends IWindowManager.Stub
mTransformation.clear();
final boolean more = mAnimation.getTransformation(
currentTime, mTransformation);
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Stepped animation in " + this +
": more=" + more + ", xform=" + mTransformation);
if (more) {
// we're not done!
return true;
}
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Finished animation in " + this +
" @ " + currentTime);
mAnimation = null;
@@ -7566,7 +7688,7 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Animation done in " + this + ": exiting=" + mExiting
+ ", reportedVisible="
+ (mAppToken != null ? mAppToken.reportedVisible : false));
@@ -7580,16 +7702,25 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (mIsWallpaper) {
mAnimLayer += mWallpaperAnimLayerAdjustment;
}
- if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
+ if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this
+ " anim layer: " + mAnimLayer);
mHasTransformation = false;
mHasLocalTransformation = false;
- mPolicyVisibility = mPolicyVisibilityAfterAnim;
- if (!mPolicyVisibility) {
- // Window is no longer visible -- make sure if we were waiting
- // for it to be displayed before enabling the display, that
- // we allow the display to be enabled now.
- enableScreenIfNeededLocked();
+ if (mPolicyVisibility != mPolicyVisibilityAfterAnim) {
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG, "Policy visibility changing after anim in " + this + ": "
+ + mPolicyVisibilityAfterAnim);
+ }
+ mPolicyVisibility = mPolicyVisibilityAfterAnim;
+ if (!mPolicyVisibility) {
+ if (mCurrentFocus == this) {
+ mFocusMayChange = true;
+ }
+ // Window is no longer visible -- make sure if we were waiting
+ // for it to be displayed before enabling the display, that
+ // we allow the display to be enabled now.
+ enableScreenIfNeededLocked();
+ }
}
mTransformation.clear();
if (mHasDrawn
@@ -7597,7 +7728,7 @@ public class WindowManagerService extends IWindowManager.Stub
&& mAppToken != null
&& mAppToken.firstWindowDrawn
&& mAppToken.startingData != null) {
- if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting "
+ mToken + ": first real window done animating");
mFinishedStarting.add(mAppToken);
mH.sendEmptyMessage(H.FINISHED_STARTING);
@@ -7613,7 +7744,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void finishExit() {
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "finishExit in " + this
+ ": exiting=" + mExiting
+ " remove=" + mRemoveOnExit
@@ -7632,18 +7763,18 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.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)");
+ if (SHOW_TRANSACTIONS) logSurface(this, "HIDE (finishExit)", null);
+ mSurfaceShown = false;
try {
mSurface.hide();
} catch (RuntimeException e) {
- Log.w(TAG, "Error hiding surface in " + this, e);
+ Slog.w(TAG, "Error hiding surface in " + this, e);
}
mLastHidden = true;
mKeyWaiter.releasePendingPointerLocked(mSession);
@@ -7671,7 +7802,7 @@ public class WindowManagerService extends IWindowManager.Stub
Transformation appTransformation =
(mAppToken != null && mAppToken.hasTransformation)
? mAppToken.transformation : null;
-
+
// Wallpapers are animated based on the "real" window they
// are currently targeting.
if (mAttrs.type == TYPE_WALLPAPER && mLowerWallpaperTarget == null
@@ -7681,7 +7812,7 @@ public class WindowManagerService extends IWindowManager.Stub
!mWallpaperTarget.mAnimation.getDetachWallpaper()) {
attachedTransformation = mWallpaperTarget.mTransformation;
if (DEBUG_WALLPAPER && attachedTransformation != null) {
- Log.v(TAG, "WP target attached xform: " + attachedTransformation);
+ Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
}
}
if (mWallpaperTarget.mAppToken != null &&
@@ -7690,11 +7821,11 @@ public class WindowManagerService extends IWindowManager.Stub
!mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) {
appTransformation = mWallpaperTarget.mAppToken.transformation;
if (DEBUG_WALLPAPER && appTransformation != null) {
- Log.v(TAG, "WP target app xform: " + appTransformation);
+ Slog.v(TAG, "WP target app xform: " + appTransformation);
}
}
}
-
+
if (selfTransformation || attachedTransformation != null
|| appTransformation != null) {
// cache often used attributes locally
@@ -7719,7 +7850,7 @@ public class WindowManagerService extends IWindowManager.Stub
// (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);
+ //Slog.i(TAG, "Transform: " + matrix);
tmpMatrix.getValues(tmpFloats);
mDsDx = tmpFloats[Matrix.MSCALE_X];
@@ -7742,7 +7873,7 @@ public class WindowManagerService extends IWindowManager.Stub
|| (!PixelFormat.formatHasAlpha(mAttrs.format)
|| (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
&& x == frame.left && y == frame.top))) {
- //Log.i(TAG, "Applying alpha transform");
+ //Slog.i(TAG, "Applying alpha transform");
if (selfTransformation) {
mShownAlpha *= mTransformation.getAlpha();
}
@@ -7753,10 +7884,10 @@ public class WindowManagerService extends IWindowManager.Stub
mShownAlpha *= appTransformation.getAlpha();
}
} else {
- //Log.i(TAG, "Not applying alpha transform");
+ //Slog.i(TAG, "Not applying alpha transform");
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Continuing animation in " + this +
": " + mShownFrame +
", alpha=" + mTransformation.getAlpha());
@@ -7798,6 +7929,7 @@ public class WindowManagerService extends IWindowManager.Stub
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mAttachedHidden
&& (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
+ && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending))
&& !mExiting && !mDestroying;
}
@@ -7901,12 +8033,14 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Returns true if the window has a surface that it has drawn a
- * complete UI in to.
+ * complete UI in to. Note that this returns true if the orientation
+ * is changing even if the window hasn't redrawn because we don't want
+ * to stop things from executing during that time.
*/
public boolean isDrawnLw() {
final AppWindowToken atoken = mAppToken;
return mSurface != null && !mDestroying
- && !mDrawPending && !mCommitDrawPending;
+ && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
}
public boolean fillsScreenLw(int screenWidth, int screenHeight,
@@ -7984,8 +8118,8 @@ public class WindowManagerService extends IWindowManager.Stub
public void binderDied() {
try {
synchronized(mWindowMap) {
- WindowState win = windowForClientLocked(mSession, mClient);
- Log.i(TAG, "WIN DEATH: " + win);
+ WindowState win = windowForClientLocked(mSession, mClient, false);
+ Slog.i(TAG, "WIN DEATH: " + win);
if (win != null) {
removeWindowLocked(mSession, win);
}
@@ -8016,6 +8150,19 @@ public class WindowManagerService extends IWindowManager.Stub
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
return false;
}
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
+ if (doAnimation) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
+ + mPolicyVisibility + " mAnimation=" + mAnimation);
+ if (mDisplayFrozen || !mPolicy.isScreenOn()) {
+ doAnimation = false;
+ } else if (mPolicyVisibility && mAnimation == null) {
+ // Check for the case where we are currently visible and
+ // not animating; we do not want to do animation at such a
+ // point to become visible when we already are.
+ doAnimation = false;
+ }
+ }
mPolicyVisibility = true;
mPolicyVisibilityAfterAnim = true;
if (doAnimation) {
@@ -8032,6 +8179,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean hideLw(boolean doAnimation, boolean requestAnim) {
+ if (doAnimation) {
+ if (mDisplayFrozen || !mPolicy.isScreenOn()) {
+ doAnimation = false;
+ }
+ }
boolean current = doAnimation ? mPolicyVisibilityAfterAnim
: mPolicyVisibility;
if (!current) {
@@ -8046,12 +8198,16 @@ public class WindowManagerService extends IWindowManager.Stub
if (doAnimation) {
mPolicyVisibilityAfterAnim = false;
} else {
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this);
mPolicyVisibilityAfterAnim = false;
mPolicyVisibility = false;
// Window is no longer visible -- make sure if we were waiting
// for it to be displayed before enabling the display, that
// we allow the display to be enabled now.
enableScreenIfNeededLocked();
+ if (mCurrentFocus == this) {
+ mFocusMayChange = true;
+ }
}
if (requestAnim) {
requestAnimationLocked(0);
@@ -8060,8 +8216,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
void dump(PrintWriter pw, String prefix) {
- StringBuilder sb = new StringBuilder(64);
-
pw.print(prefix); pw.print("mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
@@ -8084,6 +8238,13 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mLastLayer="); pw.println(mLastLayer);
if (mSurface != null) {
pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
+ pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown);
+ pw.print(" layer="); pw.print(mSurfaceLayer);
+ pw.print(" alpha="); pw.print(mSurfaceAlpha);
+ pw.print(" rect=("); pw.print(mSurfaceX);
+ pw.print(","); pw.print(mSurfaceY);
+ pw.print(") "); pw.print(mSurfaceW);
+ pw.print(" x "); pw.println(mSurfaceH);
}
pw.print(prefix); pw.print("mToken="); pw.println(mToken);
pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
@@ -8109,7 +8270,8 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
- pw.print(" h="); pw.println(mRequestedHeight);
+ pw.print(" h="); pw.print(mRequestedHeight);
+ pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
if (mXOffset != 0 || mYOffset != 0) {
pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
pw.print(" y="); pw.println(mYOffset);
@@ -8123,6 +8285,7 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
}
+ pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
pw.print(prefix); pw.print("mShownFrame=");
mShownFrame.printShortString(pw);
pw.print(" last="); mLastShownFrame.printShortString(pw);
@@ -8236,19 +8399,19 @@ public class WindowManagerService extends IWindowManager.Stub
// Set to true when this token is in a pending transaction where it
// will be shown.
boolean waitingToShow;
-
+
// Set to true when this token is in a pending transaction where it
// will be hidden.
boolean waitingToHide;
-
+
// Set to true when this token is in a pending transaction where its
// windows will be put to the bottom of the list.
boolean sendingToBottom;
-
+
// Set to true when this token is in a pending transaction where its
// windows will be put to the top of the list.
boolean sendingToTop;
-
+
WindowToken(IBinder _token, int type, boolean _explicit) {
token = _token;
windowType = type;
@@ -8350,7 +8513,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void setAnimation(Animation anim) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Setting animation in " + this + ": " + anim);
animation = anim;
animating = false;
@@ -8372,7 +8535,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setDummyAnimation() {
if (animation == null) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Setting dummy animation in " + this);
animation = sDummyAnimation;
}
@@ -8391,7 +8554,7 @@ public class WindowManagerService extends IWindowManager.Stub
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 + ": "
+ if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
+ w.mAnimLayer);
if (w == mInputMethodTarget) {
setInputMethodAnimLayerAdjustment(adj);
@@ -8411,7 +8574,7 @@ public class WindowManagerService extends IWindowManager.Stub
continue;
}
try {
- if (DEBUG_VISIBILITY) Log.v(TAG,
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
"Setting visibility of " + win + ": " + (!clientHidden));
win.mClient.dispatchAppVisibility(!clientHidden);
} catch (RemoteException e) {
@@ -8423,7 +8586,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int NW = allAppWindows.size();
for (int i=0; i<NW; i++) {
WindowState w = allAppWindows.get(i);
- if (DEBUG_VISIBILITY) Log.v(TAG,
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
"performing show on: " + w);
w.performShowLocked();
}
@@ -8431,7 +8594,7 @@ public class WindowManagerService extends IWindowManager.Stub
// This must be called while inside a transaction.
boolean stepAnimationLocked(long currentTime, int dw, int dh) {
- if (!mDisplayFrozen) {
+ if (!mDisplayFrozen && mPolicy.isScreenOn()) {
// We will run animations as long as the display isn't frozen.
if (animation == sDummyAnimation) {
@@ -8444,7 +8607,7 @@ public class WindowManagerService extends IWindowManager.Stub
if ((allDrawn || animating || startingDisplayed) && animation != null) {
if (!animating) {
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Starting animation in " + this +
" @ " + currentTime + ": dw=" + dw + " dh=" + dh
+ " scale=" + mTransitionAnimationScale
@@ -8456,7 +8619,7 @@ public class WindowManagerService extends IWindowManager.Stub
transformation.clear();
final boolean more = animation.getTransformation(
currentTime, transformation);
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Stepped animation in " + this +
": more=" + more + ", xform=" + transformation);
if (more) {
@@ -8464,7 +8627,7 @@ public class WindowManagerService extends IWindowManager.Stub
hasTransformation = true;
return true;
}
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Finished animation in " + this +
" @ " + currentTime);
animation = null;
@@ -8488,7 +8651,7 @@ public class WindowManagerService extends IWindowManager.Stub
moveInputMethodWindowsIfNeededLocked(true);
}
- if (DEBUG_ANIM) Log.v(
+ if (DEBUG_ANIM) Slog.v(
TAG, "Animation done in " + this
+ ": reportedVisible=" + reportedVisible);
@@ -8516,20 +8679,21 @@ public class WindowManagerService extends IWindowManager.Stub
int numVisible = 0;
boolean nowGone = true;
- if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
+ if (DEBUG_VISIBILITY) Slog.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
- || win.mAttrs.type == TYPE_APPLICATION_STARTING) {
+ || win.mViewVisibility != View.VISIBLE
+ || win.mAttrs.type == TYPE_APPLICATION_STARTING) {
continue;
}
if (DEBUG_VISIBILITY) {
- Log.v(TAG, "Win " + win + ": isDrawn="
+ Slog.v(TAG, "Win " + win + ": isDrawn="
+ win.isDrawnLw()
+ ", isAnimating=" + win.isAnimating());
if (!win.isDrawnLw()) {
- Log.v(TAG, "Not displayed: s=" + win.mSurface
+ Slog.v(TAG, "Not displayed: s=" + win.mSurface
+ " pv=" + win.mPolicyVisibility
+ " dp=" + win.mDrawPending
+ " cdp=" + win.mCommitDrawPending
@@ -8552,10 +8716,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
- if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
+ numInteresting + " visible=" + numVisible);
if (nowVisible != reportedVisible) {
- if (DEBUG_VISIBILITY) Log.v(
+ if (DEBUG_VISIBILITY) Slog.v(
TAG, "Visibility changed in " + this
+ ": vis=" + nowVisible);
reportedVisible = nowVisible;
@@ -8580,7 +8744,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
return null;
}
-
+
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
@@ -8697,7 +8861,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int FORCE_GC = 15;
public static final int ENABLE_SCREEN = 16;
public static final int APP_FREEZE_TIMEOUT = 17;
- public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
+ public static final int SEND_NEW_CONFIGURATION = 18;
private Session mLastReportedHold;
@@ -8719,11 +8883,11 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
mLastFocus = newFocus;
- //Log.i(TAG, "Focus moving from " + lastFocus
+ //Slog.i(TAG, "Focus moving from " + lastFocus
// + " to " + newFocus);
if (newFocus != null && lastFocus != null
&& !newFocus.isDisplayedLw()) {
- //Log.i(TAG, "Delaying loss of focus...");
+ //Slog.i(TAG, "Delaying loss of focus...");
mLosingFocus.add(lastFocus);
lastFocus = null;
}
@@ -8734,7 +8898,7 @@ public class WindowManagerService extends IWindowManager.Stub
// + " to " + newFocus);
if (newFocus != null) {
try {
- //Log.i(TAG, "Gaining focus: " + newFocus);
+ //Slog.i(TAG, "Gaining focus: " + newFocus);
newFocus.mClient.windowFocusChanged(true, mInTouchMode);
} catch (RemoteException e) {
// Ignore if process has died.
@@ -8743,7 +8907,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (lastFocus != null) {
try {
- //Log.i(TAG, "Losing focus: " + lastFocus);
+ //Slog.i(TAG, "Losing focus: " + lastFocus);
lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
} catch (RemoteException e) {
// Ignore if process has died.
@@ -8763,7 +8927,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int N = losers.size();
for (int i=0; i<N; i++) {
try {
- //Log.i(TAG, "Losing delayed focus: " + losers.get(i));
+ //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
} catch (RemoteException e) {
// Ignore if process has died.
@@ -8787,7 +8951,7 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
+ wtoken + ": pkg=" + sd.pkg);
View view = null;
@@ -8797,7 +8961,7 @@ public class WindowManagerService extends IWindowManager.Stub
sd.theme, sd.nonLocalizedLabel, sd.labelRes,
sd.icon);
} catch (Exception e) {
- Log.w(TAG, "Exception when adding starting window", e);
+ Slog.w(TAG, "Exception when adding starting window", e);
}
if (view != null) {
@@ -8808,7 +8972,7 @@ public class WindowManagerService extends IWindowManager.Stub
// If the window was successfully added, then
// we need to remove it.
if (wtoken.startingWindow != null) {
- if (DEBUG_STARTING_WINDOW) Log.v(TAG,
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
"Aborted starting " + wtoken
+ ": removed=" + wtoken.removed
+ " startingData=" + wtoken.startingData);
@@ -8819,7 +8983,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
wtoken.startingView = view;
}
- if (DEBUG_STARTING_WINDOW && !abort) Log.v(TAG,
+ if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
"Added starting " + wtoken
+ ": startingWindow="
+ wtoken.startingWindow + " startingView="
@@ -8830,7 +8994,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
mPolicy.removeStartingWindow(wtoken.token, view);
} catch (Exception e) {
- Log.w(TAG, "Exception when removing starting window", e);
+ Slog.w(TAG, "Exception when removing starting window", e);
}
}
}
@@ -8841,7 +9005,7 @@ public class WindowManagerService extends IWindowManager.Stub
IBinder token = null;
View view = null;
synchronized (mWindowMap) {
- if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Remove starting "
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
+ wtoken + ": startingWindow="
+ wtoken.startingWindow + " startingView="
+ wtoken.startingView);
@@ -8857,7 +9021,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
mPolicy.removeStartingWindow(token, view);
} catch (Exception e) {
- Log.w(TAG, "Exception when removing starting window", e);
+ Slog.w(TAG, "Exception when removing starting window", e);
}
}
} break;
@@ -8873,7 +9037,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
AppWindowToken wtoken = mFinishedStarting.remove(N-1);
- if (DEBUG_STARTING_WINDOW) Log.v(TAG,
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
"Finished starting " + wtoken
+ ": startingWindow=" + wtoken.startingWindow
+ " startingView=" + wtoken.startingView);
@@ -8892,7 +9056,7 @@ public class WindowManagerService extends IWindowManager.Stub
try {
mPolicy.removeStartingWindow(token, view);
} catch (Exception e) {
- Log.w(TAG, "Exception when removing starting window", e);
+ Slog.w(TAG, "Exception when removing starting window", e);
}
}
} break;
@@ -8904,7 +9068,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean nowGone = msg.arg2 != 0;
try {
- if (DEBUG_VISIBILITY) Log.v(
+ if (DEBUG_VISIBILITY) Slog.v(
TAG, "Reporting visible in " + wtoken
+ " visible=" + nowVisible
+ " gone=" + nowGone);
@@ -8919,14 +9083,14 @@ public class WindowManagerService extends IWindowManager.Stub
case WINDOW_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
- Log.w(TAG, "Window freeze timeout expired.");
+ Slog.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);
+ Slog.w(TAG, "Force clearing orientation change: " + w);
}
}
performLayoutAndPlaceSurfacesLocked();
@@ -8964,7 +9128,7 @@ public class WindowManagerService extends IWindowManager.Stub
case APP_TRANSITION_TIMEOUT: {
synchronized (mWindowMap) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"*** APP TRANSITION TIMEOUT");
mAppTransitionReady = true;
mAppTransitionTimeout = true;
@@ -9009,13 +9173,13 @@ public class WindowManagerService extends IWindowManager.Stub
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
- Log.w(TAG, "App freeze timeout expired.");
+ Slog.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);
+ Slog.w(TAG, "Force clearing freeze: " + tok);
unsetAppFreezingScreenLocked(tok, true, true);
}
}
@@ -9023,10 +9187,9 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
- case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
- if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
- sendNewConfiguration();
- }
+ case SEND_NEW_CONFIGURATION: {
+ removeMessages(SEND_NEW_CONFIGURATION);
+ sendNewConfiguration();
break;
}
@@ -9068,23 +9231,33 @@ public class WindowManagerService extends IWindowManager.Stub
// Internals
// -------------------------------------------------------------
- final WindowState windowForClientLocked(Session session, IWindow client) {
- return windowForClientLocked(session, client.asBinder());
+ final WindowState windowForClientLocked(Session session, IWindow client,
+ boolean throwOnError) {
+ return windowForClientLocked(session, client.asBinder(), throwOnError);
}
- final WindowState windowForClientLocked(Session session, IBinder client) {
+ final WindowState windowForClientLocked(Session session, IBinder client,
+ boolean throwOnError) {
WindowState win = mWindowMap.get(client);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Looking up client " + client + ": " + win);
if (win == null) {
- RuntimeException ex = new RuntimeException();
- Log.w(TAG, "Requested window " + client + " does not exist", ex);
+ RuntimeException ex = new IllegalArgumentException(
+ "Requested window " + client + " does not exist");
+ if (throwOnError) {
+ throw ex;
+ }
+ Slog.w(TAG, "Failed looking up window", 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);
+ RuntimeException ex = new IllegalArgumentException(
+ "Requested window " + client + " is in session " +
+ win.mSession + ", not " + session);
+ if (throwOnError) {
+ throw ex;
+ }
+ Slog.w(TAG, "Failed looking up window", ex);
return null;
}
@@ -9096,14 +9269,14 @@ public class WindowManagerService extends IWindowManager.Stub
int i;
int lastWallpaper = -1;
int numRemoved = 0;
-
+
// First remove all existing app windows.
i=0;
while (i < NW) {
WindowState w = (WindowState)mWindows.get(i);
if (w.mAppToken != null) {
WindowState win = (WindowState)mWindows.remove(i);
- if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
"Rebuild removing window: " + win);
NW--;
numRemoved++;
@@ -9114,12 +9287,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
i++;
}
-
+
// The wallpaper window(s) typically live at the bottom of the stack,
// so skip them before adding app tokens.
lastWallpaper++;
i = lastWallpaper;
-
+
// First add all of the exiting app tokens... these are no longer
// in the main app list, but still have windows shown. We put them
// in the back because now that the animation is over we no longer
@@ -9128,20 +9301,20 @@ public class WindowManagerService extends IWindowManager.Stub
for (int j=0; j<NT; j++) {
i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
}
-
+
// And add in the still active app tokens in Z order.
NT = mAppTokens.size();
for (int j=0; j<NT; j++) {
i = reAddAppWindowsLocked(i, mAppTokens.get(j));
}
-
+
i -= lastWallpaper;
if (i != numRemoved) {
- Log.w(TAG, "Rebuild removed " + numRemoved
+ Slog.w(TAG, "Rebuild removed " + numRemoved
+ " windows but added " + i);
}
}
-
+
private final void assignLayersLocked() {
int N = mWindows.size();
int curBaseLayer = 0;
@@ -9170,7 +9343,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (w.mIsWallpaper) {
w.mAnimLayer += mWallpaperAnimLayerAdjustment;
}
- if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
+ if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
+ w.mAnimLayer);
//System.out.println(
// "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
@@ -9183,21 +9356,28 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG) {
throw new RuntimeException("Recursive call!");
}
- Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
+ Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
return;
}
+ if (mWaitingForConfig) {
+ // Our configuration has changed (most likely rotation), but we
+ // don't yet have the complete configuration to report to
+ // applications. Don't do any window layout until we have it.
+ 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);
+ Slog.i(TAG, "Force removing: " + ws);
removeWindowInnerLocked(ws.mSession, ws);
}
mForceRemoves = null;
- Log.w(TAG, "Due to memory failure, waiting a bit for next layout");
+ Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
Object tmp = new Object();
synchronized (tmp) {
try {
@@ -9233,134 +9413,110 @@ public class WindowManagerService extends IWindowManager.Stub
}
} catch (RuntimeException e) {
mInLayout = false;
- Log.e(TAG, "Unhandled exception while layout out windows", e);
+ Slog.e(TAG, "Unhandled exception while layout out windows", e);
}
}
- private final void performLayoutLockedInner() {
+ private final int performLayoutLockedInner() {
+ if (!mLayoutNeeded) {
+ return 0;
+ }
+
+ mLayoutNeeded = false;
+
final int dw = mDisplay.getWidth();
final int dh = mDisplay.getHeight();
final int N = mWindows.size();
- int repeats = 0;
int i;
- if (DEBUG_LAYOUT) Log.v(TAG, "performLayout: needed="
+ if (DEBUG_LAYOUT) Slog.v(TAG, "performLayout: needed="
+ mLayoutNeeded + " dw=" + dw + " dh=" + dh);
- // FIRST LOOP: Perform a layout, if needed.
-
- while (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);
-
- // Don't do layout of a window if it is not visible, or
- // soon won't be visible, to avoid wasting time and funky
- // changes while a window is animating away.
- final AppWindowToken atoken = win.mAppToken;
- final boolean gone = win.mViewVisibility == View.GONE
- || !win.mRelayoutCalled
- || win.mRootToken.hidden
- || (atoken != null && atoken.hiddenRequested)
- || win.mAttachedHidden
- || win.mExiting || win.mDestroying;
-
- if (win.mLayoutAttached) {
- if (DEBUG_LAYOUT) Log.v(TAG, "First pass " + win
- + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
- + " mLayoutAttached=" + win.mLayoutAttached);
- if (DEBUG_LAYOUT && gone) Log.v(TAG, " (mViewVisibility="
- + win.mViewVisibility + " mRelayoutCalled="
- + win.mRelayoutCalled + " hidden="
- + win.mRootToken.hidden + " hiddenRequested="
- + (atoken != null && atoken.hiddenRequested)
- + " mAttachedHidden=" + win.mAttachedHidden);
- }
-
- // 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);
- if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
- + win.mFrame + " mContainingFrame="
- + win.mContainingFrame + " mDisplayFrame="
- + win.mDisplayFrame);
- } 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);
+ mPolicy.beginLayoutLw(dw, dh);
- // 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 (DEBUG_LAYOUT) Log.v(TAG, "Second pass " + win
- + " mHaveFrame=" + win.mHaveFrame
- + " mViewVisibility=" + win.mViewVisibility
- + " mRelayoutCalled=" + win.mRelayoutCalled);
- if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
- || !win.mHaveFrame) {
- mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
- if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
- + win.mFrame + " mContainingFrame="
- + win.mContainingFrame + " mDisplayFrame="
- + win.mDisplayFrame);
- }
- }
+ int seq = mLayoutSeq+1;
+ if (seq < 0) seq = 0;
+ mLayoutSeq = seq;
+
+ // 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);
+
+ // Don't do layout of a window if it is not visible, or
+ // soon won't be visible, to avoid wasting time and funky
+ // changes while a window is animating away.
+ final AppWindowToken atoken = win.mAppToken;
+ final boolean gone = win.mViewVisibility == View.GONE
+ || !win.mRelayoutCalled
+ || win.mRootToken.hidden
+ || (atoken != null && atoken.hiddenRequested)
+ || win.mAttachedHidden
+ || win.mExiting || win.mDestroying;
+
+ if (!win.mLayoutAttached) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "First pass " + win
+ + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
+ + " mLayoutAttached=" + win.mLayoutAttached);
+ if (DEBUG_LAYOUT && gone) Slog.v(TAG, " (mViewVisibility="
+ + win.mViewVisibility + " mRelayoutCalled="
+ + win.mRelayoutCalled + " hidden="
+ + win.mRootToken.hidden + " hiddenRequested="
+ + (atoken != null && atoken.hiddenRequested)
+ + " mAttachedHidden=" + win.mAttachedHidden);
}
-
- int changes = mPolicy.finishLayoutLw();
- if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
- if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
- assignLayersLocked();
+
+ // 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);
+ win.mLayoutSeq = seq;
+ if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ + win.mFrame + " mContainingFrame="
+ + win.mContainingFrame + " mDisplayFrame="
+ + win.mDisplayFrame);
+ } else {
+ if (topAttached < 0) topAttached = i;
}
}
- if (changes == 0) {
- mLayoutNeeded = false;
- } else if (repeats > 2) {
- Log.w(TAG, "Layout repeat aborted after too many iterations");
- mLayoutNeeded = false;
- if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
- Configuration newConfig = updateOrientationFromAppTokensLocked(
- null, null);
- if (newConfig != null) {
- mLayoutNeeded = true;
- mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
- }
- }
- } else {
- if (DEBUG_LAYOUT) Log.v(TAG, "Repeating layout because changes=0x"
- + Integer.toHexString(changes));
- repeats++;
- if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
- if (DEBUG_LAYOUT) Log.v(TAG, "Computing new config from layout");
- Configuration newConfig = updateOrientationFromAppTokensLocked(
- null, null);
- if (newConfig != null) {
- mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
- }
+ }
+
+ // 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 (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
+ + " mHaveFrame=" + win.mHaveFrame
+ + " mViewVisibility=" + win.mViewVisibility
+ + " mRelayoutCalled=" + win.mRelayoutCalled);
+ if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
+ || !win.mHaveFrame) {
+ mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ win.mLayoutSeq = seq;
+ if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ + win.mFrame + " mContainingFrame="
+ + win.mContainingFrame + " mDisplayFrame="
+ + win.mDisplayFrame);
}
}
}
+
+ return mPolicy.finishLayoutLw();
}
private final void performLayoutAndPlaceSurfacesLockedInner(
@@ -9371,14 +9527,16 @@ public class WindowManagerService extends IWindowManager.Stub
int i;
- // FIRST LOOP: Perform a layout, if needed.
- performLayoutLockedInner();
-
+ if (mFocusMayChange) {
+ mFocusMayChange = false;
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
+ }
+
if (mFxSession == null) {
mFxSession = new SurfaceSession();
}
- if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
// Initialize state of exiting tokens.
for (i=mExitingTokens.size()-1; i>=0; i--) {
@@ -9390,19 +9548,59 @@ public class WindowManagerService extends IWindowManager.Stub
mExitingAppTokens.get(i).hasVisible = false;
}
- // SECOND LOOP: Execute animations and update visibility of windows.
boolean orientationChangeComplete = true;
Session holdScreen = null;
float screenBrightness = -1;
+ float buttonBrightness = -1;
boolean focusDisplayed = false;
boolean animating = false;
Surface.openTransaction();
try {
- boolean restart;
- boolean forceHiding = false;
-
+ boolean wallpaperForceHidingChanged = false;
+ int repeats = 0;
+ int changes = 0;
+
do {
+ repeats++;
+ if (repeats > 6) {
+ Slog.w(TAG, "Animation repeat aborted after too many iterations");
+ mLayoutNeeded = false;
+ break;
+ }
+
+ if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
+ | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
+ | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
+ if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+ assignLayersLocked();
+ mLayoutNeeded = true;
+ }
+ }
+ if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+ if (updateOrientationFromAppTokensLocked()) {
+ mLayoutNeeded = true;
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+ }
+ }
+ if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ mLayoutNeeded = true;
+ }
+ }
+
+ // FIRST LOOP: Perform a layout, if needed.
+ if (repeats < 4) {
+ changes = performLayoutLockedInner();
+ if (changes != 0) {
+ continue;
+ }
+ } else {
+ Slog.w(TAG, "Layout repeat skipped after too many iterations");
+ changes = 0;
+ }
+
final int transactionSequence = ++mTransactionSequence;
// Update animations of all applications, including those
@@ -9421,18 +9619,22 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ // SECOND LOOP: Execute animations and update visibility of windows.
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
+ + transactionSequence + " tokensAnimating="
+ + tokensAnimating);
+
animating = tokensAnimating;
- restart = false;
boolean tokenMayBeDrawn = false;
boolean wallpaperMayChange = false;
- boolean focusMayChange = false;
- boolean wallpaperForceHidingChanged = false;
+ boolean forceHiding = false;
mPolicy.beginAnimationLw(dw, dh);
final int N = mWindows.size();
-
+
for (i=N-1; i>=0; i--) {
WindowState w = (WindowState)mWindows.get(i);
@@ -9443,12 +9645,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (w.commitFinishDrawingLocked(currentTime)) {
if ((w.mAttrs.flags
& WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"First draw done in potential wallpaper target " + w);
wallpaperMayChange = true;
}
}
-
+
boolean wasAnimating = w.mAnimating;
if (w.stepAnimationLocked(currentTime, dw, dh)) {
animating = true;
@@ -9457,11 +9659,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
wallpaperMayChange = true;
}
-
+
if (mPolicy.doesForceHide(w, attrs)) {
if (!wasAnimating && animating) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
+ "Animation done that could impact force hide: "
+ + w);
wallpaperForceHidingChanged = true;
- focusMayChange = true;
+ mFocusMayChange = true;
} else if (w.isReadyForDisplay() && w.mAnimation == null) {
forceHiding = true;
}
@@ -9469,17 +9674,30 @@ public class WindowManagerService extends IWindowManager.Stub
boolean changed;
if (forceHiding) {
changed = w.hideLw(false, false);
+ if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
+ "Now policy hidden: " + w);
} else {
changed = w.showLw(false, false);
- if (changed && wallpaperForceHidingChanged
- && w.isReadyForDisplay()) {
- // Assume we will need to animate. If
- // we don't (because the wallpaper will
- // stay with the lock screen), then we will
- // clean up later.
- Animation a = mPolicy.createForceHideEnterAnimation();
- if (a != null) {
- w.setAnimation(a);
+ if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
+ "Now policy shown: " + w);
+ if (changed) {
+ if (wallpaperForceHidingChanged
+ && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+ // Assume we will need to animate. If
+ // we don't (because the wallpaper will
+ // stay with the lock screen), then we will
+ // clean up later.
+ Animation a = mPolicy.createForceHideEnterAnimation();
+ if (a != null) {
+ w.setAnimation(a);
+ }
+ }
+ if (mCurrentFocus == null ||
+ mCurrentFocus.mLayer < w.mLayer) {
+ // We are showing on to of the current
+ // focus, so re-evaluate focus to make
+ // sure it is correct.
+ mFocusMayChange = true;
}
}
}
@@ -9487,17 +9705,8 @@ public class WindowManagerService extends IWindowManager.Stub
& WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
wallpaperMayChange = true;
}
- if (changed && !forceHiding
- && (mCurrentFocus == null)
- && (mFocusedApp != null)) {
- // It's possible that the last focus recalculation left no
- // current focused window even though the app has come to the
- // foreground already. In this case, we make sure to recalculate
- // focus when we show a window.
- focusMayChange = true;
- }
}
-
+
mPolicy.animatingWindowLw(w, attrs);
}
@@ -9512,11 +9721,11 @@ public class WindowManagerService extends IWindowManager.Stub
== WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
&& !w.mExiting && !w.mDestroying) {
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
- Log.v(TAG, "Eval win " + w + ": isDrawn="
+ Slog.v(TAG, "Eval win " + w + ": isDrawn="
+ w.isDrawnLw()
+ ", isAnimating=" + w.isAnimating());
if (!w.isDrawnLw()) {
- Log.v(TAG, "Not displayed: s=" + w.mSurface
+ Slog.v(TAG, "Not displayed: s=" + w.mSurface
+ " pv=" + w.mPolicyVisibility
+ " dp=" + w.mDrawPending
+ " cdp=" + w.mCommitDrawPending
@@ -9530,7 +9739,7 @@ public class WindowManagerService extends IWindowManager.Stub
atoken.numInterestingWindows++;
if (w.isDrawnLw()) {
atoken.numDrawnWindows++;
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
"tokenMayBeDrawn: " + atoken
+ " freezingScreen=" + atoken.freezingScreen
+ " mAppFreezing=" + w.mAppFreezing);
@@ -9546,9 +9755,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (mPolicy.finishAnimationLw()) {
- restart = true;
- }
+ changes |= mPolicy.finishAnimationLw();
if (tokenMayBeDrawn) {
// See if any windows have been drawn, so they (and others
@@ -9562,7 +9769,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken.freezingScreen) {
int numInteresting = wtoken.numInterestingWindows;
if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
- if (DEBUG_VISIBILITY) Log.v(TAG,
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
"allDrawn: " + wtoken
+ " interesting=" + numInteresting
+ " drawn=" + wtoken.numDrawnWindows);
@@ -9573,12 +9780,12 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (!wtoken.allDrawn) {
int numInteresting = wtoken.numInterestingWindows;
if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
- if (DEBUG_VISIBILITY) Log.v(TAG,
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
"allDrawn: " + wtoken
+ " interesting=" + numInteresting
+ " drawn=" + wtoken.numDrawnWindows);
wtoken.allDrawn = true;
- restart = true;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
// We can now show all of the drawn windows!
if (!mOpeningApps.contains(wtoken)) {
@@ -9595,7 +9802,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAppTransitionReady) {
int NN = mOpeningApps.size();
boolean goodToGo = true;
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Checking " + NN + " opening apps (frozen="
+ mDisplayFrozen + " timeout="
+ mAppTransitionTimeout + ")...");
@@ -9605,7 +9812,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Check opening app" + wtoken + ": allDrawn="
+ wtoken.allDrawn + " startingDisplayed="
+ wtoken.startingDisplayed);
@@ -9616,7 +9823,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
if (goodToGo) {
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
int transit = mNextAppTransition;
if (mSkipAppTransitionAnimation) {
transit = WindowManagerPolicy.TRANSIT_UNSET;
@@ -9646,19 +9853,19 @@ public class WindowManagerService extends IWindowManager.Stub
}
mToTopApps.clear();
}
-
+
WindowState oldWallpaper = mWallpaperTarget;
-
+
adjustWallpaperWindowsLocked();
wallpaperMayChange = false;
-
+
// The top-most window will supply the layout params,
// and we will determine it below.
LayoutParams animLp = null;
AppWindowToken animToken = null;
int bestAnimLayer = -1;
-
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + mWallpaperTarget
+ ", lower target=" + mLowerWallpaperTarget
+ ", upper target=" + mUpperWallpaperTarget);
@@ -9708,9 +9915,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
if (foundWallpapers == 3) {
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Wallpaper animation!");
switch (transit) {
case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
@@ -9724,22 +9931,22 @@ public class WindowManagerService extends IWindowManager.Stub
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
break;
}
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit: " + transit);
} else if (oldWallpaper != null) {
// We are transitioning from an activity with
// a wallpaper to one without.
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit away from wallpaper: " + transit);
} else if (mWallpaperTarget != null) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit into wallpaper: " + transit);
}
-
+
if ((transit&WindowManagerPolicy.TRANSIT_ENTER_MASK) != 0) {
mLastEnterAnimToken = animToken;
mLastEnterAnimParams = animLp;
@@ -9748,11 +9955,19 @@ public class WindowManagerService extends IWindowManager.Stub
mLastEnterAnimToken = null;
mLastEnterAnimParams = null;
}
+
+ // If all closing windows are obscured, then there is
+ // no need to do an animation. This is the case, for
+ // example, when this transition is being done behind
+ // the lock screen.
+ if (!mPolicy.allowAppAnimationsLw()) {
+ animLp = null;
+ }
NN = mOpeningApps.size();
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mOpeningApps.get(i);
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Now opening app" + wtoken);
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
@@ -9765,7 +9980,7 @@ public class WindowManagerService extends IWindowManager.Stub
NN = mClosingApps.size();
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mClosingApps.get(i);
- if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Now closing app" + wtoken);
wtoken.inPendingTransaction = false;
wtoken.animation = null;
@@ -9779,24 +9994,24 @@ public class WindowManagerService extends IWindowManager.Stub
}
mNextAppTransitionPackage = null;
-
+
mOpeningApps.clear();
mClosingApps.clear();
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
mLayoutNeeded = true;
if (!moveInputMethodWindowsIfNeededLocked(true)) {
assignLayersLocked();
}
- performLayoutLockedInner();
updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
- focusMayChange = false;
-
- restart = true;
+ mFocusMayChange = false;
}
}
-
+
+ int adjResult = 0;
+
if (!animating && mAppTransitionRunning) {
// We have finished the animation of an app transition. To do
// this, we have delayed a lot of operations like showing and
@@ -9807,21 +10022,19 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransitionRunning = false;
// Clear information about apps that were moving.
mToBottomApps.clear();
-
+
rebuildAppWindowListLocked();
- restart = true;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+ adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
moveInputMethodWindowsIfNeededLocked(false);
wallpaperMayChange = true;
- mLayoutNeeded = true;
// Since the window list has been rebuilt, focus might
// have to be recomputed since the actual order of windows
// might have changed again.
- focusMayChange = true;
+ mFocusMayChange = true;
}
-
- int adjResult = 0;
-
- if (wallpaperForceHidingChanged) {
+
+ if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
// At this point, there was a window with a wallpaper that
// was force hiding other windows behind it, but now it
// is going away. This may be simple -- just animate
@@ -9829,10 +10042,28 @@ public class WindowManagerService extends IWindowManager.Stub
// hard -- the wallpaper now needs to be shown behind
// something that was hidden.
WindowState oldWallpaper = mWallpaperTarget;
- adjResult = adjustWallpaperWindowsLocked();
+ if (mLowerWallpaperTarget != null
+ && mLowerWallpaperTarget.mAppToken != null) {
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "wallpaperForceHiding changed with lower="
+ + mLowerWallpaperTarget);
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
+ " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
+ if (mLowerWallpaperTarget.mAppToken.hidden) {
+ // The lower target has become hidden before we
+ // actually started the animation... let's completely
+ // re-evaluate everything.
+ mLowerWallpaperTarget = mUpperWallpaperTarget = null;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+ }
+ }
+ adjResult |= adjustWallpaperWindowsLocked();
wallpaperMayChange = false;
- if (false) Log.v(TAG, "****** OLD: " + oldWallpaper
- + " NEW: " + mWallpaperTarget);
+ wallpaperForceHidingChanged = false;
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
+ + " NEW: " + mWallpaperTarget
+ + " LOWER: " + mLowerWallpaperTarget);
if (mLowerWallpaperTarget == null) {
// Whoops, we don't need a special wallpaper animation.
// Clear them out.
@@ -9842,7 +10073,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (w.mSurface != null) {
final WindowManager.LayoutParams attrs = w.mAttrs;
if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
- if (DEBUG_FOCUS) Log.i(TAG, "win=" + w + " force hides other windows");
+ if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
forceHiding = true;
} else if (mPolicy.canBeForceHidden(w, attrs)) {
if (!w.mAnimating) {
@@ -9855,39 +10086,40 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
-
+
if (wallpaperMayChange) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper may change! Adjusting");
- adjResult = adjustWallpaperWindowsLocked();
+ adjResult |= adjustWallpaperWindowsLocked();
}
-
+
if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper layer changed: assigning layers + relayout");
- restart = true;
- mLayoutNeeded = true;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
assignLayersLocked();
} else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper visibility changed: relayout");
- restart = true;
- mLayoutNeeded = true;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
}
-
- if (focusMayChange) {
+
+ if (mFocusMayChange) {
+ mFocusMayChange = false;
if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES)) {
- restart = true;
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
adjResult = 0;
}
}
if (mLayoutNeeded) {
- restart = true;
- performLayoutLockedInner();
+ changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
}
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
+ + Integer.toHexString(changes));
- } while (restart);
+ } while (changes != 0);
// THIRD LOOP: Update the surfaces of all windows.
@@ -9901,7 +10133,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean backgroundFillerShown = false;
final int N = mWindows.size();
-
+
for (i=N-1; i>=0; i--) {
WindowState w = (WindowState)mWindows.get(i);
@@ -9910,8 +10142,22 @@ public class WindowManagerService extends IWindowManager.Stub
final int attrFlags = attrs.flags;
if (w.mSurface != null) {
+ // XXX NOTE: The logic here could be improved. We have
+ // the decision about whether to resize a window separated
+ // from whether to hide the surface. This can cause us to
+ // resize a surface even if we are going to hide it. You
+ // can see this by (1) holding device in landscape mode on
+ // home screen; (2) tapping browser icon (device will rotate
+ // to landscape; (3) tap home. The wallpaper will be resized
+ // in step 2 but then immediately hidden, causing us to
+ // have to resize and then redraw it again in step 3. It
+ // would be nice to figure out how to avoid this, but it is
+ // difficult because we do need to resize surfaces in some
+ // cases while they are hidden such as when first showing a
+ // window.
+
w.computeShownFrameLocked();
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Placing surface #" + i + " " + w.mSurface
+ ": new=" + w.mShownFrame + ", old="
+ w.mLastShownFrame);
@@ -9929,13 +10175,14 @@ public class WindowManagerService extends IWindowManager.Stub
w.mLastRequestedHeight = height;
w.mLastShownFrame.set(w.mShownFrame);
try {
- if (SHOW_TRANSACTIONS) Log.i(
- TAG, " SURFACE " + w.mSurface
- + ": POS " + w.mShownFrame.left
- + ", " + w.mShownFrame.top);
+ if (SHOW_TRANSACTIONS) logSurface(w,
+ "POS " + w.mShownFrame.left
+ + ", " + w.mShownFrame.top, null);
+ w.mSurfaceX = w.mShownFrame.left;
+ w.mSurfaceY = w.mShownFrame.top;
w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
} catch (RuntimeException e) {
- Log.w(TAG, "Error positioning surface in " + w, e);
+ Slog.w(TAG, "Error positioning surface in " + w, e);
if (!recoveringMemory) {
reclaimSomeSurfaceMemoryLocked(w, "position");
}
@@ -9952,20 +10199,24 @@ public class WindowManagerService extends IWindowManager.Stub
if (height < 1) height = 1;
if (w.mSurface != null) {
try {
- if (SHOW_TRANSACTIONS) Log.i(
- TAG, " SURFACE " + w.mSurface + ": POS "
- + w.mShownFrame.left + ","
+ if (SHOW_TRANSACTIONS) logSurface(w,
+ "POS " + w.mShownFrame.left + ","
+ w.mShownFrame.top + " SIZE "
+ w.mShownFrame.width() + "x"
- + w.mShownFrame.height());
+ + w.mShownFrame.height(), null);
+ w.mSurfaceResized = true;
+ w.mSurfaceW = width;
+ w.mSurfaceH = height;
w.mSurface.setSize(width, height);
+ w.mSurfaceX = w.mShownFrame.left;
+ w.mSurfaceY = w.mShownFrame.top;
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
+ Slog.e(TAG, "Failure updating surface of " + w
+ "size=(" + width + "x" + height
+ "), pos=(" + w.mShownFrame.left
+ "," + w.mShownFrame.top + ")", e);
@@ -9975,14 +10226,27 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
- if (!w.mAppFreezing) {
+ if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
w.mContentInsetsChanged =
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged =
!w.mLastVisibleInsets.equals(w.mVisibleInsets);
+ boolean configChanged =
+ w.mConfiguration != mCurConfiguration
+ && (w.mConfiguration == null
+ || mCurConfiguration.diff(w.mConfiguration) != 0);
+ if (DEBUG_CONFIGURATION && configChanged) {
+ Slog.v(TAG, "Win " + w + " config changed: "
+ + mCurConfiguration);
+ }
+ if (localLOGV) Slog.v(TAG, "Resizing " + w
+ + ": configChanged=" + configChanged
+ + " last=" + w.mLastFrame + " frame=" + w.mFrame);
if (!w.mLastFrame.equals(w.mFrame)
|| w.mContentInsetsChanged
- || w.mVisibleInsetsChanged) {
+ || w.mVisibleInsetsChanged
+ || w.mSurfaceResized
+ || configChanged) {
w.mLastFrame.set(w.mFrame);
w.mLastContentInsets.set(w.mContentInsets);
w.mLastVisibleInsets.set(w.mVisibleInsets);
@@ -9990,10 +10254,10 @@ public class WindowManagerService extends IWindowManager.Stub
// it frozen until this window draws at its new
// orientation.
if (mDisplayFrozen) {
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Resizing while display frozen: " + w);
w.mOrientationChanging = true;
- if (mWindowsFreezingScreen) {
+ if (!mWindowsFreezingScreen) {
mWindowsFreezingScreen = true;
// XXX should probably keep timeout from
// when we first froze the display.
@@ -10008,7 +10272,7 @@ public class WindowManagerService extends IWindowManager.Stub
// 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,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation start waiting for draw in "
+ w + ", surface " + w.mSurface);
w.mDrawPending = true;
@@ -10018,12 +10282,12 @@ public class WindowManagerService extends IWindowManager.Stub
w.mAppToken.allDrawn = false;
}
}
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.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,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation not waiting for draw in "
+ w + ", surface " + w.mSurface);
w.mOrientationChanging = false;
@@ -10034,14 +10298,21 @@ public class WindowManagerService extends IWindowManager.Stub
if (w.mAttachedHidden || !w.isReadyForDisplay()) {
if (!w.mLastHidden) {
//dump();
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Window hiding: waitingToShow="
+ + w.mRootToken.waitingToShow + " polvis="
+ + w.mPolicyVisibility + " atthid="
+ + w.mAttachedHidden + " tokhid="
+ + w.mRootToken.hidden + " vis="
+ + w.mViewVisibility);
w.mLastHidden = true;
- if (SHOW_TRANSACTIONS) Log.i(
- TAG, " SURFACE " + w.mSurface + ": HIDE (performLayout)");
+ if (SHOW_TRANSACTIONS) logSurface(w,
+ "HIDE (performLayout)", null);
if (w.mSurface != null) {
+ w.mSurfaceShown = false;
try {
w.mSurface.hide();
} catch (RuntimeException e) {
- Log.w(TAG, "Exception hiding surface in " + w);
+ Slog.w(TAG, "Exception hiding surface in " + w);
}
}
mKeyWaiter.releasePendingPointerLocked(w.mSession);
@@ -10054,7 +10325,7 @@ public class WindowManagerService extends IWindowManager.Stub
// new orientation.
if (w.mOrientationChanging) {
w.mOrientationChanging = false;
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation change skips hidden " + w);
}
} else if (w.mLastLayer != w.mAnimLayer
@@ -10075,22 +10346,23 @@ public class WindowManagerService extends IWindowManager.Stub
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 (SHOW_TRANSACTIONS) logSurface(w,
+ "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
+ " matrix=[" + (w.mDsDx*w.mHScale)
+ "," + (w.mDtDx*w.mVScale)
+ "][" + (w.mDsDy*w.mHScale)
- + "," + (w.mDtDy*w.mVScale) + "]");
+ + "," + (w.mDtDy*w.mVScale) + "]", null);
if (w.mSurface != null) {
try {
+ w.mSurfaceAlpha = w.mShownAlpha;
w.mSurface.setAlpha(w.mShownAlpha);
+ w.mSurfaceLayer = w.mAnimLayer;
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);
+ Slog.w(TAG, "Error updating surface in " + w, e);
if (!recoveringMemory) {
reclaimSomeSurfaceMemoryLocked(w, "update");
}
@@ -10100,9 +10372,9 @@ public class WindowManagerService extends IWindowManager.Stub
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
+ if (SHOW_TRANSACTIONS) logSurface(w,
+ "SHOW (performLayout)", null);
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+ " during relayout");
if (showSurfaceRobustlyLocked(w)) {
w.mHasDrawn = true;
@@ -10120,26 +10392,26 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayed) {
if (!covered) {
- if (attrs.width == LayoutParams.FILL_PARENT
- && attrs.height == LayoutParams.FILL_PARENT) {
+ if (attrs.width == LayoutParams.MATCH_PARENT
+ && attrs.height == LayoutParams.MATCH_PARENT) {
covered = true;
}
}
if (w.mOrientationChanging) {
if (w.mDrawPending || w.mCommitDrawPending) {
orientationChangeComplete = false;
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation continue waiting for draw in " + w);
} else {
w.mOrientationChanging = false;
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation change complete in " + w);
}
}
w.mToken.hasVisible = true;
}
} else if (w.mOrientationChanging) {
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation change skips hidden " + w);
w.mOrientationChanging = false;
}
@@ -10151,7 +10423,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final boolean obscuredChanged = w.mObscured != obscured;
-
+
// Update effect.
if (!(w.mObscured=obscured)) {
if (w.mSurface != null) {
@@ -10162,9 +10434,14 @@ public class WindowManagerService extends IWindowManager.Stub
&& screenBrightness < 0) {
screenBrightness = w.mAttrs.screenBrightness;
}
- if (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
- || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
- || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR) {
+ if (!syswin && w.mAttrs.buttonBrightness >= 0
+ && buttonBrightness < 0) {
+ buttonBrightness = w.mAttrs.buttonBrightness;
+ }
+ if (canBeSeen
+ && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
+ || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
+ || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
syswin = true;
}
}
@@ -10176,17 +10453,18 @@ public class WindowManagerService extends IWindowManager.Stub
// performance reasons).
obscured = true;
} else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
- if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
+ if (SHOW_TRANSACTIONS) Slog.d(TAG, "showing background filler");
// This window is in compatibility mode, and needs background filler.
obscured = true;
if (mBackgroundFillerSurface == null) {
try {
mBackgroundFillerSurface = new Surface(mFxSession, 0,
+ "BackGroundFiller",
0, dw, dh,
PixelFormat.OPAQUE,
Surface.FX_SURFACE_NORMAL);
} catch (Exception e) {
- Log.e(TAG, "Exception creating filler surface", e);
+ Slog.e(TAG, "Exception creating filler surface", e);
}
}
try {
@@ -10197,62 +10475,67 @@ public class WindowManagerService extends IWindowManager.Stub
mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
mBackgroundFillerSurface.show();
} catch (RuntimeException e) {
- Log.e(TAG, "Exception showing filler surface");
+ Slog.e(TAG, "Exception showing filler surface");
}
backgroundFillerShown = true;
mBackgroundFillerShown = true;
} else if (canBeSeen && !obscured &&
(attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
- if (localLOGV) Log.v(TAG, "Win " + w
+ if (localLOGV) Slog.v(TAG, "Win " + w
+ ": blurring=" + blurring
+ " obscured=" + obscured
+ " displayed=" + displayed);
if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
if (!dimming) {
- //Log.i(TAG, "DIM BEHIND: " + w);
+ //Slog.i(TAG, "DIM BEHIND: " + w);
dimming = true;
if (mDimAnimator == null) {
mDimAnimator = new DimAnimator(mFxSession);
}
mDimAnimator.show(dw, dh);
+ mDimAnimator.updateParameters(w, currentTime);
}
- mDimAnimator.updateParameters(w, currentTime);
}
if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
if (!blurring) {
- //Log.i(TAG, "BLUR BEHIND: " + w);
+ //Slog.i(TAG, "BLUR BEHIND: " + w);
blurring = true;
- mBlurShown = true;
if (mBlurSurface == null) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR "
+ mBlurSurface + ": CREATE");
try {
mBlurSurface = new Surface(mFxSession, 0,
+ "BlurSurface",
-1, 16, 16,
PixelFormat.OPAQUE,
Surface.FX_SURFACE_BLUR);
} catch (Exception e) {
- Log.e(TAG, "Exception creating Blur surface", e);
+ Slog.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) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR "
+ + mBlurSurface + ": pos=(0,0) (" +
+ dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
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 (!mBlurShown) {
+ try {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR "
+ + mBlurSurface + ": SHOW");
+ mBlurSurface.show();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure showing blur surface", e);
+ }
+ mBlurShown = true;
}
}
}
- mBlurSurface.setLayer(w.mAnimLayer-2);
}
}
}
-
+
if (obscuredChanged && mWallpaperTarget == w) {
// This is the wallpaper target and its obscured state
// changed... make sure the current wallaper's visibility
@@ -10260,40 +10543,41 @@ public class WindowManagerService extends IWindowManager.Stub
updateWallpaperVisibilityLocked();
}
}
-
+
if (backgroundFillerShown == false && mBackgroundFillerShown) {
mBackgroundFillerShown = false;
- if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
+ if (SHOW_TRANSACTIONS) Slog.d(TAG, "hiding background filler");
try {
mBackgroundFillerSurface.hide();
} catch (RuntimeException e) {
- Log.e(TAG, "Exception hiding filler surface", e);
+ Slog.e(TAG, "Exception hiding filler surface", e);
}
}
if (mDimAnimator != null && mDimAnimator.mDimShown) {
- animating |= mDimAnimator.updateSurface(dimming, currentTime, mDisplayFrozen);
+ animating |= mDimAnimator.updateSurface(dimming, currentTime,
+ mDisplayFrozen || !mPolicy.isScreenOn());
}
if (!blurring && mBlurShown) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface
+ ": HIDE");
try {
mBlurSurface.hide();
} catch (IllegalArgumentException e) {
- Log.w(TAG, "Illegal argument exception hiding blur surface");
+ Slog.w(TAG, "Illegal argument exception hiding blur surface");
}
mBlurShown = false;
}
- if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION");
} catch (RuntimeException e) {
- Log.e(TAG, "Unhandled exception in Window Manager", e);
+ Slog.e(TAG, "Unhandled exception in Window Manager", e);
}
Surface.closeTransaction();
- if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
+ if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
"With display frozen, orientationChangeComplete="
+ orientationChangeComplete);
if (orientationChangeComplete) {
@@ -10301,9 +10585,7 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowsFreezingScreen = false;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
}
- if (mAppsFreezingScreen == 0) {
- stopFreezingDisplayLocked();
- }
+ stopFreezingDisplayLocked();
}
i = mResizingWindows.size();
@@ -10312,13 +10594,28 @@ public class WindowManagerService extends IWindowManager.Stub
i--;
WindowState win = mResizingWindows.get(i);
try {
- if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to "
- + win + ": " + win.mFrame);
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+ "Reporting new frame to " + win + ": " + win.mFrame);
+ int diff = 0;
+ boolean configChanged =
+ win.mConfiguration != mCurConfiguration
+ && (win.mConfiguration == null
+ || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
+ && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + win + ": "
+ + win.mFrame.width() + "x" + win.mFrame.height()
+ + " / " + mCurConfiguration + " / 0x"
+ + Integer.toHexString(diff));
+ }
+ win.mConfiguration = mCurConfiguration;
win.mClient.resized(win.mFrame.width(),
win.mFrame.height(), win.mLastContentInsets,
- win.mLastVisibleInsets, win.mDrawPending);
+ win.mLastVisibleInsets, win.mDrawPending,
+ configChanged ? win.mConfiguration : null);
win.mContentInsetsChanged = false;
win.mVisibleInsetsChanged = false;
+ win.mSurfaceResized = false;
} catch (RemoteException e) {
win.mOrientationChanging = false;
}
@@ -10375,7 +10672,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean needRelayout = false;
-
+
if (!animating && mAppTransitionRunning) {
// We have finished the animation of an app transition. To do
// this, we have delayed a lot of operations like showing and
@@ -10386,10 +10683,11 @@ public class WindowManagerService extends IWindowManager.Stub
mAppTransitionRunning = false;
needRelayout = true;
rebuildAppWindowListLocked();
+ assignLayersLocked();
// Clear information about apps that were moving.
mToBottomApps.clear();
}
-
+
if (focusDisplayed) {
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
@@ -10401,20 +10699,32 @@ public class WindowManagerService extends IWindowManager.Stub
} else 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);
- }
+ if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
+ + " holdScreen=" + holdScreen);
+ if (!mDisplayFrozen) {
+ mQueue.setHoldScreenLocked(holdScreen != null);
+ if (screenBrightness < 0 || screenBrightness > 1.0f) {
+ mPowerManager.setScreenBrightnessOverride(-1);
+ } else {
+ mPowerManager.setScreenBrightnessOverride((int)
+ (screenBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+ mPowerManager.setButtonBrightnessOverride(-1);
+ } else {
+ mPowerManager.setButtonBrightnessOverride((int)
+ (buttonBrightness * Power.BRIGHTNESS_ON));
+ }
+ if (holdScreen != mHoldingScreenOn) {
+ mHoldingScreenOn = holdScreen;
+ Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
+ mH.sendMessage(m);
+ }
+ }
+
if (mTurnOnScreen) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
LocalPowerManager.BUTTON_EVENT, true);
mTurnOnScreen = false;
@@ -10443,15 +10753,18 @@ public class WindowManagerService extends IWindowManager.Stub
boolean showSurfaceRobustlyLocked(WindowState win) {
try {
if (win.mSurface != null) {
+ win.mSurfaceShown = true;
win.mSurface.show();
if (win.mTurnOnScreen) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
+ "Show surface turning screen on: " + win);
win.mTurnOnScreen = false;
mTurnOnScreen = true;
}
}
return true;
} catch (RuntimeException e) {
- Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
+ Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
}
reclaimSomeSurfaceMemoryLocked(win, "show");
@@ -10462,7 +10775,7 @@ public class WindowManagerService extends IWindowManager.Stub
void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
final Surface surface = win.mSurface;
- EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
+ EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
win.mSession.mPid, operation);
if (mForceRemoves == null) {
@@ -10476,27 +10789,29 @@ public class WindowManagerService extends IWindowManager.Stub
// around.
int N = mWindows.size();
boolean leakedSurface = false;
- Log.i(TAG, "Out of memory for surface! Looking for leaks...");
+ Slog.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): "
+ Slog.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.destroy();
+ ws.mSurfaceShown = false;
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): "
+ Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
+ ws + " surface=" + ws.mSurface
+ " token=" + win.mAppToken);
ws.mSurface.destroy();
+ ws.mSurfaceShown = false;
ws.mSurface = null;
leakedSurface = true;
}
@@ -10505,7 +10820,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean killedApps = false;
if (!leakedSurface) {
- Log.w(TAG, "No leaked surfaces; killing applicatons!");
+ Slog.w(TAG, "No leaked surfaces; killing applicatons!");
SparseIntArray pidCandidates = new SparseIntArray();
for (int i=0; i<N; i++) {
WindowState ws = (WindowState)mWindows.get(i);
@@ -10519,7 +10834,7 @@ public class WindowManagerService extends IWindowManager.Stub
pids[i] = pidCandidates.keyAt(i);
}
try {
- if (mActivityManager.killPidsForMemory(pids)) {
+ if (mActivityManager.killPids(pids, "Free memory")) {
killedApps = true;
}
} catch (RemoteException e) {
@@ -10530,9 +10845,10 @@ public class WindowManagerService extends IWindowManager.Stub
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.");
+ Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
if (surface != null) {
surface.destroy();
+ win.mSurfaceShown = false;
win.mSurface = null;
}
@@ -10553,7 +10869,7 @@ public class WindowManagerService extends IWindowManager.Stub
// change message pending.
mH.removeMessages(H.REPORT_FOCUS_CHANGE);
mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
@@ -10595,7 +10911,7 @@ public class WindowManagerService extends IWindowManager.Stub
while (i >= 0) {
win = (WindowState)mWindows.get(i);
- if (localLOGV || DEBUG_FOCUS) Log.v(
+ if (localLOGV || DEBUG_FOCUS) Slog.v(
TAG, "Looking for focus: " + i
+ " = " + win
+ ", flags=" + win.mAttrs.flags
@@ -10619,7 +10935,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (nextApp == mFocusedApp) {
// Whoops, we are below the focused app... no focus
// for you!
- if (localLOGV || DEBUG_FOCUS) Log.v(
+ if (localLOGV || DEBUG_FOCUS) Slog.v(
TAG, "Reached focused app: " + mFocusedApp);
return null;
}
@@ -10640,7 +10956,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Dispatch to this window if it is wants key events.
if (win.canReceiveKeys()) {
- if (DEBUG_FOCUS) Log.v(
+ if (DEBUG_FOCUS) Slog.v(
TAG, "Found focus @ " + i + " = " + win);
result = win;
break;
@@ -10669,10 +10985,10 @@ public class WindowManagerService extends IWindowManager.Stub
mScreenFrozenLock.acquire();
long now = SystemClock.uptimeMillis();
- //Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
+ //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
if (mFreezeGcPending != 0) {
if (now > (mFreezeGcPending+1000)) {
- //Log.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
+ //Slog.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000));
mH.removeMessages(H.FORCE_GC);
Runtime.getRuntime().gc();
mFreezeGcPending = now;
@@ -10681,6 +10997,8 @@ public class WindowManagerService extends IWindowManager.Stub
mFreezeGcPending = now;
}
+ if (DEBUG_FREEZE) Slog.v(TAG, "*** FREEZING DISPLAY", new RuntimeException());
+
mDisplayFrozen = true;
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -10700,6 +11018,12 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
+ return;
+ }
+
+ if (DEBUG_FREEZE) Slog.v(TAG, "*** UNFREEZING DISPLAY", new RuntimeException());
+
mDisplayFrozen = false;
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
@@ -10714,6 +11038,14 @@ public class WindowManagerService extends IWindowManager.Stub
mKeyWaiter.notifyAll();
}
+ // While the display is frozen we don't re-compute the orientation
+ // to avoid inconsistent states. However, something interesting
+ // could have actually changed during that time so re-evaluate it
+ // now to catch that.
+ if (updateOrientationFromAppTokensLocked()) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+ }
+
// 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
@@ -10736,6 +11068,10 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ pw.println("Input State:");
+ mQueue.dump(pw, " ");
+ pw.println(" ");
+
synchronized(mWindowMap) {
pw.println("Current Window Manager state:");
for (int i=mWindows.size()-1; i>=0; i--) {
@@ -10889,7 +11225,9 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
}
- pw.print(" mInTouchMode="); pw.println(mInTouchMode);
+ pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration);
+ pw.print(" mInTouchMode="); pw.print(mInTouchMode);
+ pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
@@ -10897,7 +11235,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDimAnimator != null) {
mDimAnimator.printTo(pw);
} else {
- pw.print( " no DimAnimator ");
+ pw.println( " no DimAnimator ");
}
pw.print(" mInputMethodAnimLayerAdjustment=");
pw.print(mInputMethodAnimLayerAdjustment);
@@ -10907,7 +11245,8 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
- pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
+ pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
+ pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
pw.print(" mRotation="); pw.print(mRotation);
pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
@@ -10966,10 +11305,10 @@ public class WindowManagerService extends IWindowManager.Stub
public void virtualKeyFeedback(KeyEvent event) {
mPolicy.keyFeedbackFromInput(event);
}
-
+
/**
* DimAnimator class that controls the dim animation. This holds the surface and
- * all state used for dim animation.
+ * all state used for dim animation.
*/
private static class DimAnimator {
Surface mDimSurface;
@@ -10978,16 +11317,20 @@ public class WindowManagerService extends IWindowManager.Stub
float mDimTargetAlpha;
float mDimDeltaPerMs;
long mLastDimAnimTime;
+
+ int mLastDimWidth, mLastDimHeight;
DimAnimator (SurfaceSession session) {
if (mDimSurface == null) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM "
+ mDimSurface + ": CREATE");
try {
- mDimSurface = new Surface(session, 0, -1, 16, 16, PixelFormat.OPAQUE,
+ mDimSurface = new Surface(session, 0,
+ "DimSurface",
+ -1, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
} catch (Exception e) {
- Log.e(TAG, "Exception creating Dim surface", e);
+ Slog.e(TAG, "Exception creating Dim surface", e);
}
}
}
@@ -10996,15 +11339,23 @@ public class WindowManagerService extends IWindowManager.Stub
* Show the dim surface.
*/
void show(int dw, int dh) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
- dw + "x" + dh + ")");
- mDimShown = true;
- try {
- mDimSurface.setPosition(0, 0);
+ if (!mDimShown) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
+ dw + "x" + dh + ")");
+ mDimShown = true;
+ try {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
+ mDimSurface.setPosition(0, 0);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.show();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure showing dim surface", e);
+ }
+ } else if (mLastDimWidth != dw || mLastDimHeight != dh) {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
mDimSurface.setSize(dw, dh);
- mDimSurface.show();
- } catch (RuntimeException e) {
- Log.w(TAG, "Failure showing dim surface", e);
}
}
@@ -11016,7 +11367,7 @@ public class WindowManagerService extends IWindowManager.Stub
mDimSurface.setLayer(w.mAnimLayer-1);
final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface
+ ": layer=" + (w.mAnimLayer-1) + " target=" + target);
if (mDimTargetAlpha != target) {
// If the desired dim level has changed, then
@@ -11040,7 +11391,7 @@ public class WindowManagerService extends IWindowManager.Stub
mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
}
}
-
+
/**
* Updating the surface's alpha. Returns true if the animation continues, or returns
* false when the animation is finished and the dim surface is hidden.
@@ -11053,7 +11404,7 @@ public class WindowManagerService extends IWindowManager.Stub
mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
}
}
-
+
boolean animating = false;
if (mLastDimAnimTime != 0) {
mDimCurrentAlpha += mDimDeltaPerMs
@@ -11076,7 +11427,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Do we need to continue animating?
if (more) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM "
+ mDimSurface + ": alpha=" + mDimCurrentAlpha);
mLastDimAnimTime = currentTime;
mDimSurface.setAlpha(mDimCurrentAlpha);
@@ -11084,16 +11435,16 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
mDimCurrentAlpha = mDimTargetAlpha;
mLastDimAnimTime = 0;
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM "
+ mDimSurface + ": final alpha=" + mDimCurrentAlpha);
mDimSurface.setAlpha(mDimCurrentAlpha);
if (!dimming) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, " DIM " + mDimSurface
+ ": HIDE");
try {
mDimSurface.hide();
} catch (RuntimeException e) {
- Log.w(TAG, "Illegal argument exception hiding dim surface");
+ Slog.w(TAG, "Illegal argument exception hiding dim surface");
}
mDimShown = false;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9e9552a..8383ca3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,8 @@ import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.WindowManagerService;
+import dalvik.system.Zygote;
+
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -33,6 +35,7 @@ import android.app.AlertDialog;
import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IActivityController;
+import android.app.IActivityManager;
import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
@@ -43,8 +46,9 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.ResultInfo;
import android.app.Service;
-import android.backup.IBackupManager;
+import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -59,6 +63,7 @@ import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
@@ -68,9 +73,12 @@ import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
+import android.os.DropBoxManager;
import android.os.Environment;
+import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -86,14 +94,10 @@ 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.server.data.CrashData;
-import android.server.data.StackTraceElementData;
-import android.server.data.ThrowableData;
-import android.text.TextUtils;
import android.util.Config;
import android.util.EventLog;
+import android.util.Slog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.SparseArray;
@@ -103,15 +107,11 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
-import dalvik.system.Zygote;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
@@ -122,6 +122,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
static final String TAG = "ActivityManager";
@@ -138,6 +141,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PROCESSES = localLOGV || false;
static final boolean DEBUG_PROVIDER = localLOGV || false;
+ static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
static final boolean DEBUG_USER_LEAVING = localLOGV || false;
static final boolean DEBUG_RESULTS = localLOGV || false;
static final boolean DEBUG_BACKUP = localLOGV || false;
@@ -152,44 +156,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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_AM_PROCESS_START_TIMEOUT = 30037;
-
- static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
- static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
-
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -295,41 +261,36 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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;
+ static final int EMPTY_APP_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 final int HIDDEN_APP_MAX_ADJ;
static int HIDDEN_APP_MIN_ADJ;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
- final int HOME_APP_ADJ;
+ static final int HOME_APP_ADJ;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
- final int BACKUP_APP_ADJ;
+ static final int BACKUP_APP_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;
+ static 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;
+ static 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;
+ static 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.
@@ -341,22 +302,66 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
- // System property defining error report receiver for system apps
- static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
-
- // System property defining default error report receiver
- static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
-
// Corresponding memory levels for above adjustments.
- final int EMPTY_APP_MEM;
- final int HIDDEN_APP_MEM;
- final int HOME_APP_MEM;
- final int BACKUP_APP_MEM;
- final int SECONDARY_SERVER_MEM;
- final int VISIBLE_APP_MEM;
- final int FOREGROUND_APP_MEM;
+ static final int EMPTY_APP_MEM;
+ static final int HIDDEN_APP_MEM;
+ static final int HOME_APP_MEM;
+ static final int BACKUP_APP_MEM;
+ static final int SECONDARY_SERVER_MEM;
+ static final int VISIBLE_APP_MEM;
+ static final int FOREGROUND_APP_MEM;
+
+ // The minimum number of hidden apps we want to be able to keep around,
+ // without empty apps being able to push them out of memory.
+ static final int MIN_HIDDEN_APPS = 2;
+
+ // The maximum number of hidden processes we will keep around before
+ // killing them; this is just a control to not let us go too crazy with
+ // keeping around processes on devices with large amounts of RAM.
+ static final int MAX_HIDDEN_APPS = 15;
- final int MY_PID;
+ // We put empty content processes after any hidden processes that have
+ // been idle for less than 30 seconds.
+ static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
+
+ // We put empty content processes after any hidden processes that have
+ // been idle for less than 60 seconds.
+ static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
+
+ static {
+ // 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"));
+ BACKUP_APP_ADJ =
+ Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
+ HOME_APP_ADJ =
+ Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
+ HIDDEN_APP_MIN_ADJ =
+ Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
+ EMPTY_APP_ADJ =
+ Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
+ HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
+ 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;
+ BACKUP_APP_MEM =
+ Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
+ HOME_APP_MEM =
+ Integer.valueOf(SystemProperties.get("ro.HOME_APP_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;
+ }
+
+ static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -394,6 +399,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
= new ArrayList<PendingActivityLaunch>();
/**
+ * List of people waiting to find out about the next launched activity.
+ */
+ final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
+ = new ArrayList<IActivityManager.WaitResult>();
+
+ /**
+ * List of people waiting to find out about the next visible activity.
+ */
+ final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
+ = new ArrayList<IActivityManager.WaitResult>();
+
+ /**
* 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
@@ -568,7 +585,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* It contains ApplicationRecord objects. This list does NOT include
* any persistent application records (since we never want to exit them).
*/
- final ArrayList<ProcessRecord> mLRUProcesses
+ final ArrayList<ProcessRecord> mLruProcesses
= new ArrayList<ProcessRecord>();
/**
@@ -766,6 +783,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Configuration mConfiguration = new Configuration();
/**
+ * Current sequencing integer of the configuration, for skipping old
+ * configurations.
+ */
+ int mConfigurationSeq = 0;
+
+ /**
+ * Set when we know we are going to be calling updateConfiguration()
+ * soon, so want to skip intermediate config checks.
+ */
+ boolean mConfigWillChange;
+
+ /**
* Hardware-reported OpenGLES version.
*/
final int GL_ES_VERSION;
@@ -905,7 +934,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
final ProcessStats mProcessStats = new ProcessStats(
MONITOR_THREAD_CPU_USAGE);
- long mLastCpuTime = 0;
+ final AtomicLong mLastCpuTime = new AtomicLong(0);
+ final AtomicBoolean mProcessStatsMutexFree = new AtomicBoolean(true);
+
long mLastWriteTime = 0;
long mInitialStartTime = 0;
@@ -929,7 +960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "New death recipient " + this
+ " for thread " + thread.asBinder());
mApp = app;
@@ -938,7 +969,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public void binderDied() {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
removeRequestedPss(mApp);
@@ -965,42 +996,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
+ static final int FINALIZE_PENDING_INTENT_MSG = 23;
AlertDialog mUidAlert;
final Handler mHandler = new Handler() {
//public Handler() {
- // if (localLOGV) Log.v(TAG, "Handler started!");
+ // if (localLOGV) Slog.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);
+ Slog.e(TAG, "App already has crash dialog: " + proc);
return;
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (!mSleeping && !mShuttingDown) {
- Dialog d = new AppErrorDialog(
- mContext, res, proc,
- (Integer)data.get("flags"),
- (String)data.get("shortMsg"),
- (String)data.get("longMsg"));
+ Dialog d = new AppErrorDialog(mContext, res, proc);
d.show();
proc.crashDialog = d;
} else {
@@ -1017,7 +1038,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.e(TAG, "App already has anr dialog: " + proc);
return;
}
@@ -1069,7 +1090,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} break;
case BROADCAST_INTENT_MSG: {
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST) Slog.v(
TAG, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
@@ -1086,7 +1107,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.w(TAG, "Activity pause timeout for " + token);
activityPaused(token, null, true);
} break;
case IDLE_TIMEOUT_MSG: {
@@ -1100,14 +1121,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
IBinder token = (IBinder)msg.obj;
- Log.w(TAG, "Activity idle timeout for " + token);
+ Slog.w(TAG, "Activity idle timeout for " + token);
activityIdleInternal(token, true, null);
} 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);
+ Slog.w(TAG, "Activity destroy timeout for " + token);
activityDestroyed(token);
} break;
case IDLE_NOW_MSG: {
@@ -1126,13 +1147,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} break;
case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
- for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLRUProcesses.get(i);
+ 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);
+ Slog.w(TAG, "Failed to update time zone for: " + r.info.processName);
}
}
}
@@ -1165,18 +1186,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized (ActivityManagerService.this) {
if (mLaunchingActivity.isHeld()) {
- Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
+ Slog.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);
@@ -1205,9 +1219,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int uid = msg.arg1;
boolean restart = (msg.arg2 == 1);
String pkg = (String) msg.obj;
- uninstallPackageLocked(pkg, uid, restart);
+ forceStopPackageLocked(pkg, uid, restart, false, true);
}
} break;
+ case FINALIZE_PENDING_INTENT_MSG: {
+ ((PendingIntentRecord)msg.obj).completeFinalize();
+ } break;
}
}
};
@@ -1221,10 +1238,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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 =
@@ -1237,13 +1250,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mSystemThread.getApplicationThread(), info,
info.processName);
app.persistent = true;
- app.pid = Process.myPid();
+ app.pid = MY_PID;
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);
+ mSelf.updateLruProcessLocked(app, true, true);
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
@@ -1332,54 +1345,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- 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) {
@@ -1400,8 +1365,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (NumberFormatException e) {
}
- for (int i=0; i<service.mLRUProcesses.size(); i++) {
- ProcessRecord proc = service.mLRUProcesses.get(i);
+ for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord proc = service.mLruProcesses.get(i);
if (proc.pid == pid) {
procs.add(proc);
} else if (proc.processName.equals(args[0])) {
@@ -1413,7 +1378,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
} else {
- procs = service.mLRUProcesses;
+ procs = new ArrayList<ProcessRecord>(service.mLruProcesses);
}
}
dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
@@ -1444,9 +1409,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mSimpleProcessManagement = true;
}
- Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
-
- MY_PID = Process.myPid();
+ Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
@@ -1462,45 +1425,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
- mConfiguration.makeDefault();
+ mConfiguration.setToDefaults();
+ mConfiguration.locale = Locale.getDefault();
mProcessStats.init();
// Add ourself to the Watchdog monitors.
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"));
- BACKUP_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
- HOME_APP_ADJ =
- Integer.valueOf(SystemProperties.get("ro.HOME_APP_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;
- BACKUP_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
- HOME_APP_MEM =
- Integer.valueOf(SystemProperties.get("ro.HOME_APP_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) {
@@ -1508,23 +1439,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
synchronized(this) {
final long now = SystemClock.uptimeMillis();
- long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
+ long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
- //Log.i(TAG, "Cpu delay=" + nextCpuDelay
+ //Slog.i(TAG, "Cpu delay=" + nextCpuDelay
// + ", write delay=" + nextWriteDelay);
if (nextWriteDelay < nextCpuDelay) {
nextCpuDelay = nextWriteDelay;
}
if (nextCpuDelay > 0) {
+ mProcessStatsMutexFree.set(true);
this.wait(nextCpuDelay);
}
}
} catch (InterruptedException e) {
}
-
updateCpuStatsNow();
} catch (Exception e) {
- Log.e(TAG, "Unexpected exception collecting process stats", e);
+ Slog.e(TAG, "Unexpected exception collecting process stats", e);
}
}
}
@@ -1541,36 +1472,40 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// The activity manager only throws security exceptions, so let's
// log all others.
if (!(e instanceof SecurityException)) {
- Log.e(TAG, "Activity Manager Crash", e);
+ Slog.e(TAG, "Activity Manager Crash", e);
}
throw e;
}
}
void updateCpuStats() {
- synchronized (mProcessStatsThread) {
- final long now = SystemClock.uptimeMillis();
- if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
+ final long now = SystemClock.uptimeMillis();
+ if (mLastCpuTime.get() >= now - MONITOR_CPU_MIN_TIME) {
+ return;
+ }
+ if (mProcessStatsMutexFree.compareAndSet(true, false)) {
+ synchronized (mProcessStatsThread) {
mProcessStatsThread.notify();
}
}
}
-
+
void updateCpuStatsNow() {
synchronized (mProcessStatsThread) {
+ mProcessStatsMutexFree.set(false);
final long now = SystemClock.uptimeMillis();
boolean haveNewCpuStats = false;
if (MONITOR_CPU_USAGE &&
- mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
- mLastCpuTime = now;
+ mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
+ mLastCpuTime.set(now);
haveNewCpuStats = true;
mProcessStats.update();
- //Log.i(TAG, mProcessStats.printCurrentState());
- //Log.i(TAG, "Total CPU usage: "
+ //Slog.i(TAG, mProcessStats.printCurrentState());
+ //Slog.i(TAG, "Total CPU usage: "
// + mProcessStats.getTotalCpuPercent() + "%");
- // Log the cpu usage if the property is set.
+ // Slog the cpu usage if the property is set.
if ("true".equals(SystemProperties.get("events.cpu"))) {
int user = mProcessStats.getLastUserTime();
int system = mProcessStats.getLastSystemTime();
@@ -1582,7 +1517,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int total = user + system + iowait + irq + softIrq + idle;
if (total == 0) total = 1;
- EventLog.writeEvent(LOG_CPU,
+ EventLog.writeEvent(EventLogTags.CPU,
((user+system+iowait+irq+softIrq) * 100) / total,
(user * 100) / total,
(system * 100) / total,
@@ -1653,13 +1588,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- private final void updateLRUListLocked(ProcessRecord app,
- boolean oomAdj) {
+ private final void updateLruProcessLocked(ProcessRecord app,
+ boolean oomAdj, boolean updateActivityTime) {
// 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);
+ int lrui = mLruProcesses.indexOf(app);
+ if (lrui >= 0) mLruProcesses.remove(lrui);
+
+ int i = mLruProcesses.size()-1;
+ int skipTop = 0;
+
+ // compute the new weight for this process.
+ if (updateActivityTime) {
+ app.lastActivityTime = SystemClock.uptimeMillis();
+ }
+ if (app.activities.size() > 0) {
+ // If this process has activities, we more strongly want to keep
+ // it around.
+ app.lruWeight = app.lastActivityTime;
+ } else if (app.pubProviders.size() > 0) {
+ // If this process contains content providers, we want to keep
+ // it a little more strongly.
+ app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
+ // Also don't let it kick out the first few "real" hidden processes.
+ skipTop = MIN_HIDDEN_APPS;
+ } else {
+ // If this process doesn't have activities, we less strongly
+ // want to keep it around, and generally want to avoid getting
+ // in front of any very recently used activities.
+ app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
+ // Also don't let it kick out the first few "real" hidden processes.
+ skipTop = MIN_HIDDEN_APPS;
+ }
+ while (i >= 0) {
+ ProcessRecord p = mLruProcesses.get(i);
+ // If this app shouldn't be in front of the first N background
+ // apps, then skip over that many that are currently hidden.
+ if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
+ skipTop--;
+ }
+ if (p.lruWeight <= app.lruWeight){
+ mLruProcesses.add(i+1, app);
+ break;
+ }
+ i--;
+ }
+ if (i < 0) {
+ mLruProcesses.add(0, app);
+ }
+
+ //Slog.i(TAG, "Putting proc to front: " + app.processName);
if (oomAdj) {
updateOomAdjLocked();
}
@@ -1770,13 +1747,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app = app;
- if (localLOGV) Log.v(TAG, "Launching: " + r);
+ if (localLOGV) Slog.v(TAG, "Launching: " + r);
int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);
}
- updateLRUListLocked(app, true);
+ updateLruProcessLocked(app, true, true);
try {
if (app.thread == null) {
@@ -1788,12 +1765,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
results = r.results;
newIntents = r.newIntents;
}
- if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
+ if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
+ " icicle=" + r.icicle
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
if (andResume) {
- EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
}
@@ -1809,7 +1786,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.launchFailed) {
// This is the second time we failed -- finish activity
// and give up.
- Log.e(TAG, "Second failure launching "
+ Slog.e(TAG, "Second failure launching "
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
appDiedLocked(app, app.pid, app.thread);
@@ -1826,7 +1803,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.launchFailed = false;
if (updateLRUListLocked(r)) {
- Log.w(TAG, "Activity " + r
+ Slog.w(TAG, "Activity " + r
+ " being launched, but already in LRU list");
}
@@ -1879,7 +1856,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
- Log.w(TAG, "Exception when starting activity "
+ Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
@@ -1901,12 +1878,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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
+ if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
if (app != null && app.pid > 0) {
if (!knownToBeDead || app.thread == null) {
+ // We already have the app running, or are waiting for it to
+ // come up (we have a pid but not yet its thread), so keep it.
return app;
} else {
// An application record is attached to a previous process,
@@ -1931,7 +1910,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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,
+ EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
info.processName);
mBadProcesses.remove(info.processName, info.uid);
if (app != null) {
@@ -1991,7 +1970,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
} catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to retrieve gids", e);
+ Slog.w(TAG, "Unable to retrieve gids", e);
}
if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
@@ -2008,6 +1987,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
}
+ // Run the app in safe mode if its manifest requests so or the
+ // system is booted in safe mode.
+ if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
+ Zygote.systemInSafeMode == true) {
+ debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
+ }
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
@@ -2024,7 +2009,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
@@ -2055,7 +2040,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
buf.append("}");
- Log.i(TAG, buf.toString());
+ Slog.i(TAG, buf.toString());
if (pid == 0 || pid == MY_PID) {
// Processes are being emulated with threads.
app.pid = MY_PID;
@@ -2075,29 +2060,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
RuntimeException e = new RuntimeException(
"Failure starting process " + app.processName
+ ": returned pid=" + pid);
- Log.e(TAG, e.getMessage(), e);
+ Slog.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);
+ Slog.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 "
+ Slog.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);
+ Slog.e(TAG, "Trying to pause when nothing is resumed", e);
resumeTopActivityLocked(null);
return;
}
- if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
@@ -2107,9 +2092,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
updateCpuStats();
if (prev.app != null && prev.app.thread != null) {
- if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
try {
- EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
System.identityHashCode(prev),
prev.shortComponentName);
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
@@ -2117,7 +2102,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
updateUsageStats(prev, false);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
- Log.w(TAG, "Exception thrown during pause", e);
+ Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
}
@@ -2146,7 +2131,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else {
- if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
+ if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
}
// Schedule a pause timeout in case the app doesn't respond.
@@ -2155,29 +2140,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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...");
+ if (DEBUG_PAUSE) Slog.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.");
+ if (DEBUG_PAUSE) Slog.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 (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
if (prev != null) {
if (prev.finishing) {
- if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
+ if (DEBUG_PAUSE) Slog.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 (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
if (prev.waitingVisible) {
prev.waitingVisible = false;
mWaitingVisibleActivities.remove(prev);
- if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
+ if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
TAG, "Complete pause, no longer waiting: " + prev);
}
if (prev.configDestroy) {
@@ -2186,7 +2171,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
destroyActivityLocked(prev, true);
} else {
mStoppingActivities.add(prev);
@@ -2194,14 +2179,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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");
+ if (DEBUG_PAUSE) Slog.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);
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
prev = null;
}
mPausingActivity = null;
@@ -2294,7 +2279,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
private final void ensureActivitiesVisibleLocked(HistoryRecord top,
HistoryRecord starting, String onlyThisProcess, int configChanges) {
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
@@ -2309,7 +2294,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean behindFullscreen = false;
for (; i>=0; i--) {
r = (HistoryRecord)mHistory.get(i);
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
if (r.finishing) {
@@ -2331,13 +2316,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Start and freeze screen for " + r);
if (r != starting) {
r.startFreezingScreenLocked(r.app, configChanges);
}
if (!r.visible) {
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Starting and making visible: " + r);
mWindowManager.setAppVisibility(r, true);
}
@@ -2349,7 +2334,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else if (r.visible) {
// If this activity is already visible, then there is nothing
// else to do here.
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Skipping: already visible at " + r);
r.stopFreezingScreenLocked(false);
@@ -2360,7 +2345,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.state != ActivityState.RESUMED && r != starting) {
// If this activity is paused, tell it
// to now show its window.
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Making visible and scheduling visibility: " + r);
try {
mWindowManager.setAppVisibility(r, true);
@@ -2369,7 +2354,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (Exception e) {
// Just skip on any failure; we'll make it
// visible when it next restarts.
- Log.w(TAG, "Exception thrown making visibile: "
+ Slog.w(TAG, "Exception thrown making visibile: "
+ r.intent.getComponent(), e);
}
}
@@ -2380,7 +2365,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.fullscreen) {
// At this point, nothing else needs to be shown
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping: fullscreen at " + r);
behindFullscreen = true;
i--;
@@ -2392,14 +2377,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// sure they no longer are keeping the screen frozen.
while (i >= 0) {
r = (HistoryRecord)mHistory.get(i);
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.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(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Making invisible: " + r);
r.visible = false;
try {
@@ -2407,22 +2392,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if ((r.state == ActivityState.STOPPING
|| r.state == ActivityState.STOPPED)
&& r.app != null && r.app.thread != null) {
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.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: "
+ Slog.w(TAG, "Exception thrown making hidden: "
+ r.intent.getComponent(), e);
}
} else {
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Already invisible: " + r);
}
} else if (r.fullscreen) {
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Now behindFullscreen: " + r);
behindFullscreen = true;
}
@@ -2541,7 +2526,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private void reportResumedActivityLocked(HistoryRecord r) {
- //Log.i(TAG, "**** REPORT RESUME: " + r);
+ //Slog.i(TAG, "**** REPORT RESUME: " + r);
final int identHash = System.identityHashCode(r);
updateUsageStats(r, true);
@@ -2611,19 +2596,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mStoppingActivities.remove(next);
mWaitingVisibleActivities.remove(next);
- if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
+ if (DEBUG_SWITCH) Slog.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);
+ if (DEBUG_SWITCH) Slog.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");
+ if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
startPausingLocked(userLeaving, false);
return true;
}
@@ -2632,7 +2617,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!prev.waitingVisible && next != null && !next.nowVisible) {
prev.waitingVisible = true;
mWaitingVisibleActivities.add(prev);
- if (DEBUG_SWITCH) Log.v(
+ if (DEBUG_SWITCH) Slog.v(
TAG, "Resuming top, waiting visible to hide: " + prev);
} else {
// The next activity is already visible, so hide the previous
@@ -2645,12 +2630,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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: "
+ if (DEBUG_SWITCH) Slog.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: "
+ if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
+ prev + ", waitingVisible="
+ (prev != null ? prev.waitingVisible : null)
+ ", nowVisible=" + next.nowVisible);
@@ -2663,7 +2648,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// to ignore it when computing the desired screen orientation.
if (prev != null) {
if (prev.finishing) {
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare close transition: prev=" + prev);
if (mNoAnimActivities.contains(prev)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
@@ -2675,7 +2660,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWindowManager.setAppWillBeHidden(prev);
mWindowManager.setAppVisibility(prev, false);
} else {
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: prev=" + prev);
if (mNoAnimActivities.contains(next)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
@@ -2690,7 +2675,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWindowManager.setAppVisibility(prev, false);
}
} else if (mHistory.size() > 1) {
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
@@ -2700,7 +2685,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (next.app != null && next.app.thread != null) {
- if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
+ if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
// This activity is now becoming visible.
mWindowManager.setAppVisibility(next, true);
@@ -2713,7 +2698,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
- updateLRUListLocked(next.app, true);
+ updateLruProcessLocked(next.app, true, true);
updateLRUListLocked(next);
// Have the window manager re-evaluate the orientation of
@@ -2724,20 +2709,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mConfiguration,
next.mayFreezeScreenLocked(next.app) ? next : null);
if (config != null) {
- /*
- * Explicitly restore the locale to the one from the
- * old configuration, since the one that comes back from
- * the window manager has the default (boot) locale.
- *
- * It looks like previously the locale picker only worked
- * by coincidence: usually it would do its setting of
- * the locale after the activity transition, so it didn't
- * matter that this lost it. With the synchronized
- * block now keeping them from happening at the same time,
- * this one always would happen second and undo what the
- * locale picker had just done.
- */
- config.locale = mConfiguration.locale;
next.frozenBeforeDestroy = true;
}
updated = updateConfigurationLocked(config, next);
@@ -2749,7 +2720,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// is still at the top and schedule another run if something
// weird happened.
HistoryRecord nextNext = topRunningActivityLocked(null);
- if (DEBUG_SWITCH) Log.i(TAG,
+ if (DEBUG_SWITCH) Slog.i(TAG,
"Activity config changed during resume: " + next
+ ", new next: " + nextNext);
if (nextNext != next) {
@@ -2769,7 +2740,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
- if (DEBUG_RESULTS) Log.v(
+ if (DEBUG_RESULTS) Slog.v(
TAG, "Delivering results to " + next
+ ": " + a);
next.app.thread.scheduleSendResult(next, a);
@@ -2780,7 +2751,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
next.app.thread.scheduleNewIntent(next.newIntents, next);
}
- EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
@@ -2793,8 +2764,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Whoops, need to restart this activity!
next.state = lastState;
mResumedActivity = lastResumedActivity;
- if (Config.LOGD) Log.d(TAG,
- "Restarting because process died: " + next);
+ Slog.i(TAG, "Restarting because process died: " + next);
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
@@ -2817,7 +2787,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} 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);
+ Slog.w(TAG, "Exception thrown during resume of " + next, e);
requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
"resume-exception");
return true;
@@ -2839,7 +2809,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
next.nonLocalizedLabel,
next.labelRes, next.icon, null, true);
}
- if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
+ if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
}
startSpecificActivityLocked(next, true, true);
}
@@ -2898,7 +2868,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// activity
if (addPos < NH) {
mUserLeaving = false;
- if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
+ if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
}
// Slot the activity into the history stack and proceed
@@ -2918,7 +2888,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (proc == null || proc.thread == null) {
showStartingIcon = true;
}
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
@@ -3039,7 +3009,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!ret.finishing) {
int index = indexOfTokenLocked(ret);
if (index >= 0) {
- finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
+ finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear");
}
return null;
@@ -3101,7 +3071,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleNewIntent(ar, r);
sent = true;
} catch (Exception e) {
- Log.w(TAG, "Exception thrown sending new intent to " + r, e);
+ Slog.w(TAG, "Exception thrown sending new intent to " + r, e);
}
}
if (!sent) {
@@ -3125,13 +3095,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified) {
- Log.i(TAG, "Starting activity: " + intent);
+ Slog.i(TAG, "Starting activity: " + intent);
HistoryRecord sourceRecord = null;
HistoryRecord resultRecord = null;
if (resultTo != null) {
int index = indexOfTokenLocked(resultTo);
- if (DEBUG_RESULTS) Log.v(
+ if (DEBUG_RESULTS) Slog.v(
TAG, "Sending result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
sourceRecord = (HistoryRecord)mHistory.get(index);
@@ -3181,7 +3151,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
- Log.w(TAG, "Unable to find app for caller " + caller
+ Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = START_PERMISSION_DENIED;
@@ -3209,7 +3179,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires " + aInfo.permission;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -3297,7 +3267,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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,
+ if (DEBUG_USER_LEAVING) Slog.v(TAG,
"startActivity() => mUserLeaving=" + mUserLeaving);
// If the caller has asked not to resume at this point, we make note
@@ -3339,7 +3309,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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: "
+ Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
+ intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
@@ -3361,7 +3331,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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.");
+ Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
@@ -3441,7 +3411,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// intent.
top.task.setIntent(r.intent, r.info);
}
- logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
+ logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
} else {
// A special case: we need to
@@ -3463,7 +3433,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// desires.
if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
&& taskTop.realActivity.equals(r.realActivity)) {
- logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
+ logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
if (taskTop.frontOfTask) {
taskTop.task.setIntent(r.intent, r.info);
}
@@ -3508,9 +3478,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//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);
+ //Slog.i(TAG, "Given intent: " + r.intent);
+ //Slog.i(TAG, "URI is: " + uri);
+ //Slog.i(TAG, "To intent: " + intent2);
if (r.packageName != null) {
// If the activity being launched is the same as the one currently
@@ -3523,7 +3493,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
if (doResume) {
@@ -3563,7 +3533,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
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
+ if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
newTask = true;
addRecentTaskLocked(r.task);
@@ -3577,7 +3547,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord top = performClearTaskLocked(
sourceRecord.task.taskId, r, launchFlags, true);
if (top != null) {
- logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
+ logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
@@ -3594,7 +3564,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
if (where >= 0) {
HistoryRecord top = moveActivityToFrontLocked(where);
- logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
+ logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
if (doResume) {
resumeTopActivityLocked(null);
@@ -3606,7 +3576,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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
+ if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in existing task " + r.task);
} else {
@@ -3620,22 +3590,49 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? 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
+ if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
if (newTask) {
- EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
+ EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
}
- logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
+ logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
startActivityLocked(r, newTask, doResume);
return START_SUCCESS;
}
- public final int startActivity(IApplicationThread caller,
+ void reportActivityLaunchedLocked(boolean timeout, HistoryRecord r,
+ long thisTime, long totalTime) {
+ for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
+ WaitResult w = mWaitingActivityLaunched.get(i);
+ w.timeout = timeout;
+ if (r != null) {
+ w.who = new ComponentName(r.info.packageName, r.info.name);
+ }
+ w.thisTime = thisTime;
+ w.totalTime = totalTime;
+ }
+ notify();
+ }
+
+ void reportActivityVisibleLocked(HistoryRecord r) {
+ for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
+ WaitResult w = mWaitingActivityVisible.get(i);
+ w.timeout = false;
+ if (r != null) {
+ w.who = new ComponentName(r.info.packageName, r.info.name);
+ }
+ w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
+ w.thisTime = w.totalTime;
+ }
+ notify();
+ }
+
+ private final int startActivityMayWait(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
- boolean debug) {
+ boolean debug, WaitResult outResult, Configuration config) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3675,18 +3672,109 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- synchronized(this) {
+ synchronized (this) {
+ int callingPid;
+ int callingUid;
+ if (caller == null) {
+ callingPid = Binder.getCallingPid();
+ callingUid = Binder.getCallingUid();
+ } else {
+ callingPid = callingUid = -1;
+ }
+
+ mConfigWillChange = config != null && mConfiguration.diff(config) != 0;
+ if (DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Starting activity when config will change = " + mConfigWillChange);
+
final long origId = Binder.clearCallingIdentity();
+
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
- resultTo, resultWho, requestCode, -1, -1,
+ resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified);
+
+ if (mConfigWillChange) {
+ // If the caller also wants to switch to a new configuration,
+ // do so now. This allows a clean switch, as we are waiting
+ // for the current activity to pause (so we will not destroy
+ // it), and have not yet started the next activity.
+ enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+ "updateConfiguration()");
+ mConfigWillChange = false;
+ if (DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Updating to new configuration after starting activity.");
+ updateConfigurationLocked(config, null);
+ }
+
Binder.restoreCallingIdentity(origId);
+
+ if (outResult != null) {
+ outResult.result = res;
+ if (res == IActivityManager.START_SUCCESS) {
+ mWaitingActivityLaunched.add(outResult);
+ do {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ } while (!outResult.timeout && outResult.who == null);
+ } else if (res == IActivityManager.START_TASK_TO_FRONT) {
+ HistoryRecord r = this.topRunningActivityLocked(null);
+ if (r.nowVisible) {
+ outResult.timeout = false;
+ outResult.who = new ComponentName(r.info.packageName, r.info.name);
+ outResult.totalTime = 0;
+ outResult.thisTime = 0;
+ } else {
+ outResult.thisTime = SystemClock.uptimeMillis();
+ mWaitingActivityVisible.add(outResult);
+ do {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ } while (!outResult.timeout && outResult.who == null);
+ }
+ }
+ }
+
return res;
}
}
- public int startActivityIntentSender(IApplicationThread caller,
+ public final int startActivity(IApplicationThread caller,
+ Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+ int grantedMode, IBinder resultTo,
+ String resultWho, int requestCode, boolean onlyIfNeeded,
+ boolean debug) {
+ return startActivityMayWait(caller, intent, resolvedType,
+ grantedUriPermissions, grantedMode, resultTo, resultWho,
+ requestCode, onlyIfNeeded, debug, null, null);
+ }
+
+ public final WaitResult startActivityAndWait(IApplicationThread caller,
+ Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+ int grantedMode, IBinder resultTo,
+ String resultWho, int requestCode, boolean onlyIfNeeded,
+ boolean debug) {
+ WaitResult res = new WaitResult();
+ startActivityMayWait(caller, intent, resolvedType,
+ grantedUriPermissions, grantedMode, resultTo, resultWho,
+ requestCode, onlyIfNeeded, debug, res, null);
+ return res;
+ }
+
+ public final int startActivityWithConfig(IApplicationThread caller,
+ Intent intent, String resolvedType, Uri[] grantedUriPermissions,
+ int grantedMode, IBinder resultTo,
+ String resultWho, int requestCode, boolean onlyIfNeeded,
+ boolean debug, Configuration config) {
+ return startActivityMayWait(caller, intent, resolvedType,
+ grantedUriPermissions, grantedMode, resultTo, resultWho,
+ requestCode, onlyIfNeeded, debug, null, config);
+ }
+
+ public int startActivityIntentSender(IApplicationThread caller,
IntentSender intent, Intent fillInIntent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues) {
@@ -3913,7 +4001,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void stopActivityLocked(HistoryRecord r) {
- if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
+ if (DEBUG_SWITCH) Slog.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) {
@@ -3928,7 +4016,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
r.stopped = false;
r.state = ActivityState.STOPPING;
- if (DEBUG_VISBILITY) Log.v(
+ if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
mWindowManager.setAppVisibility(r, false);
@@ -3938,7 +4026,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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);
+ Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
r.stopped = true;
r.state = ActivityState.STOPPED;
@@ -3955,7 +4043,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
Intent resultData, String reason) {
- if (DEBUG_RESULTS) Log.v(
+ if (DEBUG_RESULTS) Slog.v(
TAG, "Finishing activity: token=" + token
+ ", result=" + resultCode + ", data=" + resultData);
@@ -3994,19 +4082,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.w(TAG, "Duplicate finish request for " + r);
return false;
}
r.finishing = true;
- EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
r.task.numActivities--;
- if (r.frontOfTask && index < (mHistory.size()-1)) {
+ if (index < (mHistory.size()-1)) {
HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
if (next.task == r.task) {
- next.frontOfTask = true;
+ if (r.frontOfTask) {
+ // The next activity is now the front of the task.
+ next.frontOfTask = true;
+ }
+ if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+ // If the caller asked that this activity (and all above it)
+ // be cleared when the task is reset, don't lose that information,
+ // but propagate it up to the next activity.
+ next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ }
}
}
@@ -4018,7 +4115,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// send the result
HistoryRecord resultTo = r.resultTo;
if (resultTo != null) {
- if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
+ if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
+ " who=" + r.resultWho + " req=" + r.requestCode
+ " res=" + resultCode + " data=" + resultData);
if (r.info.applicationInfo.uid > 0) {
@@ -4029,7 +4126,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
resultData);
r.resultTo = null;
}
- else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
+ else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
// Make sure this HistoryRecord is not holding on to other resources,
// because clients have remote IPC references to this object so we
@@ -4049,7 +4146,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mResumedActivity == r) {
boolean endTask = index <= 0
|| ((HistoryRecord)mHistory.get(index-1)).task != r.task;
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare close transition: finishing " + r);
mWindowManager.prepareAppTransition(endTask
? WindowManagerPolicy.TRANSIT_TASK_CLOSE
@@ -4059,19 +4156,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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");
+ if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
+ if (DEBUG_USER_LEAVING) Slog.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);
+ if (DEBUG_PAUSE) Slog.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);
+ if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
}
return false;
@@ -4131,7 +4228,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} 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);
+ if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
mFinishingActivities.add(r);
resumeTopActivityLocked(null);
}
@@ -4187,7 +4284,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
data, r);
}
- if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
+ if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
+ " : who=" + resultWho + " req=" + requestCode
+ " res=" + resultCode + " data=" + data);
if (mResumedActivity == r && r.app != null && r.app.thread != null) {
@@ -4198,7 +4295,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleSendResult(r, list);
return;
} catch (Exception e) {
- Log.w(TAG, "Exception thrown sending result to " + r, e);
+ Slog.w(TAG, "Exception thrown sending result to " + r, e);
}
}
@@ -4232,6 +4329,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public boolean willActivityBeVisible(IBinder token) {
+ synchronized(this) {
+ int i;
+ for (i=mHistory.size()-1; i>=0; i--) {
+ HistoryRecord r = (HistoryRecord)mHistory.get(i);
+ if (r == token) {
+ return true;
+ }
+ if (r.fullscreen && !r.finishing) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
@@ -4341,10 +4454,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
private final boolean destroyActivityLocked(HistoryRecord r,
boolean removeFromApp) {
- if (DEBUG_SWITCH) Log.v(
+ if (DEBUG_SWITCH) Slog.v(
TAG, "Removing activity: token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
- EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
@@ -4352,7 +4465,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
cleanUpActivityLocked(r, false);
- if (r.app != null) {
+ final boolean hadApp = r.app != null;
+
+ if (hadApp) {
if (removeFromApp) {
int idx = r.app.activities.indexOf(r);
if (idx >= 0) {
@@ -4361,19 +4476,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.persistent) {
decPersistentCountLocked(r.app);
}
+ if (r.app.activities.size() == 0) {
+ // No longer have activities, so update location in
+ // LRU list.
+ updateLruProcessLocked(r.app, true, false);
+ }
}
boolean skipDestroy = false;
try {
- if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
+ if (DEBUG_SWITCH) Slog.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);
+ //Slog.w(TAG, "Exception thrown during finish", e);
if (r.finishing) {
removeActivityFromHistoryLocked(r);
removedFromHistory = true;
@@ -4404,27 +4524,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.configChangeFlags = 0;
- if (!mLRUActivities.remove(r)) {
- Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
+ if (!mLRUActivities.remove(r) && hadApp) {
+ Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
}
return removedFromHistory;
}
- private static void removeHistoryRecordsForAppLocked(ArrayList list,
- ProcessRecord app)
- {
+ private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
int i = list.size();
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.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(
+ if (localLOGV) Slog.v(
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
- if (localLOGV) Log.v(TAG, "Removing this entry!");
+ if (localLOGV) Slog.v(TAG, "Removing this entry!");
list.remove(i);
}
}
@@ -4439,12 +4557,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean restarting) {
cleanUpApplicationRecordLocked(app, restarting, -1);
if (!restarting) {
- mLRUProcesses.remove(app);
+ mLruProcesses.remove(app);
}
// Just in case...
if (mPausingActivity != null && mPausingActivity.app == app) {
- if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
+ if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + mPausingActivity);
mPausingActivity = null;
}
if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
@@ -4462,16 +4580,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Clean out the history list.
int i = mHistory.size();
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Removing app " + app + " from history with " + i + " entries");
while (i > 0) {
i--;
HistoryRecord r = (HistoryRecord)mHistory.get(i);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Removing this entry! frozen=" + r.haveState
+ " finishing=" + r.finishing);
mHistory.remove(i);
@@ -4486,7 +4604,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else {
// We have the current state for this activity, so
// it can be restarted later when needed.
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Keeping entry, setting app to null");
if (r.visible) {
hasVisibleActivities = true;
@@ -4507,7 +4625,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.activities.clear();
if (app.instrumentationClass != null) {
- Log.w(TAG, "Crash of app " + app.processName
+ Slog.w(TAG, "Crash of app " + app.processName
+ " running instrumentation " + app.instrumentationClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
@@ -4532,10 +4650,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
@@ -4550,7 +4666,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
int appIndex = getLRURecordIndexForAppLocked(thread);
- return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
+ return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}
private final void appDiedLocked(ProcessRecord app, int pid,
@@ -4561,10 +4677,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- Log.i(TAG, "Process " + app.processName + " (pid " + pid
+ Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
- EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
- if (localLOGV) Log.v(
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
+ if (localLOGV) Slog.v(
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
boolean doLowMem = app.instrumentationClass == null;
@@ -4575,10 +4691,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
haveBg = true;
break;
@@ -4586,11 +4700,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (!haveBg) {
- Log.i(TAG, "Low Memory: No more background processes.");
- EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
+ Slog.i(TAG, "Low Memory: No more background processes.");
+ EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
long now = SystemClock.uptimeMillis();
- for (i=0; i<count; i++) {
- ProcessRecord rec = mLRUProcesses.get(i);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
if (rec != app && rec.thread != null &&
(rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
// The low memory report is overriding any current
@@ -4612,211 +4726,184 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} else if (app.pid != pid) {
// A new process has already been started.
- Log.i(TAG, "Process " + app.processName + " (pid " + pid
+ Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died and restarted (pid " + app.pid + ").");
- EventLog.writeEvent(LOG_AM_PROCESS_DIED, pid, app.processName);
- } else if (Config.LOGD) {
- Log.d(TAG, "Received spurious death notification for thread "
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
+ } else if (DEBUG_PROCESSES) {
+ Slog.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) {
+ /**
+ * If a stack trace dump file is configured, dump process stack traces.
+ * @param pids of dalvik VM processes to dump stack traces for
+ * @return file containing stack traces, or null if no dump file is configured
+ */
+ public static File dumpStackTraces(ArrayList<Integer> pids) {
+ String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
+ if (tracesPath == null || tracesPath.length() == 0) {
+ return null;
}
- return "";
- }
- final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
- HistoryRecord reportedActivity, final String annotation) {
- if (app.notResponding || app.crashing) {
- return;
+ File tracesFile = new File(tracesPath);
+ try {
+ File tracesDir = tracesFile.getParentFile();
+ if (!tracesDir.exists()) tracesFile.mkdirs();
+ FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
+
+ if (tracesFile.exists()) tracesFile.delete();
+ tracesFile.createNewFile();
+ FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
+ return null;
}
-
- // 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;
+
+ // Use a FileObserver to detect when traces finish writing.
+ // The order of traces is considered important to maintain for legibility.
+ FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
+ public synchronized void onEvent(int event, String path) { notify(); }
+ };
+
+ try {
+ observer.startWatching();
+ int num = pids.size();
+ for (int i = 0; i < num; i++) {
+ synchronized (observer) {
+ Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
+ observer.wait(200); // Wait for write-close, give up after 200msec
+ }
+ }
+ } catch (InterruptedException e) {
+ Log.wtf(TAG, e);
+ } finally {
+ observer.stopWatching();
}
+
+ return tracesFile;
+ }
+
+ final void appNotResponding(ProcessRecord app, HistoryRecord activity,
+ HistoryRecord parent, final String annotation) {
+ ArrayList<Integer> pids = new ArrayList<Integer>(20);
- // DeviceMonitor.start();
+ synchronized (this) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mShuttingDown) {
+ Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
+ return;
+ } else if (app.notResponding) {
+ Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
+ return;
+ } else if (app.crashing) {
+ Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
+ return;
+ }
+
+ // In case we come through here for the same app before completing
+ // this one, mark as anring now so we will bail out.
+ app.notResponding = true;
- String processInfo = null;
- if (MONITOR_CPU_USAGE) {
- updateCpuStatsNow();
- synchronized (mProcessStatsThread) {
- processInfo = mProcessStats.printCurrentState();
+ // Log the ANR to the event log.
+ EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
+ annotation);
+
+ // Dump thread traces as quickly as we can, starting with "interesting" processes.
+ pids.add(app.pid);
+
+ int parentPid = app.pid;
+ if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
+ if (parentPid != app.pid) pids.add(parentPid);
+
+ if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
+
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r != null && r.thread != null) {
+ int pid = r.pid;
+ if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
+ }
}
}
+ File tracesFile = dumpStackTraces(pids);
+
+ // Log the ANR to the main log.
StringBuilder info = mStringBuilder;
info.setLength(0);
- info.append("ANR in process: ");
- info.append(app.processName);
- if (reportedActivity != null && reportedActivity.app != null) {
- info.append(" (last in ");
- info.append(reportedActivity.app.processName);
- info.append(")");
+ info.append("ANR in ").append(app.processName);
+ if (activity != null && activity.shortComponentName != null) {
+ info.append(" (").append(activity.shortComponentName).append(")");
}
+ info.append("\n");
if (annotation != null) {
- info.append("\nAnnotation: ");
- info.append(annotation);
+ info.append("Reason: ").append(annotation).append("\n");
+ }
+ if (parent != null && parent != activity) {
+ info.append("Parent: ").append(parent.shortComponentName).append("\n");
}
+
+ String cpuInfo = null;
if (MONITOR_CPU_USAGE) {
- info.append("\nCPU usage:\n");
- info.append(processInfo);
+ updateCpuStatsNow();
+ synchronized (mProcessStatsThread) {
+ cpuInfo = mProcessStats.printCurrentState();
+ }
+ info.append(cpuInfo);
}
- 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
+ Slog.e(TAG, info.toString());
+ if (tracesFile == null) {
+ // There is no trace file, so dump (only) the alleged culprit's threads to 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) {
- // First, these are the most important processes.
- final int[] imppids = new int[3];
- int i=0;
- imppids[0] = app.pid;
- i++;
- if (reportedActivity != null && reportedActivity.app != null
- && reportedActivity.app.thread != null
- && reportedActivity.app.pid != app.pid) {
- imppids[i] = reportedActivity.app.pid;
- i++;
- }
- imppids[i] = Process.myPid();
- for (i=0; i<imppids.length && imppids[i] != 0; i++) {
- Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
- synchronized (this) {
- try {
- wait(200);
- } catch (InterruptedException e) {
- }
- }
- }
- for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLRUProcesses.get(i);
- boolean done = false;
- for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
- if (imppids[j] == r.pid) {
- done = true;
- break;
- }
- }
- if (!done && r.thread != null) {
- Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
- synchronized (this) {
- try {
- wait(200);
- } catch (InterruptedException e) {
- }
- }
- }
- }
- }
}
+ addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
+
if (mController != null) {
try {
- int res = mController.appNotResponding(app.processName,
- app.pid, info.toString());
+ // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
+ int res = mController.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;
- }
+ if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
+ return;
}
} catch (RemoteException e) {
mController = 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_IXOTH, -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();
+ // Unless configured otherwise, swallow ANRs in background processes & kill the process.
+ boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+
+ synchronized (this) {
+ if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
+ Process.killProcess(app.pid);
+ return;
}
-
- if (removeExisting) {
- try {
- f.createNewFile();
- FileUtils.setPermissions(f.getAbsolutePath(),
- FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
- fileReady = true;
- } catch (IOException e) {
- Log.w(TAG, "Unable to make ANR traces file", e);
- }
+
+ // Set the app's notResponding state, and look up the errorReportReceiver
+ makeAppNotRespondingLocked(app,
+ activity != null ? activity.shortComponentName : null,
+ annotation != null ? "ANR " + annotation : "ANR",
+ info.toString());
+
+ // Bring up the infamous App Not Responding dialog
+ 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 fileReady;
}
-
private final void decPersistentCountLocked(ProcessRecord app)
{
app.persistentActivities--;
@@ -4841,7 +4928,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -4853,26 +4940,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord r = (HistoryRecord)mHistory.get(index);
ProcessRecord app = r.app;
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Setting persistence " + isPersistent + ": " + r);
if (isPersistent) {
if (r.persistent) {
// Okay okay, I heard you already!
- if (localLOGV) Log.v(TAG, "Already persistent!");
+ if (localLOGV) Slog.v(TAG, "Already persistent!");
return;
}
r.persistent = true;
app.persistentActivities++;
- if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
+ if (localLOGV) Slog.v(TAG, "Num persistent now: " + app.persistentActivities);
if (app.persistentActivities > 1) {
// We aren't the first...
- if (localLOGV) Log.v(TAG, "Not the first!");
+ if (localLOGV) Slog.v(TAG, "Not the first!");
return;
}
if (app.persistent) {
// This would be redundant.
- if (localLOGV) Log.v(TAG, "App is persistent!");
+ if (localLOGV) Slog.v(TAG, "App is persistent!");
return;
}
@@ -4910,14 +4997,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
if (pkgUid == -1) {
- Log.w(TAG, "Invalid packageName:" + packageName);
+ Slog.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);
+ forceStopPackageLocked(packageName, pkgUid);
} else {
throw new SecurityException(pid+" does not have permission:"+
android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
@@ -4944,14 +5031,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- public void restartPackage(final String packageName) {
- if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
+ public void killBackgroundProcesses(final String packageName) {
+ if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+ != PackageManager.PERMISSION_GRANTED &&
+ checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: killBackgroundProcesses() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+ Slog.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) {
+ Slog.w(TAG, "Invalid packageName: " + packageName);
+ return;
+ }
+ killPackageProcessesLocked(packageName, pkgUid,
+ SECONDARY_SERVER_ADJ, false, true);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ public void forceStopPackage(final String packageName) {
+ if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: restartPackage() from pid="
+ String msg = "Permission Denial: forceStopPackage() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.RESTART_PACKAGES;
- Log.w(TAG, msg);
+ + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -4965,10 +5086,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
if (pkgUid == -1) {
- Log.w(TAG, "Invalid packageName: " + packageName);
+ Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
- restartPackageLocked(packageName, pkgUid);
+ forceStopPackageLocked(packageName, pkgUid);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -4985,7 +5106,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
// Make sure the uid is valid.
if (uid < 0) {
- Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
+ Slog.w(TAG, "Invalid uid specified for pkg : " + pkg);
return;
}
int callerUid = Binder.getCallingUid();
@@ -5068,7 +5189,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the other end already died, then our work here is done.
}
} else {
- Log.w(TAG, "Process/uid not found attempting kill of "
+ Slog.w(TAG, "Process/uid not found attempting kill of "
+ processName + " / " + uid);
}
}
@@ -5078,8 +5199,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- private void restartPackageLocked(final String packageName, int uid) {
- uninstallPackageLocked(packageName, uid, false);
+ private void forceStopPackageLocked(final String packageName, int uid) {
+ forceStopPackageLocked(packageName, uid, false, false, true);
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_UID, uid);
@@ -5088,59 +5209,77 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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();
- }
- }
-
+ private final boolean killPackageProcessesLocked(String packageName, int uid,
+ int minOomAdj, boolean callerWillRestart, boolean doit) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
// matches the package name.
+ final String procNamePrefix = packageName + ":";
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);
+ if (doit) {
+ procs.add(app);
+ }
} else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
- || app.processName.equals(name)
+ || app.processName.equals(packageName)
|| app.processName.startsWith(procNamePrefix)) {
- app.removed = true;
- procs.add(app);
+ if (app.setAdj >= minOomAdj) {
+ if (!doit) {
+ return true;
+ }
+ app.removed = true;
+ procs.add(app);
+ }
}
}
}
-
- N = procs.size();
- for (i=0; i<N; i++) {
+
+ int N = procs.size();
+ for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), callerWillRestart);
}
+ return N > 0;
+ }
+
+ private final boolean forceStopPackageLocked(String name, int uid,
+ boolean callerWillRestart, boolean purgeCache, boolean doit) {
+ int i, N;
+
+ if (uid < 0) {
+ try {
+ uid = ActivityThread.getPackageManager().getPackageUid(name);
+ } catch (RemoteException e) {
+ }
+ }
+
+ if (doit) {
+ Slog.i(TAG, "Force stopping package " + name + " uid=" + uid);
+
+ Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
+ while (badApps.hasNext()) {
+ SparseArray<Long> ba = badApps.next();
+ if (ba.get(uid) != null) {
+ badApps.remove();
+ }
+ }
+ }
+
+ boolean didSomething = killPackageProcessesLocked(name, uid, -100,
+ callerWillRestart, doit);
for (i=mHistory.size()-1; i>=0; i--) {
HistoryRecord r = (HistoryRecord)mHistory.get(i);
if (r.packageName.equals(name)) {
- if (Config.LOGD) Log.d(
- TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ Slog.i(TAG, " Force finishing activity " + r);
if (r.app != null) {
r.app.removed = true;
}
@@ -5152,6 +5291,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
for (ServiceRecord service : mServices.values()) {
if (service.packageName.equals(name)) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = true;
}
@@ -5165,13 +5309,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
bringDownServiceLocked(services.get(i), true);
}
- resumeTopActivityLocked(null);
+ if (doit) {
+ if (purgeCache) {
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.removePackage(name);
+ }
+ }
+ resumeTopActivityLocked(null);
+ }
+
+ return didSomething;
}
private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
final String name = app.processName;
final int uid = app.info.uid;
- if (Config.LOGD) Log.d(
+ if (DEBUG_PROCESSES) Slog.d(
TAG, "Force removing process " + app + " (" + name
+ "/" + uid + ")");
@@ -5184,7 +5338,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
handleAppDiedLocked(app, true);
- mLRUProcesses.remove(app);
+ mLruProcesses.remove(app);
Process.killProcess(pid);
if (app.persistent) {
@@ -5213,8 +5367,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (gone) {
- Log.w(TAG, "Process " + app + " failed to attach");
- EventLog.writeEvent(LOG_AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
+ Slog.w(TAG, "Process " + app + " failed to attach");
+ EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
app.processName);
mProcessNames.remove(app.processName, app.info.uid);
// Take care of any launching providers waiting for this process.
@@ -5224,7 +5378,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord sr = mPendingServices.get(i);
if (app.info.uid == sr.appInfo.uid
&& app.processName.equals(sr.processName)) {
- Log.w(TAG, "Forcing bringing down service: " + sr);
+ Slog.w(TAG, "Forcing bringing down service: " + sr);
mPendingServices.remove(i);
i--;
bringDownServiceLocked(sr, true);
@@ -5232,7 +5386,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
Process.killProcess(pid);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
- Log.w(TAG, "Unattached app died before backup, skipping");
+ Slog.w(TAG, "Unattached app died before backup, skipping");
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -5242,12 +5396,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
- Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+ Slog.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);
+ Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
}
}
@@ -5270,9 +5424,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (app == null) {
- Log.w(TAG, "No pending application record for pid " + pid
+ Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
- EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
+ EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
Process.killProcess(pid);
} else {
@@ -5293,7 +5447,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Tell the process all about itself.
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Binding process pid " + pid + " to record " + app);
String processName = app.processName;
@@ -5306,11 +5460,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return false;
}
- EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
app.thread = thread;
app.curAdj = app.setAdj = -100;
- app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false;
@@ -5321,10 +5476,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (!normalMode) {
- Log.i(TAG, "Launching preboot mode app: " + app);
+ Slog.i(TAG, "Launching preboot mode app: " + app);
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
try {
@@ -5353,7 +5508,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app.instrumentationClass != null) {
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
}
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
+ processName + " with config " + mConfiguration);
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
@@ -5361,13 +5516,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked());
- updateLRUListLocked(app, false);
+ updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = 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);
+ Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList();
startProcessLocked(app, "bind fail", processName);
@@ -5391,7 +5546,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
didSomething = true;
}
} catch (Exception e) {
- Log.w(TAG, "Exception in new application when starting activity "
+ Slog.w(TAG, "Exception in new application when starting activity "
+ hr.intent.getComponent().flattenToShortString(), e);
badApp = true;
}
@@ -5417,7 +5572,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
didSomething = true;
}
} catch (Exception e) {
- Log.w(TAG, "Exception in new application when starting service "
+ Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
badApp = true;
}
@@ -5431,7 +5586,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
- Log.w(TAG, "Exception in new application when starting receiver "
+ Slog.w(TAG, "Exception in new application when starting receiver "
+ br.curComponent.flattenToShortString(), e);
badApp = true;
logBroadcastReceiverDiscard(br);
@@ -5445,12 +5600,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Check whether the next backup agent is in this process...
if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
- if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
+ if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
} catch (Exception e) {
- Log.w(TAG, "Exception scheduling backup agent creation: ");
+ Slog.w(TAG, "Exception scheduling backup agent creation: ");
e.printStackTrace();
}
}
@@ -5496,7 +5651,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
&& !mResumedActivity.waitingVisible;
for (int i=0; i<N; i++) {
HistoryRecord s = mStoppingActivities.get(i);
- if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
+ if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
+ nowVisible + " waitingVisible=" + s.waitingVisible
+ " finishing=" + s.finishing);
if (s.waitingVisible && nowVisible) {
@@ -5508,12 +5663,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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);
+ if (localLOGV) Slog.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 (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
if (stops == null) {
stops = new ArrayList<HistoryRecord>();
}
@@ -5528,14 +5683,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void enableScreenAfterBoot() {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
}
final void activityIdleInternal(IBinder token, boolean fromTimeout,
Configuration config) {
- if (localLOGV) Log.v(TAG, "Activity idle: " + token);
+ if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
ArrayList<HistoryRecord> stops = null;
ArrayList<HistoryRecord> finishes = null;
@@ -5557,6 +5712,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
+ if (fromTimeout) {
+ reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
+ }
+
// This is a hack to semi-deal with a race condition
// in the client where it can be constructed with a
// newer configuration from when we asked it to launch.
@@ -5583,14 +5742,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If this activity is fullscreen, set up to hide those under it.
- if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
+ if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + r);
ensureActivitiesVisibleLocked(null, 0);
- //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
+ //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
if (!mBooted && !fromTimeout) {
mBooted = true;
enableScreen = true;
}
+
+ } else if (fromTimeout) {
+ reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
}
// Atomically retrieve all of the other things to do.
@@ -5616,7 +5778,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
sendThumbnail.requestThumbnail(token);
} catch (Exception e) {
- Log.w(TAG, "Exception thrown when requesting thumbnail", e);
+ Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
sendPendingThumbnail(null, token, null, null, true);
}
}
@@ -5663,21 +5825,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
final void finishBooting() {
- // Ensure that any processes we had put on hold are now started
- // up.
- final int NP = mProcessesOnHold.size();
- if (NP > 0) {
- ArrayList<ProcessRecord> procs =
- new ArrayList<ProcessRecord>(mProcessesOnHold);
- for (int ip=0; ip<NP; ip++) {
- synchronized (this) {
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ pkgFilter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ if (pkgs != null) {
+ for (String pkg : pkgs) {
+ if (forceStopPackageLocked(pkg, -1, false, false, false)) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ }
+ }
+ }
+ }, pkgFilter);
+
+ synchronized (this) {
+ // Ensure that any processes we had put on hold are now started
+ // up.
+ final int NP = mProcessesOnHold.size();
+ if (NP > 0) {
+ ArrayList<ProcessRecord> procs =
+ new ArrayList<ProcessRecord>(mProcessesOnHold);
+ for (int ip=0; ip<NP; ip++) {
this.startProcessLocked(procs.get(ip), "on-hold", null);
}
}
- }
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- // Tell anyone interested that we are done booting!
- synchronized (this) {
+
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ // Tell anyone interested that we are done booting!
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
@@ -5718,7 +5897,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
- if (DEBUG_PAUSE) Log.v(
+ if (DEBUG_PAUSE) Slog.v(
TAG, "Activity paused: token=" + token + ", icicle=" + icicle
+ ", timeout=" + timeout);
@@ -5737,7 +5916,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
- EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
+ EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
@@ -5748,7 +5927,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public final void activityStopped(IBinder token, Bitmap thumbnail,
CharSequence description) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "Activity stopped: token=" + token);
HistoryRecord r = null;
@@ -5782,7 +5961,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public final void activityDestroyed(IBinder token) {
- if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
+ if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
synchronized (this) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
@@ -5873,7 +6052,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ ", uid=" + Binder.getCallingUid()
+ ", (need uid=" + uid + ")"
+ " is not allowed to send as package " + packageName;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
@@ -5945,7 +6124,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ ", uid=" + Binder.getCallingUid()
+ " is not allowed to cancel packges "
+ rec.key.packageName;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} catch (RemoteException e) {
@@ -5967,12 +6146,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!(pendingResult instanceof PendingIntentRecord)) {
return null;
}
- synchronized(this) {
- try {
- PendingIntentRecord res = (PendingIntentRecord)pendingResult;
- return res.key.packageName;
- } catch (ClassCastException e) {
- }
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+ return res.key.packageName;
+ } catch (ClassCastException e) {
}
return null;
}
@@ -6016,7 +6193,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (mPidsSelfLocked) {
ProcessRecord pr = mPidsSelfLocked.get(pid);
if (pr == null) {
- Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
+ Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
return;
}
ForegroundToken oldToken = mForegroundProcesses.get(pid);
@@ -6078,7 +6255,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// client identity accordingly before proceeding.
Identity tlsIdentity = sCallerIdentity.get();
if (tlsIdentity != null) {
- Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
+ Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
+ tlsIdentity.pid + "," + tlsIdentity.uid + "}");
uid = tlsIdentity.uid;
pid = tlsIdentity.pid;
@@ -6091,7 +6268,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
// If the target requires a specific UID, always fail for others.
if (reqUid >= 0 && uid != reqUid) {
- Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
+ Slog.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
@@ -6102,7 +6279,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
// Should never happen, but if it does... deny!
- Log.e(TAG, "PackageManager is dead?!?", e);
+ Slog.e(TAG, "PackageManager is dead?!?", e);
}
return PackageManager.PERMISSION_DENIED;
}
@@ -6146,7 +6323,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + permission;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -6214,10 +6391,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Requested grant " + targetPkg + " permission to " + uri);
+
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())) {
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Can't grant URI permission for non-content URI: " + uri);
return;
}
@@ -6235,7 +6417,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
if (pi == null) {
- Log.w(TAG, "No content provider found for: " + name);
+ Slog.w(TAG, "No content provider found for: " + name);
return;
}
@@ -6243,6 +6425,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
targetUid = pm.getPackageUid(targetPkg);
if (targetUid < 0) {
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Can't grant URI permission no uid for: " + targetPkg);
return;
}
} catch (RemoteException ex) {
@@ -6252,17 +6436,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// First... does the target actually need this permission?
if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
// No need to grant the target this permission.
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Target " + targetPkg + " already has full permission to " + uri);
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?
+ // Second... is the provider allowing granting of URI permissions?
if (!pi.grantUriPermissions) {
throw new SecurityException("Provider " + pi.packageName
+ "/" + pi.name
@@ -6287,7 +6466,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- // Fourth... does the caller itself have permission to access
+ // Third... does the caller itself have permission to access
// this uri?
if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
@@ -6300,6 +6479,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// to the uri, and the target doesn't. Let's now give this to
// the target.
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Granting " + targetPkg + " permission to " + uri);
+
HashMap<Uri, UriPermission> targetUris
= mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
@@ -6354,11 +6536,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " when granting permission to uri " + uri);
}
if (targetPkg == null) {
- Log.w(TAG, "grantUriPermission: null target");
+ Slog.w(TAG, "grantUriPermission: null target");
return;
}
if (uri == null) {
- Log.w(TAG, "grantUriPermission: null uri");
+ Slog.w(TAG, "grantUriPermission: null uri");
return;
}
@@ -6373,6 +6555,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HashMap<Uri, UriPermission> perms
= mGrantedUriPermissions.get(perm.uid);
if (perms != null) {
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Removing " + perm.uid + " permission to " + perm.uri);
perms.remove(perm.uri);
if (perms.size() == 0) {
mGrantedUriPermissions.remove(perm.uid);
@@ -6412,6 +6596,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Revoking all granted permissions to " + uri);
+
final IPackageManager pm = ActivityThread.getPackageManager();
final String authority = uri.getAuthority();
@@ -6428,7 +6615,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
if (pi == null) {
- Log.w(TAG, "No content provider found for: " + authority);
+ Slog.w(TAG, "No content provider found for: " + authority);
return;
}
@@ -6470,6 +6657,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
continue toploop;
}
}
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ "Revoking " + perm.uid + " permission to " + perm.uri);
perm.clearModes(modeFlags);
if (perm.modeFlags == 0) {
it.remove();
@@ -6495,7 +6684,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " when revoking permission to uri " + uri);
}
if (uri == null) {
- Log.w(TAG, "revokeUriPermission: null uri");
+ Slog.w(TAG, "revokeUriPermission: null uri");
return;
}
@@ -6521,7 +6710,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
if (pi == null) {
- Log.w(TAG, "No content provider found for: " + authority);
+ Slog.w(TAG, "No content provider found for: " + authority);
return;
}
@@ -6563,7 +6752,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord topRecord = null;
synchronized(this) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "getTasks: max=" + maxNum + ", flags=" + flags
+ ", receiver=" + receiver);
@@ -6581,7 +6770,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + android.Manifest.permission.GET_TASKS;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -6617,7 +6806,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
topDescription = r.description;
}
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, r.intent.getComponent().flattenToShortString()
+ ": task=" + r.task);
@@ -6636,7 +6825,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//System.out.println(
// "#" + maxNum + ": " + " descr=" + ci.description);
if (ci.thumbnail == null && receiver != null) {
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "State=" + top.state + "Idle=" + top.idle
+ " app=" + top.app
+ " thr=" + (top.app != null ? top.app.thread : null));
@@ -6666,14 +6855,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
+ if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
if (topThumbnail != null) {
- if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
+ if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
try {
topThumbnail.requestThumbnail(topRecord);
} catch (Exception e) {
- Log.w(TAG, "Exception thrown when requesting thumbnail", e);
+ Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
sendPendingThumbnail(null, topRecord, null, null, true);
}
}
@@ -6698,6 +6887,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
enforceCallingPermission(android.Manifest.permission.GET_TASKS,
"getRecentTasks()");
+ IPackageManager pm = ActivityThread.getPackageManager();
+
final int N = mRecentTasks.size();
ArrayList<ActivityManager.RecentTaskInfo> res
= new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -6714,6 +6905,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
rti.baseIntent = new Intent(
tr.intent != null ? tr.intent : tr.affinityIntent);
rti.origActivity = tr.origActivity;
+
+ if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
+ // Check whether this activity is currently available.
+ try {
+ if (rti.origActivity != null) {
+ if (pm.getActivityInfo(rti.origActivity, 0) == null) {
+ continue;
+ }
+ } else if (rti.baseIntent != null) {
+ if (pm.queryIntentActivities(rti.baseIntent,
+ null, 0) == null) {
+ continue;
+ }
+ }
+ } catch (RemoteException e) {
+ // Will never happen.
+ }
+ }
+
res.add(rti);
maxNum--;
}
@@ -6846,7 +7056,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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
+ if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to bottom task " + p.task);
} else {
mCurTask++;
@@ -6856,7 +7066,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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
+ if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
}
mWindowManager.setAppGroupId(target, task.taskId);
@@ -6869,7 +7079,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (p.finishing) {
continue;
}
- if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
+ if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
+ " out to target's task " + target.task);
task.numActivities--;
p.task = target.task;
@@ -7006,7 +7216,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
p.task.numActivities--;
p.task = task;
mHistory.add(lastReparentPos, p);
- if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
+ if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+ " in to resetting task " + task);
task.numActivities++;
mWindowManager.moveAppToken(lastReparentPos, p);
@@ -7082,7 +7292,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
- if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
+ if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
final int task = tr.taskId;
int top = mHistory.size()-1;
@@ -7103,11 +7313,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// of the stack, keeping them in the same internal order.
while (pos >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(pos);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.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);
+ if (localLOGV) Slog.v(TAG, "Removing and adding at " + top);
mHistory.remove(pos);
mHistory.add(top, r);
moved.add(0, r);
@@ -7120,7 +7330,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pos--;
}
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare to front transition: task=" + tr);
if (reason != null &&
(reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -7139,7 +7349,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
finishTaskMoveLocked(task);
- EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
+ EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
}
private final void finishTaskMoveLocked(int task) {
@@ -7196,7 +7406,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* @return Returns true if the move completed, false if not.
*/
private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
- Log.i(TAG, "moveTaskToBack: " + task);
+ Slog.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
@@ -7222,7 +7432,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ArrayList moved = new ArrayList();
- if (DEBUG_TRANSITION) Log.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare to back transition: task=" + task);
final int N = mHistory.size();
@@ -7233,10 +7443,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// of the stack, keeping them in the same internal order.
while (pos < N) {
HistoryRecord r = (HistoryRecord)mHistory.get(pos);
- if (localLOGV) Log.v(
+ if (localLOGV) Slog.v(
TAG, "At " + pos + " ckp " + r.task + ": " + r);
if (r.task.taskId == task) {
- if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
+ if (localLOGV) Slog.v(TAG, "Removing and adding at " + (N-1));
mHistory.remove(pos);
mHistory.add(bottom, r);
moved.add(r);
@@ -7280,7 +7490,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void moveTaskBackwardsLocked(int task) {
- Log.e(TAG, "moveTaskBackwards not yet implemented!");
+ Slog.e(TAG, "moveTaskBackwards not yet implemented!");
}
public int getTaskForActivity(IBinder token, boolean onlyRoot) {
@@ -7324,25 +7534,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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()
+ //Slog.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!");
+ //Slog.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!");
+ //Slog.i(TAG, "Found matching class!");
//dump();
- //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+ //Slog.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!");
+ //Slog.i(TAG, "Found matching class!");
//dump();
- //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+ //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
return r;
}
}
@@ -7367,9 +7577,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord r = (HistoryRecord)mHistory.get(i);
if (!r.finishing) {
if (r.intent.getComponent().equals(cls)) {
- //Log.i(TAG, "Found matching class!");
+ //Slog.i(TAG, "Found matching class!");
//dump();
- //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
+ //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
return r;
}
}
@@ -7474,7 +7684,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pr.receiver.finished();
}
} catch (Exception e) {
- Log.w(TAG, "Exception thrown when sending thumbnail", e);
+ Slog.w(TAG, "Exception thrown when sending thumbnail", e);
}
}
}
@@ -7551,7 +7761,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ ", uid=" + callingUid + ") requires "
+ cpi.readPermission + " or " + cpi.writePermission;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
return msg;
}
@@ -7600,7 +7810,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// In this case the provider instance already exists, so we can
// return it right away.
if (r != null) {
- if (DEBUG_PROVIDER) Log.v(TAG,
+ if (DEBUG_PROVIDER) Slog.v(TAG,
"Adding provider requested by "
+ r.processName + " from process "
+ cpr.info.processName);
@@ -7638,6 +7848,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? cpi.readPermission : cpi.writePermission);
}
+ if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
+ && !cpi.processName.equals("system")) {
+ // If this content provider does not run in the system
+ // process, and the system is not yet ready to run other
+ // processes, then fail fast instead of hanging.
+ throw new IllegalArgumentException(
+ "Attempt to launch content provider before system ready");
+ }
+
cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
final boolean firstClass = cpr == null;
if (firstClass) {
@@ -7648,7 +7867,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS);
if (ai == null) {
- Log.w(TAG, "No package info for content provider "
+ Slog.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
}
@@ -7668,7 +7887,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_PROVIDER) {
RuntimeException e = new RuntimeException("here");
- Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
+ Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
+ " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
}
@@ -7692,7 +7911,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false);
if (proc == null) {
- Log.w(TAG, "Unable to launch app "
+ Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
@@ -7711,7 +7930,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mProvidersByName.put(name, cpr);
if (r != null) {
- if (DEBUG_PROVIDER) Log.v(TAG,
+ if (DEBUG_PROVIDER) Slog.v(TAG,
"Adding provider requested by "
+ r.processName + " from process "
+ cpr.info.processName);
@@ -7732,11 +7951,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
- Log.w(TAG, "Unable to launch app "
+ Slog.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,
+ EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
return null;
@@ -7755,7 +7974,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -7775,7 +7994,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
if(cpr == null) {
// remove from mProvidersByClass
- if (DEBUG_PROVIDER) Log.v(TAG, name +
+ if (DEBUG_PROVIDER) Slog.v(TAG, name +
" provider not found in providers list");
return;
}
@@ -7788,12 +8007,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//update content provider record entry info
ContentProviderRecord localCpr = (ContentProviderRecord)
mProvidersByClass.get(cpr.info.name);
- if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
+ if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by "
+ r.info.processName + " from process "
+ localCpr.appInfo.processName);
if (localCpr.app == r) {
//should not happen. taken care of as a local provider
- Log.w(TAG, "removeContentProvider called on local provider: "
+ Slog.w(TAG, "removeContentProvider called on local provider: "
+ cpr.info.name + " in process " + r.processName);
return;
} else {
@@ -7814,7 +8033,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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");
+ if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list");
return;
}
@@ -7822,7 +8041,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
localCpr.externals--;
if (localCpr.externals < 0) {
- Log.e(TAG, "Externals < 0 for content provider " + localCpr);
+ Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
}
updateOomAdjLocked();
}
@@ -7883,10 +8102,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public static final void installSystemProviders() {
- List providers = null;
+ List providers;
synchronized (mSelf) {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
providers = mSelf.generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i=providers.size()-1; i>=0; i--) {
+ ProviderInfo pi = (ProviderInfo)providers.get(i);
+ if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Slog.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
+ }
+ }
}
if (providers != null) {
mSystemThread.installSystemProviders(providers);
@@ -7914,7 +8143,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app == null) {
app = newProcessRecordLocked(null, info, null);
mProcessNames.put(info.processName, info.uid, app);
- updateLRUListLocked(app, true);
+ updateLruProcessLocked(app, true, true);
}
if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
@@ -7936,7 +8165,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
int count = mHistory.size();
- if (Config.LOGD) Log.d(
+ if (DEBUG_SWITCH) Slog.d(
TAG, "Performing unhandledBack(): stack size = " + count);
if (count > 1) {
final long origId = Binder.clearCallingIdentity();
@@ -7973,7 +8202,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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 + "'");
+ Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
}
return pfd;
}
@@ -7986,7 +8215,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mResumedActivity != null) {
pauseIfSleepingLocked();
} else {
- Log.w(TAG, "goingToSleep with no resumed activity!");
+ Slog.w(TAG, "goingToSleep with no resumed activity!");
}
}
}
@@ -8010,7 +8239,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (mResumedActivity != null || mPausingActivity != null) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
- Log.w(TAG, "Activity manager shutdown timed out");
+ Slog.w(TAG, "Activity manager shutdown timed out");
timedout = true;
break;
}
@@ -8042,8 +8271,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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");
+ if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause...");
+ if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
startPausingLocked(false, true);
}
}
@@ -8105,7 +8334,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- Log.w(TAG, name + " request from " + callingUid + " stopped");
+ Slog.w(TAG, name + " request from " + callingUid + " stopped");
return false;
}
@@ -8137,7 +8366,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mDebugTransient = !persistent;
if (packageName != null) {
final long origId = Binder.clearCallingIdentity();
- uninstallPackageLocked(packageName, -1, false);
+ forceStopPackageLocked(packageName, -1, false, false, true);
Binder.restoreCallingIdentity(origId);
}
}
@@ -8164,6 +8393,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public boolean isUserAMonkey() {
+ // For now the fact that there is a controller implies
+ // we have a monkey.
+ synchronized (this) {
+ return mController != null;
+ }
+ }
+
public void registerActivityWatcher(IActivityWatcher watcher) {
synchronized (this) {
mWatchers.register(watcher);
@@ -8220,11 +8457,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- public boolean killPidsForMemory(int[] pids) {
+ public boolean killPids(int[] pids, String pReason) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("killPidsForMemory only available to the system");
+ throw new SecurityException("killPids only available to the system");
}
-
+ String reason = (pReason == null) ? "Unknown" : pReason;
// XXX Note: don't acquire main activity lock here, because the window
// manager calls in with its locks held.
@@ -8248,7 +8485,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
for (int i=0; i<pids.length; i++) {
ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
if (proc == null) {
@@ -8256,10 +8493,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
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);
+ Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
+ EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+ proc.processName, adj, reason);
killed = true;
Process.killProcess(pids[i]);
}
@@ -8295,8 +8531,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
mRequestPssCallback = completeCallback;
mRequestPssList.clear();
- for (int i=mLRUProcesses.size()-1; i>=0; i--) {
- ProcessRecord proc = mLRUProcesses.get(i);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
if (!proc.persistent) {
mRequestPssList.add(proc);
}
@@ -8356,25 +8592,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
i++;
}
- for (i=mLRUProcesses.size()-1; i>=0; i--) {
- ProcessRecord proc = mLRUProcesses.get(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);
+ //Slog.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++;
+ if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
+ if (proc.empty) {
+ stats.mEmptyPss += proc.lastPss;
+ stats.mEmptyCount++;
+ } else {
+ stats.mBackgroundPss += proc.lastPss;
+ stats.mBackgroundCount++;
+ }
} else if (proc.setAdj >= VISIBLE_APP_ADJ) {
stats.mVisiblePss += proc.lastPss;
stats.mVisibleCount++;
@@ -8424,7 +8659,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// This happens before any activities are started, so we can
// change mConfiguration in-place.
mConfiguration.updateFrom(configuration);
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
+ mConfigurationSeq = mConfiguration.seq = 1;
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Initial config: " + mConfiguration);
}
}
@@ -8471,7 +8707,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ActivityInfo ai = ris.get(i).activityInfo;
intent.setComponent(new ComponentName(ai.packageName, ai.name));
IIntentReceiver finisher = null;
- if (i == 0) {
+ if (i == ris.size()-1) {
finisher = new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
@@ -8484,10 +8720,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
};
}
- Log.i(TAG, "Sending system update to: " + intent.getComponent());
+ Slog.i(TAG, "Sending system update to: " + intent.getComponent());
broadcastIntentLocked(null, null, intent, null, finisher,
0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
- if (i == 0) {
+ if (finisher != null) {
mWaitingUpdate = true;
}
}
@@ -8521,14 +8757,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
- Log.i(TAG, "Removing system update proc: " + proc);
+ Slog.i(TAG, "Removing system update proc: " + proc);
removeProcessLocked(proc, true);
}
}
}
- Log.i(TAG, "System now ready");
- EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
+ Slog.i(TAG, "System now ready");
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis());
synchronized(this) {
@@ -8609,89 +8845,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- boolean makeAppCrashingLocked(ProcessRecord app,
- String tag, String shortMsg, String longMsg, byte[] crashData) {
+ private boolean makeAppCrashingLocked(ProcessRecord app,
+ String shortMsg, String longMsg, String stackTrace) {
app.crashing = true;
- app.crashingReport = generateProcessError(app,
- ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
+ app.crashingReport = generateProcessError(app,
+ ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
startAppProblemLocked(app);
app.stopFreezingAllLocked();
return handleAppCrashLocked(app);
}
- private ComponentName getErrorReportReceiver(ProcessRecord app) {
- // check if error reporting is enabled in Gservices
- int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
- Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
- if (enabled == 0) {
- return null;
- }
-
- IPackageManager pm = ActivityThread.getPackageManager();
-
- try {
- // look for receiver in the installer package
- String candidate = pm.getInstallerPackageName(app.info.packageName);
- ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
- if (result != null) {
- return result;
- }
-
- // if the error app is on the system image, look for system apps
- // error receiver
- if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
- candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
- result = getErrorReportReceiver(pm, app.info.packageName, candidate);
- if (result != null) {
- return result;
- }
- }
-
- // if there is a default receiver, try that
- candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
- return getErrorReportReceiver(pm, app.info.packageName, candidate);
- } catch (RemoteException e) {
- // should not happen
- Log.e(TAG, "error talking to PackageManager", e);
- return null;
- }
- }
-
- /**
- * Return activity in receiverPackage that handles ACTION_APP_ERROR.
- *
- * @param pm PackageManager isntance
- * @param errorPackage package which caused the error
- * @param receiverPackage candidate package to receive the error
- * @return activity component within receiverPackage which handles
- * ACTION_APP_ERROR, or null if not found
- */
- private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
- String receiverPackage) throws RemoteException {
- if (receiverPackage == null || receiverPackage.length() == 0) {
- return null;
- }
-
- // break the loop if it's the error report receiver package that crashed
- if (receiverPackage.equals(errorPackage)) {
- return null;
- }
-
- Intent intent = new Intent(Intent.ACTION_APP_ERROR);
- intent.setPackage(receiverPackage);
- ResolveInfo info = pm.resolveIntent(intent, null, 0);
- if (info == null || info.activityInfo == null) {
- return null;
- }
- return new ComponentName(receiverPackage, info.activityInfo.name);
- }
-
- void makeAppNotRespondingLocked(ProcessRecord app,
- String tag, String shortMsg, String longMsg, byte[] crashData) {
+ private void makeAppNotRespondingLocked(ProcessRecord app,
+ String activity, String shortMsg, String longMsg) {
app.notResponding = true;
- app.notRespondingReport = generateProcessError(app,
- ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
- crashData);
+ app.notRespondingReport = generateProcessError(app,
+ ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
+ activity, shortMsg, longMsg, null);
startAppProblemLocked(app);
app.stopFreezingAllLocked();
}
@@ -8702,31 +8871,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* @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 activity The activity associated with the crash, if known.
* @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.
- *
+ * @param stackTrace Full crash stack trace, may be null.
+ *
* @return Returns a fully-formed AppErrorStateInfo record.
*/
private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
- int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
+ int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
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.tag = activity;
report.shortMsg = shortMsg;
report.longMsg = longMsg;
- report.crashData = crashData;
+ report.stackTrace = stackTrace;
return report;
}
- void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
- boolean crashed) {
+ void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
synchronized (this) {
app.crashing = false;
app.crashingReport = null;
@@ -8739,35 +8907,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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");
+ handleAppCrashLocked(app);
+ Slog.i(ActivityManagerService.TAG, "Killing "
+ + app.processName + " (pid=" + app.pid + "): user's request");
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "user's request after error");
Process.killProcess(app.pid);
}
-
}
}
-
- boolean handleAppCrashLocked(ProcessRecord app) {
+
+ private 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
+ Slog.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
- EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
+ EventLog.writeEvent(EventLogTags.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 "
+ Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
}
@@ -8777,7 +8942,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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,
+ EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
app.info.processName);
mBadProcesses.put(app.info.processName, app.info.uid, now);
app.bad = true;
@@ -8786,6 +8951,34 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
removeProcessLocked(app, false);
return false;
}
+ } else {
+ HistoryRecord r = topRunningActivityLocked(null);
+ if (r.app == app) {
+ // If the top running activity is from this crashing
+ // process, then terminate it to avoid getting in a loop.
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ int index = indexOfTokenLocked(r);
+ finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed");
+ // Also terminate an activities below it that aren't yet
+ // stopped, to avoid a situation where one will get
+ // re-start our crashing activity once it gets resumed again.
+ index--;
+ if (index >= 0) {
+ r = (HistoryRecord)mHistory.get(index);
+ if (r.state == ActivityState.RESUMED
+ || r.state == ActivityState.PAUSING
+ || r.state == ActivityState.PAUSED) {
+ if (!r.isHomeActivity) {
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ finishActivityLocked(r, index,
+ Activity.RESULT_CANCELED, null, "crashed");
+ }
+ }
+ }
+ }
}
// Bump up the crash count of any services currently running in the proc.
@@ -8804,7 +8997,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void startAppProblemLocked(ProcessRecord app) {
- app.errorReportReceiver = getErrorReportReceiver(app);
+ app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mContext, app.info.packageName, app.info.flags);
skipCurrentReceiverLocked(app);
}
@@ -8822,7 +9016,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
r = mPendingBroadcast;
if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG,
"skip & discard pending app " + r);
logBroadcastReceiverDiscard(r);
finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
@@ -8834,42 +9028,241 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- public int handleApplicationError(IBinder app, int flags,
- String tag, String shortMsg, String longMsg, byte[] crashData) {
- AppErrorResult result = new AppErrorResult();
- ProcessRecord r = null;
+ /**
+ * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
+ * The application process will exit immediately after this call returns.
+ * @param app object of the crashing app, null for the system server
+ * @param crashInfo describing the exception
+ */
+ public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
+ ProcessRecord r = findAppProcess(app);
+
+ EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
+ app == null ? "system" : (r == null ? "unknown" : r.processName),
+ r == null ? -1 : r.info.flags,
+ crashInfo.exceptionClassName,
+ crashInfo.exceptionMessage,
+ crashInfo.throwFileName,
+ crashInfo.throwLineNumber);
+
+ addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
+
+ crashApplication(r, crashInfo);
+ }
+
+ /**
+ * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
+ * @param app object of the crashing app, null for the system server
+ * @param tag reported by the caller
+ * @param crashInfo describing the context of the error
+ * @return true if the process should exit immediately (WTF is fatal)
+ */
+ public boolean handleApplicationWtf(IBinder app, String tag,
+ ApplicationErrorReport.CrashInfo crashInfo) {
+ ProcessRecord r = findAppProcess(app);
+
+ EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
+ app == null ? "system" : (r == null ? "unknown" : r.processName),
+ r == null ? -1 : r.info.flags,
+ tag, crashInfo.exceptionMessage);
+
+ addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
+
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WTF_IS_FATAL, 0) != 0) {
+ crashApplication(r, crashInfo);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
+ * @return the corresponding {@link ProcessRecord} object, or null if none could be found
+ */
+ private ProcessRecord findAppProcess(IBinder app) {
+ if (app == null) {
+ return 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;
+ 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) {
+ return p;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Can't find mystery application: " + app);
+ return null;
+ }
+ }
+
+ /**
+ * Write a description of an error (crash, WTF, ANR) to the drop box.
+ * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
+ * @param process which caused the error, null means the system server
+ * @param activity which triggered the error, null if unknown
+ * @param parent activity related to the error, null if unknown
+ * @param subject line related to the error, null if absent
+ * @param report in long form describing the error, null if absent
+ * @param logFile to include in the report, null if none
+ * @param crashInfo giving an application stack trace, null if absent
+ */
+ public void addErrorToDropBox(String eventType,
+ ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject,
+ final String report, final File logFile,
+ final ApplicationErrorReport.CrashInfo crashInfo) {
+ // NOTE -- this must never acquire the ActivityManagerService lock,
+ // otherwise the watchdog may be prevented from resetting the system.
+
+ String prefix;
+ if (process == null || process.pid == MY_PID) {
+ prefix = "system_server_";
+ } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ prefix = "system_app_";
+ } else {
+ prefix = "data_app_";
+ }
+
+ final String dropboxTag = prefix + eventType;
+ final DropBoxManager dbox = (DropBoxManager)
+ mContext.getSystemService(Context.DROPBOX_SERVICE);
+
+ // Exit early if the dropbox isn't configured to accept this report type.
+ if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
+
+ final StringBuilder sb = new StringBuilder(1024);
+ if (process == null || process.pid == MY_PID) {
+ sb.append("Process: system_server\n");
+ } else {
+ sb.append("Process: ").append(process.processName).append("\n");
+ }
+ if (process != null) {
+ int flags = process.info.flags;
+ IPackageManager pm = ActivityThread.getPackageManager();
+ sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
+ for (String pkg : process.pkgList) {
+ sb.append("Package: ").append(pkg);
+ try {
+ PackageInfo pi = pm.getPackageInfo(pkg, 0);
+ if (pi != null) {
+ sb.append(" v").append(pi.versionCode);
+ if (pi.versionName != null) {
+ sb.append(" (").append(pi.versionName).append(")");
}
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error getting package info: " + pkg, e);
}
+ sb.append("\n");
}
+ }
+ if (activity != null) {
+ sb.append("Activity: ").append(activity.shortComponentName).append("\n");
+ }
+ if (parent != null && parent.app != null && parent.app.pid != process.pid) {
+ sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
+ }
+ if (parent != null && parent != activity) {
+ sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
+ }
+ if (subject != null) {
+ sb.append("Subject: ").append(subject).append("\n");
+ }
+ sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+ sb.append("\n");
- 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);
+ // Do the rest in a worker thread to avoid blocking the caller on I/O
+ // (After this point, we shouldn't access AMS internal data structures.)
+ Thread worker = new Thread("Error dump: " + dropboxTag) {
+ @Override
+ public void run() {
+ if (report != null) {
+ sb.append(report);
+ }
+ if (logFile != null) {
+ try {
+ sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading " + logFile, e);
+ }
+ }
+ if (crashInfo != null && crashInfo.stackTrace != null) {
+ sb.append(crashInfo.stackTrace);
+ }
+
+ String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag;
+ int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0);
+ if (lines > 0) {
+ sb.append("\n");
+
+ // Merge several logcat streams, and take the last N lines
+ InputStreamReader input = null;
+ try {
+ java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
+ "-v", "time", "-b", "events", "-b", "system", "-b", "main",
+ "-t", String.valueOf(lines)).redirectErrorStream(true).start();
+
+ try { logcat.getOutputStream().close(); } catch (IOException e) {}
+ try { logcat.getErrorStream().close(); } catch (IOException e) {}
+ input = new InputStreamReader(logcat.getInputStream());
+
+ int num;
+ char[] buf = new char[8192];
+ while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error running logcat", e);
+ } finally {
+ if (input != null) try { input.close(); } catch (IOException e) {}
+ }
+ }
+
+ dbox.addText(dropboxTag, sb.toString());
}
+ };
+
+ if (process == null || process.pid == MY_PID) {
+ worker.run(); // We may be about to die -- need to run this synchronously
+ } else {
+ worker.start();
+ }
+ }
+ /**
+ * Bring up the "unexpected error" dialog box for a crashing app.
+ * Deal with edge cases (intercepts from instrumented applications,
+ * ActivityController, error intent receivers, that sort of thing).
+ * @param r the application crashing
+ * @param crashInfo describing the failure
+ */
+ private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+ long timeMillis = System.currentTimeMillis();
+ String shortMsg = crashInfo.exceptionClassName;
+ String longMsg = crashInfo.exceptionMessage;
+ String stackTrace = crashInfo.stackTrace;
+ if (shortMsg != null && longMsg != null) {
+ longMsg = shortMsg + ": " + longMsg;
+ } else if (shortMsg != null) {
+ longMsg = shortMsg;
+ }
+
+ AppErrorResult result = new AppErrorResult();
+ synchronized (this) {
if (mController != null) {
try {
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : Binder.getCallingPid();
if (!mController.appCrashed(name, pid,
- shortMsg, longMsg, crashData)) {
- Log.w(TAG, "Force-killing crashed app " + name
+ shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
+ Slog.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
Process.killProcess(pid);
- return 0;
+ return;
}
} catch (RemoteException e) {
mController = null;
@@ -8880,29 +9273,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If this process is running instrumentation, finish it.
if (r != null && r.instrumentationClass != null) {
- Log.w(TAG, "Error in app " + r.processName
+ Slog.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);
+ if (shortMsg != null) Slog.w(TAG, " " + shortMsg);
+ if (longMsg != null) Slog.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;
+ return;
}
- 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);
+ // If we can't identify the process or it's already exceeded its crash quota,
+ // quit right away without showing a crash dialog.
+ if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
Binder.restoreCallingIdentity(origId);
- return 0;
+ return;
}
Message msg = Message.obtain();
@@ -8910,13 +9297,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
@@ -8932,8 +9312,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
SystemClock.uptimeMillis());
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
- appErrorIntent = createAppErrorIntentLocked(r);
- res = AppErrorDialog.FORCE_QUIT;
+ appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
}
@@ -8941,15 +9320,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
mContext.startActivity(appErrorIntent);
} catch (ActivityNotFoundException e) {
- Log.w(TAG, "bug report receiver dissappeared", e);
+ Slog.w(TAG, "bug report receiver dissappeared", e);
}
}
-
- return res;
}
-
- Intent createAppErrorIntentLocked(ProcessRecord r) {
- ApplicationErrorReport report = createAppErrorReportLocked(r);
+
+ Intent createAppErrorIntentLocked(ProcessRecord r,
+ long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
+ ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
if (report == null) {
return null;
}
@@ -8960,7 +9338,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return result;
}
- ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
+ private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
+ long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
if (r.errorReportReceiver == null) {
return null;
}
@@ -8969,58 +9348,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return null;
}
- try {
- ApplicationErrorReport report = new ApplicationErrorReport();
- report.packageName = r.info.packageName;
- report.installerPackageName = r.errorReportReceiver.getPackageName();
- report.processName = r.processName;
-
- if (r.crashing) {
- report.type = ApplicationErrorReport.TYPE_CRASH;
- report.crashInfo = new ApplicationErrorReport.CrashInfo();
-
- ByteArrayInputStream byteStream = new ByteArrayInputStream(
- r.crashingReport.crashData);
- DataInputStream dataStream = new DataInputStream(byteStream);
- CrashData crashData = new CrashData(dataStream);
- ThrowableData throwData = crashData.getThrowableData();
-
- report.time = crashData.getTime();
- report.crashInfo.stackTrace = throwData.toString();
-
- // Extract the source of the exception, useful for report
- // clustering. Also extract the "deepest" non-null exception
- // message.
- String exceptionMessage = throwData.getMessage();
- while (throwData.getCause() != null) {
- throwData = throwData.getCause();
- String msg = throwData.getMessage();
- if (msg != null && msg.length() > 0) {
- exceptionMessage = msg;
- }
- }
- StackTraceElementData trace = throwData.getStackTrace()[0];
- report.crashInfo.exceptionMessage = exceptionMessage;
- report.crashInfo.exceptionClassName = throwData.getType();
- report.crashInfo.throwFileName = trace.getFileName();
- report.crashInfo.throwClassName = trace.getClassName();
- report.crashInfo.throwMethodName = trace.getMethodName();
- report.crashInfo.throwLineNumber = trace.getLineNumber();
- } else if (r.notResponding) {
- report.type = ApplicationErrorReport.TYPE_ANR;
- report.anrInfo = new ApplicationErrorReport.AnrInfo();
-
- report.anrInfo.activity = r.notRespondingReport.tag;
- report.anrInfo.cause = r.notRespondingReport.shortMsg;
- report.anrInfo.info = r.notRespondingReport.longMsg;
- }
-
- return report;
- } catch (IOException e) {
- // we don't send it
+ ApplicationErrorReport report = new ApplicationErrorReport();
+ report.packageName = r.info.packageName;
+ report.installerPackageName = r.errorReportReceiver.getPackageName();
+ report.processName = r.processName;
+ report.time = timeMillis;
+ report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+ if (r.crashing) {
+ report.type = ApplicationErrorReport.TYPE_CRASH;
+ report.crashInfo = crashInfo;
+ } else if (r.notResponding) {
+ report.type = ApplicationErrorReport.TYPE_ANR;
+ report.anrInfo = new ApplicationErrorReport.AnrInfo();
+
+ report.anrInfo.activity = r.notRespondingReport.tag;
+ report.anrInfo.cause = r.notRespondingReport.shortMsg;
+ report.anrInfo.info = r.notRespondingReport.longMsg;
}
- return null;
+ return report;
}
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
@@ -9030,9 +9377,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
// iterate across all processes
- final int N = mLRUProcesses.size();
- for (int i = 0; i < N; i++) {
- ProcessRecord app = mLRUProcesses.get(i);
+ for (int i=mLruProcesses.size()-1; i>=0; 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)
@@ -9049,7 +9395,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
errList.add(report);
} else {
- Log.w(TAG, "Missing app error report, app = " + app.processName +
+ Slog.w(TAG, "Missing app error report, app = " + app.processName +
" crashing = " + app.crashing +
" notResponding = " + app.notResponding);
}
@@ -9065,9 +9411,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
// Generate process state info for running application
ActivityManager.RunningAppProcessInfo currApp =
@@ -9075,7 +9420,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.pid, app.getPackageList());
currApp.uid = app.info.uid;
int adj = app.curAdj;
- if (adj >= CONTENT_PROVIDER_ADJ) {
+ if (adj >= EMPTY_APP_ADJ) {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
} else if (adj >= HIDDEN_APP_MIN_ADJ) {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
@@ -9100,7 +9445,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app.adjTarget instanceof ComponentName) {
currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
}
- //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
+ //Slog.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
// + " lru=" + currApp.lru);
if (runList == null) {
runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
@@ -9112,71 +9457,218 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return runList;
}
+ public List<ApplicationInfo> getRunningExternalApplications() {
+ List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
+ List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
+ if (runningApps != null && runningApps.size() > 0) {
+ Set<String> extList = new HashSet<String>();
+ for (ActivityManager.RunningAppProcessInfo app : runningApps) {
+ if (app.pkgList != null) {
+ for (String pkg : app.pkgList) {
+ extList.add(pkg);
+ }
+ }
+ }
+ IPackageManager pm = ActivityThread.getPackageManager();
+ for (String pkg : extList) {
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+ if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ retList.add(info);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return retList;
+ }
+
@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);
+ 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;
+ }
+
+ boolean dumpAll = false;
+
+ int opti = 0;
+ while (opti < args.length) {
+ String opt = args[opti];
+ if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
+ break;
+ }
+ opti++;
+ if ("-a".equals(opt)) {
+ dumpAll = true;
+ } else if ("-h".equals(opt)) {
+ pw.println("Activity manager dump options:");
+ pw.println(" [-a] [-h] [cmd] ...");
+ pw.println(" cmd may be one of:");
+ pw.println(" activities: activity stack state");
+ pw.println(" broadcasts: broadcast state");
+ pw.println(" intents: pending intent state");
+ pw.println(" processes: process state");
+ pw.println(" providers: content provider state");
+ pw.println(" services: service state");
+ pw.println(" service [name]: service client-side state");
return;
+ } else {
+ pw.println("Unknown argument: " + opt + "; use -h for help");
}
- if (args.length != 0 && "service".equals(args[0])) {
- dumpService(fd, pw, args);
+ }
+
+ // Is the caller requesting to dump a particular piece of data?
+ if (opti < args.length) {
+ String cmd = args[opti];
+ opti++;
+ if ("activities".equals(cmd) || "a".equals(cmd)) {
+ synchronized (this) {
+ dumpActivitiesLocked(fd, pw, args, opti, true, true);
+ }
+ return;
+ } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
+ synchronized (this) {
+ dumpBroadcastsLocked(fd, pw, args, opti, true);
+ }
+ return;
+ } else if ("intents".equals(cmd) || "i".equals(cmd)) {
+ synchronized (this) {
+ dumpPendingIntentsLocked(fd, pw, args, opti, true);
+ }
+ return;
+ } else if ("processes".equals(cmd) || "p".equals(cmd)) {
+ synchronized (this) {
+ dumpProcessesLocked(fd, pw, args, opti, true);
+ }
+ return;
+ } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
+ synchronized (this) {
+ dumpProvidersLocked(fd, pw, args, opti, true);
+ }
+ return;
+ } else if ("service".equals(cmd)) {
+ dumpService(fd, pw, args, opti, true);
+ return;
+ } else if ("services".equals(cmd) || "s".equals(cmd)) {
+ synchronized (this) {
+ dumpServicesLocked(fd, pw, args, opti, true);
+ }
return;
}
- pw.println("Activities in Current Activity Manager State:");
- dumpHistoryList(pw, mHistory, " ", "Hist", true);
- pw.println(" ");
- pw.println(" Running activities (most recent first):");
- dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
- if (mWaitingVisibleActivities.size() > 0) {
+ }
+
+ // No piece of data specified, dump everything.
+ synchronized (this) {
+ boolean needSep;
+ if (dumpAll) {
+ pw.println("Providers in Current Activity Manager State:");
+ }
+ needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
+ if (needSep) {
pw.println(" ");
- pw.println(" Activities waiting for another to become visible:");
- dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
}
- if (mStoppingActivities.size() > 0) {
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ pw.println("Broadcasts in Current Activity Manager State:");
+ }
+ needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
+ if (needSep) {
pw.println(" ");
- pw.println(" Activities waiting to stop:");
- dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
}
- if (mFinishingActivities.size() > 0) {
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ pw.println("Services in Current Activity Manager State:");
+ }
+ needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
+ if (needSep) {
pw.println(" ");
- pw.println(" Activities waiting to finish:");
- dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
}
-
- pw.println(" ");
- pw.println(" mPausingActivity: " + mPausingActivity);
- pw.println(" mResumedActivity: " + mResumedActivity);
- pw.println(" mFocusedActivity: " + mFocusedActivity);
- pw.println(" mLastPausedActivity: " + mLastPausedActivity);
-
- if (mRecentTasks.size() > 0) {
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ pw.println("PendingIntents in Current Activity Manager State:");
+ }
+ needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
+ if (needSep) {
pw.println(" ");
- pw.println("Recent tasks in Current Activity Manager State:");
-
- final int N = mRecentTasks.size();
- for (int i=0; i<N; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- pw.print(" * Recent #"); pw.print(i); pw.print(": ");
- pw.println(tr);
- mRecentTasks.get(i).dump(pw, " ");
- }
}
-
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ pw.println("Activities in Current Activity Manager State:");
+ }
+ needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
+ if (needSep) {
+ pw.println(" ");
+ }
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ pw.println("Processes in Current Activity Manager State:");
+ }
+ dumpProcessesLocked(fd, pw, args, opti, dumpAll);
+ }
+ }
+
+ boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, boolean needHeader) {
+ if (needHeader) {
+ pw.println(" Activity stack:");
+ }
+ dumpHistoryList(pw, mHistory, " ", "Hist", true);
+ pw.println(" ");
+ pw.println(" Running activities (most recent first):");
+ dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
+ if (mWaitingVisibleActivities.size() > 0) {
pw.println(" ");
- pw.println(" mCurTask: " + mCurTask);
-
+ pw.println(" Activities waiting for another to become visible:");
+ dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
+ }
+ if (mStoppingActivities.size() > 0) {
+ pw.println(" ");
+ pw.println(" Activities waiting to stop:");
+ dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
+ }
+ if (mFinishingActivities.size() > 0) {
+ pw.println(" ");
+ pw.println(" Activities waiting to finish:");
+ dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
+ }
+
+ pw.println(" ");
+ pw.println(" mPausingActivity: " + mPausingActivity);
+ pw.println(" mResumedActivity: " + mResumedActivity);
+ pw.println(" mFocusedActivity: " + mFocusedActivity);
+ pw.println(" mLastPausedActivity: " + mLastPausedActivity);
+
+ if (dumpAll && mRecentTasks.size() > 0) {
pw.println(" ");
- pw.println("Processes in Current Activity Manager State:");
+ pw.println("Recent tasks in Current Activity Manager State:");
- boolean needSep = false;
- int numPers = 0;
+ final int N = mRecentTasks.size();
+ for (int i=0; i<N; i++) {
+ TaskRecord tr = mRecentTasks.get(i);
+ pw.print(" * Recent #"); pw.print(i); pw.print(": ");
+ pw.println(tr);
+ mRecentTasks.get(i).dump(pw, " ");
+ }
+ }
+
+ pw.println(" ");
+ pw.println(" mCurTask: " + mCurTask);
+
+ return true;
+ }
+
+ boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
+ boolean needSep = false;
+ int numPers = 0;
+ if (dumpAll) {
for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
final int NA = procs.size();
for (int ia=0; ia<NA; ia++) {
@@ -9194,142 +9686,152 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
}
-
- if (mLRUProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Running processes (most recent first):");
- dumpProcessList(pw, mLRUProcesses, " ",
- "App ", "PERS", true);
- needSep = true;
- }
+ }
+
+ if (mLruProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Running processes (most recent first):");
+ dumpProcessList(pw, this, mLruProcesses, " ",
+ "App ", "PERS", 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.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
- pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
- }
- }
- }
-
- if (mForegroundProcesses.size() > 0) {
+ synchronized (mPidsSelfLocked) {
+ if (mPidsSelfLocked.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
- pw.println(" Foreground Processes:");
- for (int i=0; i<mForegroundProcesses.size(); i++) {
- pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
- pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
+ pw.println(" PID mappings:");
+ for (int i=0; i<mPidsSelfLocked.size(); i++) {
+ pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
+ pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
}
}
-
- if (mPersistentStartingProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Persisent processes that are starting:");
- dumpProcessList(pw, mPersistentStartingProcesses, " ",
- "Starting Norm", "Restarting PERS", false);
+ }
+
+ if (mForegroundProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Foreground Processes:");
+ for (int i=0; i<mForegroundProcesses.size(); i++) {
+ pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
+ pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
}
+ }
+
+ if (mPersistentStartingProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Persisent processes that are starting:");
+ dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
+ "Starting Norm", "Restarting PERS", false);
+ }
- if (mStartingProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are starting:");
- dumpProcessList(pw, mStartingProcesses, " ",
- "Starting Norm", "Starting PERS", false);
- }
+ if (mStartingProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Processes that are starting:");
+ dumpProcessList(pw, this, mStartingProcesses, " ",
+ "Starting Norm", "Starting PERS", false);
+ }
- if (mRemovedProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are being removed:");
- dumpProcessList(pw, mRemovedProcesses, " ",
- "Removed Norm", "Removed PERS", 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", "OnHold PERS", false);
- }
+ if (mRemovedProcesses.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Processes that are being removed:");
+ dumpProcessList(pw, this, mRemovedProcesses, " ",
+ "Removed Norm", "Removed PERS", 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, this, mProcessesOnHold, " ",
+ "OnHold Norm", "OnHold PERS", false);
+ }
- if (mProcessesToGc.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are waiting to GC:");
- long now = SystemClock.uptimeMillis();
- for (int i=0; i<mProcessesToGc.size(); i++) {
- ProcessRecord proc = mProcessesToGc.get(i);
- pw.print(" Process "); pw.println(proc);
- pw.print(" lowMem="); pw.print(proc.reportLowMemory);
- pw.print(", last gced=");
- pw.print(now-proc.lastRequestedGc);
- pw.print(" ms ago, last lowMem=");
- pw.print(now-proc.lastLowMemory);
- pw.println(" ms ago");
-
- }
+ if (mProcessesToGc.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" Processes that are waiting to GC:");
+ long now = SystemClock.uptimeMillis();
+ for (int i=0; i<mProcessesToGc.size(); i++) {
+ ProcessRecord proc = mProcessesToGc.get(i);
+ pw.print(" Process "); pw.println(proc);
+ pw.print(" lowMem="); pw.print(proc.reportLowMemory);
+ pw.print(", last gced=");
+ pw.print(now-proc.lastRequestedGc);
+ pw.print(" ms ago, last lowMem=");
+ pw.print(now-proc.lastLowMemory);
+ pw.println(" ms ago");
+
}
-
- 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.print(" Process "); pw.print(procs.getKey());
- pw.print(" uid "); pw.print(uids.keyAt(i));
- pw.print(": last crashed ");
- pw.print((now-uids.valueAt(i)));
- pw.println(" ms ago");
- }
+ }
+
+ 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.print(" Process "); pw.print(procs.getKey());
+ pw.print(" uid "); pw.print(uids.keyAt(i));
+ pw.print(": last crashed ");
+ pw.print((now-uids.valueAt(i)));
+ pw.println(" 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.print(" Bad process "); pw.print(procs.getKey());
- pw.print(" uid "); pw.print(uids.keyAt(i));
- pw.print(": crashed at time ");
- pw.println(uids.valueAt(i));
- }
+ 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.print(" Bad process "); pw.print(procs.getKey());
+ pw.print(" uid "); pw.print(uids.keyAt(i));
+ pw.print(": crashed at time ");
+ pw.println(uids.valueAt(i));
}
}
+ }
- pw.println(" ");
+ pw.println(" ");
+ pw.println(" mHomeProcess: " + mHomeProcess);
+ pw.println(" mConfiguration: " + mConfiguration);
+ pw.println(" mConfigWillChange: " + mConfigWillChange);
+ pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
+ if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
+ || mOrigWaitForDebugger) {
+ pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
+ + " mDebugTransient=" + mDebugTransient
+ + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
+ }
+ if (mAlwaysFinishActivities || mController != null) {
+ pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
+ + " mController=" + mController);
+ }
+ if (dumpAll) {
pw.println(" Total persistent processes: " + numPers);
- pw.println(" mHomeProcess: " + mHomeProcess);
- pw.println(" mConfiguration: " + mConfiguration);
pw.println(" mStartRunning=" + mStartRunning
+ " mSystemReady=" + mSystemReady
+ " mBooting=" + mBooting
+ " mBooted=" + mBooted
+ " mFactoryTest=" + mFactoryTest);
- pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
pw.println(" mGoingToSleep=" + mGoingToSleep);
pw.println(" mLaunchingActivity=" + mLaunchingActivity);
- pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
- + " mDebugTransient=" + mDebugTransient
- + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
- pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
- + " mController=" + mController);
}
+
+ return true;
}
/**
@@ -9340,20 +9842,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* - 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) {
+ protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
String[] newArgs;
String componentNameString;
ServiceRecord r;
- if (args.length == 1) {
+ if (opti >= args.length) {
componentNameString = null;
newArgs = EMPTY_STRING_ARRAY;
r = null;
} else {
- componentNameString = args[1];
+ componentNameString = args[opti];
+ opti++;
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);
+ newArgs = new String[args.length - opti];
+ if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
}
if (r != null) {
@@ -9387,19 +9891,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- 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:");
-
+ boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
+ boolean needSep = false;
+
+ if (dumpAll) {
if (mRegisteredReceivers.size() > 0) {
pw.println(" ");
pw.println(" Registered Receivers:");
@@ -9410,38 +9906,42 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.dump(pw, " ");
}
}
-
+
pw.println(" ");
pw.println("Receiver Resolver Table:");
- mReceiverResolver.dump(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, " ");
- }
+ mReceiverResolver.dump(pw, null, " ", null);
+ needSep = true;
+ }
+
+ if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+ || mPendingBroadcast != null) {
+ if (mParallelBroadcasts.size() > 0) {
pw.println(" ");
- pw.println(" Pending broadcast:");
- if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
- } else {
- pw.println(" (null)");
- }
+ 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 ordered 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)");
+ }
+ needSep = true;
+ }
+ if (dumpAll) {
pw.println(" ");
pw.println(" Historical broadcasts:");
for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
@@ -9452,54 +9952,50 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pw.println(" Historical Broadcast #" + i + ":");
r.dump(pw, " ");
}
-
+ needSep = true;
+ }
+
+ if (mStickyBroadcasts != null) {
pw.println(" ");
- pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
- if (mStickyBroadcasts != null) {
- pw.println(" ");
- pw.println(" Sticky broadcasts:");
- StringBuilder sb = new StringBuilder(128);
- for (Map.Entry<String, ArrayList<Intent>> ent
- : mStickyBroadcasts.entrySet()) {
- pw.print(" * Sticky action "); pw.print(ent.getKey());
- pw.println(":");
- ArrayList<Intent> intents = ent.getValue();
- final int N = intents.size();
- for (int i=0; i<N; i++) {
- sb.setLength(0);
- sb.append(" Intent: ");
- intents.get(i).toShortString(sb, true, false);
- pw.println(sb.toString());
- Bundle bundle = intents.get(i).getExtras();
- if (bundle != null) {
- pw.print(" ");
- pw.println(bundle.toString());
- }
+ pw.println(" Sticky broadcasts:");
+ StringBuilder sb = new StringBuilder(128);
+ for (Map.Entry<String, ArrayList<Intent>> ent
+ : mStickyBroadcasts.entrySet()) {
+ pw.print(" * Sticky action "); pw.print(ent.getKey());
+ pw.println(":");
+ ArrayList<Intent> intents = ent.getValue();
+ final int N = intents.size();
+ for (int i=0; i<N; i++) {
+ sb.setLength(0);
+ sb.append(" Intent: ");
+ intents.get(i).toShortString(sb, true, false);
+ pw.println(sb.toString());
+ Bundle bundle = intents.get(i).getExtras();
+ if (bundle != null) {
+ pw.print(" ");
+ pw.println(bundle.toString());
}
}
}
-
+ needSep = true;
+ }
+
+ if (dumpAll) {
pw.println(" ");
+ pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
pw.println(" mHandler:");
mHandler.dump(new PrintWriterPrinter(pw), " ");
+ needSep = true;
}
+
+ return needSep;
}
- 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;
+ boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
+ boolean needSep = false;
+ if (dumpAll) {
if (mServices.size() > 0) {
pw.println(" Active services:");
Iterator<ServiceRecord> it = mServices.values().iterator();
@@ -9510,40 +10006,42 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
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.print(" * Pending "); pw.println(r);
- 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.print(" * Pending "); pw.println(r);
+ 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.print(" * Restarting "); pw.println(r);
- 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.print(" * Restarting "); pw.println(r);
+ 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.print(" * Stopping "); pw.println(r);
- 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.print(" * Stopping "); pw.println(r);
+ r.dump(pw, " ");
}
+ needSep = true;
+ }
+ if (dumpAll) {
if (mServiceConnections.size() > 0) {
if (needSep) pw.println(" ");
pw.println(" Connection bindings to services:");
@@ -9554,26 +10052,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pw.print(" * "); pw.println(r);
r.dump(pw, " ");
}
+ needSep = true;
}
}
+
+ return needSep;
}
- 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;
+ boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
+ boolean needSep = false;
+ if (dumpAll) {
if (mProvidersByClass.size() > 0) {
if (needSep) pw.println(" ");
pw.println(" Published content providers (by class):");
@@ -9586,7 +10076,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
needSep = true;
}
-
+
if (mProvidersByName.size() > 0) {
pw.println(" ");
pw.println(" Authority to provider mappings:");
@@ -9599,55 +10089,50 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
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.print(" Launching #"); pw.print(i); pw.print(": ");
- pw.println(mLaunchingProviders.get(i));
- }
- 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.print(" Launching #"); pw.print(i); pw.print(": ");
+ pw.println(mLaunchingProviders.get(i));
}
+ needSep = true;
+ }
- if (mGrantedUriPermissions.size() > 0) {
- 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.print(" * UID "); pw.print(uid);
- pw.println(" holds:");
- for (UriPermission perm : perms.values()) {
- pw.print(" "); pw.println(perm);
- perm.dump(pw, " ");
- }
+ if (mGrantedUriPermissions.size() > 0) {
+ 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.print(" * UID "); pw.print(uid);
+ pw.println(" holds:");
+ for (UriPermission perm : perms.values()) {
+ pw.print(" "); pw.println(perm);
+ perm.dump(pw, " ");
}
}
+ needSep = true;
}
+
+ return needSep;
}
- 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("Pending Intents in Current Activity Manager State:");
-
+ boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll) {
+ boolean needSep = false;
+
+ if (dumpAll) {
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;
+ needSep = true;
if (rec != null) {
pw.print(" * "); pw.println(rec);
rec.dump(pw, " ");
@@ -9657,6 +10142,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
}
+
+ return needSep;
}
private static final void dumpHistoryList(PrintWriter pw, List list,
@@ -9683,7 +10170,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- private static final int dumpProcessList(PrintWriter pw, List list,
+ private static String buildOomTag(String prefix, String space, int val, int base) {
+ if (val == base) {
+ if (space == null) return prefix;
+ return prefix + " ";
+ }
+ return prefix + "+" + Integer.toString(val-base);
+ }
+
+ private static final int dumpProcessList(PrintWriter pw,
+ ActivityManagerService service, List list,
String prefix, String normalLabel, String persistentLabel,
boolean inclOomAdj) {
int numPers = 0;
@@ -9694,12 +10190,46 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " #" + i + ":");
r.dump(pw, prefix + " ");
} else if (inclOomAdj) {
- pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
+ String oomAdj;
+ if (r.setAdj >= EMPTY_APP_ADJ) {
+ oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
+ } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
+ oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
+ } else if (r.setAdj >= HOME_APP_ADJ) {
+ oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
+ } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
+ oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
+ } else if (r.setAdj >= BACKUP_APP_ADJ) {
+ oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
+ } else if (r.setAdj >= VISIBLE_APP_ADJ) {
+ oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
+ } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
+ oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
+ } else if (r.setAdj >= CORE_SERVER_ADJ) {
+ oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
+ } else if (r.setAdj >= SYSTEM_ADJ) {
+ oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
+ } else {
+ oomAdj = Integer.toString(r.setAdj);
+ }
+ String schedGroup;
+ switch (r.setSchedGroup) {
+ case Process.THREAD_GROUP_BG_NONINTERACTIVE:
+ schedGroup = "B";
+ break;
+ case Process.THREAD_GROUP_DEFAULT:
+ schedGroup = "F";
+ break;
+ default:
+ schedGroup = Integer.toString(r.setSchedGroup);
+ break;
+ }
+ pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
+ i, oomAdj, schedGroup, r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.println(prefix + " " + r.adjTarget
- + " used by " + r.adjSource);
+ + "<=" + r.adjSource);
}
} else {
pw.println(String.format("%s%s #%2d: %s",
@@ -9713,7 +10243,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return numPers;
}
- private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
+ static final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, List list, String prefix, String[] args) {
final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
@@ -9767,12 +10297,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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;
}
@@ -9801,7 +10329,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//c.conn.connected(r.className, null);
} catch (Exception e) {
// todo: this should be asynchronous!
- Log.w(TAG, "Exception thrown disconnected servce "
+ Slog.w(TAG, "Exception thrown disconnected servce "
+ r.shortName
+ " from app " + app.processName, e);
}
@@ -9841,7 +10369,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
= sr.bindings.values().iterator();
while (bindings.hasNext()) {
IntentBindRecord b = bindings.next();
- if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
+ if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+ ": shouldUnbind=" + b.hasBound);
b.binder = null;
b.requested = b.received = b.hasBound = false;
@@ -9849,9 +10377,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (sr.crashCount >= 2) {
- Log.w(TAG, "Service crashed " + sr.crashCount
+ Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
- EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
+ EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr, true);
} else if (!allowRestart) {
@@ -9911,10 +10439,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.i(TAG, "Kill " + capp.processName
+ + " (pid " + capp.pid + "): provider " + cpr.info.name
+ + " in dying process " + proc.processName);
+ EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+ capp.processName, capp.setAdj, "dying provider " + proc.processName);
Process.killProcess(capp.pid);
}
}
@@ -9930,7 +10459,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, int index) {
if (index >= 0) {
- mLRUProcesses.remove(index);
+ mLruProcesses.remove(index);
}
mProcessesToGc.remove(app);
@@ -10039,7 +10568,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the app is undergoing backup, tell the backup manager about it
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
- if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
+ if (DEBUG_BACKUP) Slog.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -10056,7 +10585,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (!app.persistent) {
- if (DEBUG_PROCESSES) Log.v(TAG,
+ if (DEBUG_PROCESSES) Slog.v(TAG,
"Removing non-persistent process during cleanup: " + app);
mProcessNames.remove(app.processName, app.info.uid);
} else if (!app.removed) {
@@ -10139,7 +10668,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.startRequested) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
}
- if (r.app != null && r.app.pid == Process.myPid()) {
+ if (r.app != null && r.app.pid == MY_PID) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
}
if (r.app != null && r.app.persistent) {
@@ -10245,7 +10774,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (checkComponentPermission(r.permission,
callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: Accessing service " + r.name
+ Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires " + r.permission);
@@ -10286,7 +10815,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
- Log.w(TAG, "Unable to start service " + service +
+ Slog.w(TAG, "Unable to start service " + service +
": not found");
return null;
}
@@ -10328,7 +10857,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (checkComponentPermission(r.permission,
callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: Accessing service " + r.name
+ Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + r.permission);
@@ -10364,7 +10893,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (i < N) {
try {
ServiceRecord.StartItem si = r.pendingStarts.get(i);
- if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
+ if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: "
+ r.name + " " + r.intent + " args=" + si.intent);
if (si.intent == null && N > 1) {
// If somehow we got a dummy start at the front, then
@@ -10394,7 +10923,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// care of this.
break;
} catch (Exception e) {
- Log.w(TAG, "Unexpected exception", e);
+ Slog.w(TAG, "Unexpected exception", e);
break;
}
}
@@ -10417,7 +10946,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r);
- if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
+ if (DEBUG_SERVICE) Slog.v(TAG, "Connecting binding " + i
+ ": shouldUnbind=" + i.hasBound);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
if (!rebind) {
@@ -10453,15 +10982,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.services.add(r);
bumpServiceExecutingLocked(r);
- updateLRUListLocked(app, true);
+ updateLruProcessLocked(app, true, true);
boolean created = false;
try {
- if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
+ if (DEBUG_SERVICE) Slog.v(TAG, "Scheduling start service: "
+ r.name + " " + r.intent);
mStringBuilder.setLength(0);
r.intent.getIntent().toShortString(mStringBuilder, false, true);
- EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
+ EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
System.identityHashCode(r), r.shortName,
mStringBuilder.toString(), r.app.pid);
synchronized (r.stats.getBatteryStats()) {
@@ -10518,7 +11047,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (minDuration < dur) minDuration = dur;
if (resetTime < dur) resetTime = dur;
} else {
- Log.w(TAG, "Canceling start item " + si.intent + " in service "
+ Slog.w(TAG, "Canceling start item " + si.intent + " in service "
+ r.name);
canceled = true;
}
@@ -10577,16 +11106,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeCallbacks(r.restarter);
mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
- Log.w(TAG, "Scheduling restart of crashed service "
+ Slog.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
- EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
+ EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
r.shortName, r.restartDelay);
- Message msg = Message.obtain();
- msg.what = SERVICE_ERROR_MSG;
- msg.obj = r;
- mHandler.sendMessage(msg);
-
return canceled;
}
@@ -10609,7 +11133,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final boolean bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean whileRestarting) {
- //Log.i(TAG, "Bring up service:");
+ //Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
@@ -10622,7 +11146,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up service " + r.name
+ " " + r.intent);
// We are now bringing the service up, so no longer in the
@@ -10636,7 +11160,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
realStartServiceLocked(r, app);
return true;
} catch (RemoteException e) {
- Log.w(TAG, "Exception when starting service " + r.shortName, e);
+ Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
@@ -10647,7 +11171,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// to be executed when the app comes up.
if (startProcessLocked(appName, r.appInfo, true, intentFlags,
"service", r.name, false) == null) {
- Log.w(TAG, "Unable to launch app "
+ Slog.w(TAG, "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad");
@@ -10663,7 +11187,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
- //Log.i(TAG, "Bring down service:");
+ //Slog.i(TAG, "Bring down service:");
//r.dump(" ");
// Does it still need to run?
@@ -10692,7 +11216,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// todo: shouldn't be a synchronous call!
c.conn.connected(r.name, null);
} catch (Exception e) {
- Log.w(TAG, "Failure disconnecting service " + r.name +
+ Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
@@ -10704,7 +11228,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Iterator<IntentBindRecord> it = r.bindings.values().iterator();
while (it.hasNext()) {
IntentBindRecord ibr = it.next();
- if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (r.app != null && r.app.thread != null && ibr.hasBound) {
try {
@@ -10714,7 +11238,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
- Log.w(TAG, "Exception when unbinding service "
+ Slog.w(TAG, "Exception when unbinding service "
+ r.shortName, e);
serviceDoneExecutingLocked(r, true);
}
@@ -10722,15 +11246,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down service " + r.name
+ " " + r.intent);
- EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
+ EventLog.writeEvent(EventLogTags.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);
+ if (localLOGV) Slog.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r);
@@ -10739,7 +11263,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
for (int i=0; i<N; i++) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Removed pending service: " + r.shortName);
i--;
N--;
@@ -10762,24 +11286,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.services.remove(r);
if (r.app.thread != null) {
try {
- if (DEBUG_SERVICE) Log.v(TAG,
+ if (DEBUG_SERVICE) Slog.v(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 "
+ Slog.w(TAG, "Exception when stopping service "
+ r.shortName, e);
serviceDoneExecutingLocked(r, true);
}
updateServiceForegroundLocked(r.app, false);
} else {
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Removed service that has no process: " + r.shortName);
}
} else {
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Removed service that is not running: " + r.shortName);
}
}
@@ -10788,7 +11312,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Intent service, String resolvedType,
int callingPid, int callingUid) {
synchronized(this) {
- if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
if (caller != null) {
@@ -10813,7 +11337,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
ServiceRecord r = res.record;
if (unscheduleServiceRestartLocked(r)) {
- if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
+ if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: "
+ r.shortName);
}
r.startRequested = true;
@@ -10871,7 +11395,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
- if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+ " type=" + resolvedType);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
@@ -10936,7 +11460,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
synchronized(this) {
- if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
+ if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token);
if (r != null) {
@@ -10958,7 +11482,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (r.deliveredStarts.size() > 0) {
- Log.w(TAG, "stopServiceToken startId " + startId
+ Slog.w(TAG, "stopServiceToken startId " + startId
+ " is last, but have " + r.deliveredStarts.size()
+ " remaining args");
}
@@ -11004,6 +11528,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.isForeground) {
r.isForeground = false;
if (r.app != null) {
+ updateLruProcessLocked(r.app, false, true);
updateServiceForegroundLocked(r.app, true);
}
}
@@ -11045,7 +11570,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
- if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
final ProcessRecord callerApp = getRecordForAppLocked(caller);
@@ -11060,7 +11585,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (token != null) {
int aindex = indexOfTokenLocked(token);
if (aindex < 0) {
- Log.w(TAG, "Binding with unknown activity: " + token);
+ Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
activity = (HistoryRecord)mHistory.get(aindex);
@@ -11103,7 +11628,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
if (unscheduleServiceRestartLocked(s)) {
- if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s.shortName);
}
@@ -11135,7 +11660,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
updateOomAdjLocked(s.app);
}
- if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
+ if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+ ": received=" + b.intent.received
+ " apps=" + b.intent.apps.size()
+ " doRebind=" + b.intent.doRebind);
@@ -11146,7 +11671,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
- Log.w(TAG, "Failure sending service " + s.shortName
+ Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
@@ -11188,7 +11713,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
b.intent.apps.remove(b.client);
}
- if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
+ if (DEBUG_SERVICE) Slog.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) {
@@ -11201,7 +11726,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceDoneExecutingLocked(s, true);
}
}
@@ -11214,10 +11739,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
IBinder binder = connection.asBinder();
- if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
+ if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
ConnectionRecord r = mServiceConnections.get(binder);
if (r == null) {
- Log.w(TAG, "Unbind failed: could not find connection for "
+ Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
}
@@ -11251,7 +11776,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
+ if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING SERVICE " + r.name
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
@@ -11267,19 +11792,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (it.hasNext()) {
ConnectionRecord c = it.next();
if (!filter.equals(c.binding.intent.intent)) {
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Not publishing to: " + c);
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Bound intent: " + c.binding.intent.intent);
- if (DEBUG_SERVICE) Log.v(
+ if (DEBUG_SERVICE) Slog.v(
TAG, "Published intent: " + intent);
continue;
}
- if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
- Log.w(TAG, "Failure sending service " + r.name +
+ Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
@@ -11312,7 +11837,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
- if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
+ if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r
+ " at " + b + ": apps="
+ (b != null ? b.apps.size() : 0));
if (b != null) {
@@ -11342,11 +11867,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ServiceRecord r = (ServiceRecord)token;
boolean inStopping = mStoppingServices.contains(token);
if (r != null) {
- if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
+ if (DEBUG_SERVICE) Slog.v(TAG, "DONE EXECUTING SERVICE " + r.name
+ ": nesting=" + r.executeNesting
+ ", inStopping=" + inStopping);
if (r != token) {
- Log.w(TAG, "Done executing service " + r.name
+ Slog.w(TAG, "Done executing service " + r.name
+ " with incorrect token: given " + token
+ ", expected " + r);
return;
@@ -11401,7 +11926,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
} else {
- Log.w(TAG, "Done executing unknown service " + r.name
+ Slog.w(TAG, "Done executing unknown service " + r.name
+ " with token " + token);
}
}
@@ -11422,6 +11947,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void serviceTimeout(ProcessRecord proc) {
+ String anrMessage = null;
+
synchronized(this) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
@@ -11440,16 +11967,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
nextTime = sr.executingStart;
}
}
- if (timeout != null && mLRUProcesses.contains(proc)) {
- Log.w(TAG, "Timeout executing service: " + timeout);
- appNotRespondingLocked(proc, null, null, "Executing service "
- + timeout.name);
+ if (timeout != null && mLruProcesses.contains(proc)) {
+ Slog.w(TAG, "Timeout executing service: " + timeout);
+ anrMessage = "Executing service " + timeout.shortName;
} else {
Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
}
}
+
+ if (anrMessage != null) {
+ appNotResponding(proc, null, null, anrMessage);
+ }
}
// =========================================================
@@ -11460,7 +11990,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
- if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
+ if (DEBUG_BACKUP) Slog.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
synchronized(this) {
@@ -11477,7 +12007,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ProcessRecord proc = startProcessLocked(app.processName, app,
false, 0, "backup", hostingName, false);
if (proc == null) {
- Log.e(TAG, "Unable to start backup agent process " + r);
+ Slog.e(TAG, "Unable to start backup agent process " + r);
return false;
}
@@ -11491,14 +12021,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the process is already attached, schedule the creation of the backup agent now.
// If it is not yet live, this will be done when it attaches to the framework.
if (proc.thread != null) {
- if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
+ if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc already running: " + proc);
try {
proc.thread.scheduleCreateBackupAgent(app, backupMode);
} catch (RemoteException e) {
// Will time out on the backup manager side
}
} else {
- if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
+ if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc not running, waiting for attach");
}
// Invariants: at this point, the target app process exists and the application
// is either already running or in the process of coming up. mBackupTarget and
@@ -11511,12 +12041,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// A backup agent has just come up
public void backupAgentCreated(String agentPackageName, IBinder agent) {
- if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
+ if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
+ " = " + agent);
synchronized(this) {
if (!agentPackageName.equals(mBackupAppName)) {
- Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
+ Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
return;
}
@@ -11528,7 +12058,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
// can't happen; the backup manager service is local
} catch (Exception e) {
- Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
+ Slog.w(TAG, "Exception trying to deliver BackupAgent binding: ");
e.printStackTrace();
} finally {
Binder.restoreCallingIdentity(oldIdent);
@@ -11538,20 +12068,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// done with this agent
public void unbindBackupAgent(ApplicationInfo appInfo) {
- if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
+ if (DEBUG_BACKUP) Slog.v(TAG, "unbindBackupAgent: " + appInfo);
if (appInfo == null) {
- Log.w(TAG, "unbind backup agent for null app");
+ Slog.w(TAG, "unbind backup agent for null app");
return;
}
synchronized(this) {
if (mBackupAppName == null) {
- Log.w(TAG, "Unbinding backup agent with no active backup");
+ Slog.w(TAG, "Unbinding backup agent with no active backup");
return;
}
if (!mBackupAppName.equals(appInfo.packageName)) {
- Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
+ Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
return;
}
@@ -11567,7 +12097,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
proc.thread.scheduleDestroyBackupAgent(appInfo);
} catch (Exception e) {
- Log.e(TAG, "Exception when unbinding backup agent:");
+ Slog.e(TAG, "Exception when unbinding backup agent:");
e.printStackTrace();
}
}
@@ -11598,7 +12128,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
@@ -11639,7 +12169,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// the client.
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
- if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
+ ": " + sticky);
if (receiver == null) {
@@ -11667,7 +12197,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
rl.add(bf);
if (!bf.debugCheck()) {
- Log.w(TAG, "==> For Dynamic broadast");
+ Slog.w(TAG, "==> For Dynamic broadast");
}
mReceiverResolver.addFilter(bf);
@@ -11695,7 +12225,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public void unregisterReceiver(IIntentReceiver receiver) {
- if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
boolean doNext = false;
@@ -11746,11 +12276,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
- if (DEBUG_BROADCAST_LIGHT) Log.v(
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
if ((resultTo != null) && !ordered) {
- Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
+ Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
}
// Handle special intents: if this broadcast is from the package
@@ -11760,6 +12290,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
intent.getAction());
if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
|| intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+ || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
|| uidRemoved) {
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
@@ -11776,15 +12307,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
} 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);
- AttributeCache ac = AttributeCache.instance();
- if (ac != null) {
- ac.removePackage(ssp);
+ // If resources are unvailble just force stop all
+ // those packages and flush the attribute cache as well.
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
+ String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ if (list != null && (list.length > 0)) {
+ for (String pkg : list) {
+ forceStopPackageLocked(pkg, -1, false, true, true);
+ }
+ }
+ } else {
+ Uri data = intent.getData();
+ String ssp;
+ if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+ if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
+ forceStopPackageLocked(ssp,
+ intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
}
}
}
@@ -11795,7 +12333,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
@@ -11823,11 +12361,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from pid="
+ callingPid + ", uid=" + callingUid;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception", e);
+ Slog.w(TAG, "Remote exception", e);
return BROADCAST_SUCCESS;
}
}
@@ -11840,11 +12378,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
+ callingPid + ", uid=" + callingUid
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (requiredPermission != null) {
- Log.w(TAG, "Can't broadcast sticky intent " + intent
+ Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permission " + requiredPermission);
return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
@@ -11899,6 +12437,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// pm is in same process, this will never happen.
}
+ final boolean replacePending =
+ (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+ + " replacePending=" + replacePending);
+
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
@@ -11908,11 +12452,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
callerPackage, callingPid, callingUid, requiredPermission,
registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false);
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing parallel broadcast " + r
+ ": prev had " + mParallelBroadcasts.size());
- mParallelBroadcasts.add(r);
- scheduleBroadcastsLocked();
+ boolean replaced = false;
+ if (replacePending) {
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING PARALLEL: " + intent);
+ mParallelBroadcasts.set(i, r);
+ replaced = true;
+ break;
+ }
+ }
+ }
+ if (!replaced) {
+ mParallelBroadcasts.add(r);
+ scheduleBroadcastsLocked();
+ }
registeredReceivers = null;
NR = 0;
}
@@ -11926,25 +12484,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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.
- boolean skip = false;
- if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
- skip = true;
- } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
- skip = true;
- } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
- skip = true;
- }
- String skipPackage = (skip && 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--;
+ String skipPackages[] = null;
+ if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
+ || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
+ || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
+ Uri data = intent.getData();
+ if (data != null) {
+ String pkgName = data.getSchemeSpecificPart();
+ if (pkgName != null) {
+ skipPackages = new String[] { pkgName };
+ }
+ }
+ } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
+ skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ }
+ if (skipPackages != null && (skipPackages.length > 0)) {
+ for (String skipPackage : skipPackages) {
+ if (skipPackage != 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--;
+ }
+ }
}
}
}
@@ -11988,15 +12553,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false);
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST) Slog.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);
+ Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
+ }
+ boolean replaced = false;
+ if (replacePending) {
+ for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+ if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING ORDERED: " + intent);
+ mOrderedBroadcasts.set(i, r);
+ replaced = true;
+ break;
+ }
+ }
+ }
+ if (!replaced) {
+ mOrderedBroadcasts.add(r);
+ scheduleBroadcastsLocked();
}
- mOrderedBroadcasts.add(r);
- scheduleBroadcastsLocked();
}
return BROADCAST_SUCCESS;
@@ -12021,7 +12600,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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
+ Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ " before boot completion");
throw new IllegalStateException("Cannot broadcast before boot completed");
}
@@ -12074,7 +12653,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
- Log.w(TAG, msg);
+ Slog.w(TAG, msg);
throw new SecurityException(msg);
}
ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
@@ -12096,26 +12675,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean explicit) {
if (mOrderedBroadcasts.size() == 0) {
if (explicit) {
- Log.w(TAG, "finishReceiver called but no pending broadcasts");
+ Slog.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");
+ Slog.w(TAG, "finishReceiver called but none active");
}
return false;
}
if (r.receiver != receiver) {
- Log.w(TAG, "finishReceiver called but active receiver is different");
+ Slog.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");
+ Slog.w(TAG, "finishReceiver called but state is IDLE");
}
}
r.receiver = null;
@@ -12146,7 +12725,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort) {
- if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Finish receiver: " + who);
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -12175,22 +12754,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Object curReceiver = r.receivers.get(r.nextReceiver-1);
if (curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter) curReceiver;
- EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
System.identityHashCode(r),
r.intent.getAction(),
r.nextReceiver - 1,
System.identityHashCode(bf));
} else {
- EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
+ EventLog.writeEvent(EventLogTags.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: "
+ Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+ r);
- EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
System.identityHashCode(r),
r.intent.getAction(),
r.nextReceiver,
@@ -12199,6 +12778,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private final void broadcastTimeout() {
+ ProcessRecord app = null;
+ String anrMessage = null;
+
synchronized (this) {
if (mOrderedBroadcasts.size() == 0) {
return;
@@ -12206,7 +12788,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mOrderedBroadcasts.get(0);
if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG,
"Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ (r.receiverTime + BROADCAST_TIMEOUT));
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
@@ -12214,20 +12796,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
- Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
r.receiverTime = now;
r.anrCount++;
// Current receiver has passed its expiration date.
if (r.nextReceiver <= 0) {
- Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+ Slog.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);
+ Slog.w(TAG, "Receiver during timeout: " + curReceiver);
logBroadcastReceiverDiscard(r);
if (curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
@@ -12243,8 +12823,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (app != null) {
- appNotRespondingLocked(app, null, null,
- "Broadcast of " + r.intent.toString());
+ anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
@@ -12256,6 +12835,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.resultExtras, r.resultAbort, true);
scheduleBroadcastsLocked();
}
+
+ if (anrMessage != null) {
+ appNotResponding(app, null, null, anrMessage);
+ }
}
private final void processCurBroadcastLocked(BroadcastRecord r,
@@ -12266,14 +12849,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceiver = r;
- updateLRUListLocked(app, true);
+ updateLruProcessLocked(app, true, true);
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
boolean started = false;
try {
- if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
"Delivering to component " + r.curComponent
+ ": " + r);
ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -12310,7 +12893,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int perm = checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: broadcasting "
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
@@ -12323,7 +12906,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int perm = checkComponentPermission(r.requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: receiving "
+ Slog.w(TAG, "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
@@ -12358,7 +12941,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
if (DEBUG_BROADCAST_LIGHT) {
int seq = r.intent.getIntExtra("seq", -1);
- Log.i(TAG, "Delivering to " + filter.receiverList.app
+ Slog.i(TAG, "Delivering to " + filter
+ " (seq=" + seq + "): " + r);
}
performReceive(filter.receiverList.app, filter.receiverList.receiver,
@@ -12368,7 +12951,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
- Log.w(TAG, "Failure sending broadcast " + r.intent, e);
+ Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
if (ordered) {
r.receiver = null;
r.curFilter = null;
@@ -12396,9 +12979,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
BroadcastRecord r;
- if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
+ if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast: "
+ mParallelBroadcasts.size() + " broadcasts, "
- + mOrderedBroadcasts.size() + " serialized broadcasts");
+ + mOrderedBroadcasts.size() + " ordered broadcasts");
updateCpuStats();
@@ -12411,17 +12994,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast "
+ r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Log.v(TAG,
- "Delivering non-serialized to registered "
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering non-ordered to registered "
+ target + ": " + r);
deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast "
+ r);
}
@@ -12432,7 +13015,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {
if (DEBUG_BROADCAST_LIGHT) {
- Log.v(TAG, "processNextBroadcast: waiting for "
+ Slog.v(TAG, "processNextBroadcast: waiting for "
+ mPendingBroadcast.curApp);
}
@@ -12444,7 +13027,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// It's still alive, so keep waiting
return;
} else {
- Log.w(TAG, "pending app " + mPendingBroadcast.curApp
+ Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast = null;
}
@@ -12475,7 +13058,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.dispatchTime > 0) {
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
- Log.w(TAG, "Hung broadcast discarded after timeout failure:"
+ Slog.w(TAG, "Hung broadcast discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
@@ -12490,7 +13073,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Log.d(TAG,
+ if (DEBUG_BROADCAST) Slog.d(TAG,
"processNextBroadcast() called when not idle (state="
+ r.state + ")");
return;
@@ -12504,21 +13087,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
if (DEBUG_BROADCAST) {
int seq = r.intent.getIntExtra("seq", -1);
- Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
+ Slog.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, false);
} catch (RemoteException e) {
- Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
+ Slog.w(TAG, "Failure sending broadcast result of " + r.intent, e);
}
}
- if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
- if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+ r);
// ... and on to the next...
@@ -12539,9 +13122,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
- if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
+ r);
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG,
"Submitting BROADCAST_TIMEOUT_MSG for "
+ (r.receiverTime + BROADCAST_TIMEOUT));
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
@@ -12553,13 +13136,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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 "
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering ordered 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.
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing: ordered="
+ + r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
}
@@ -12578,7 +13163,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
info.activityInfo.exported
? -1 : info.activityInfo.applicationInfo.uid);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: broadcasting "
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
@@ -12597,7 +13182,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
perm = PackageManager.PERMISSION_DENIED;
}
if (perm != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission Denial: receiving "
+ Slog.w(TAG, "Permission Denial: receiving "
+ r.intent + " to "
+ info.activityInfo.applicationInfo.packageName
+ " requires " + r.requiredPermission
@@ -12634,7 +13219,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
- Log.w(TAG, "Exception when sending broadcast to "
+ Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
}
@@ -12651,7 +13236,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
== 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 "
+ Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ info.activityInfo.applicationInfo.uid + " for broadcast "
+ r.intent + ": process is bad");
@@ -12715,7 +13300,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
final long origId = Binder.clearCallingIdentity();
- uninstallPackageLocked(ii.targetPackage, -1, true);
+ forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
ProcessRecord app = addAppLocked(ai);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
@@ -12740,7 +13325,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
ComponentName cn, String report) {
- Log.w(TAG, report);
+ Slog.w(TAG, report);
try {
if (watcher != null) {
Bundle results = new Bundle();
@@ -12749,7 +13334,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
watcher.instrumentationStatus(cn, -1, results);
}
} catch (RemoteException e) {
- Log.w(TAG, e);
+ Slog.w(TAG, e);
}
}
@@ -12770,7 +13355,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.instrumentationProfileFile = null;
app.instrumentationArguments = null;
- uninstallPackageLocked(app.processName, -1, false);
+ forceStopPackageLocked(app.processName, -1, false, false, true);
}
public void finishInstrumentation(IApplicationThread target,
@@ -12783,7 +13368,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
ProcessRecord app = getRecordForAppLocked(target);
if (app == null) {
- Log.w(TAG, "finishInstrumentation: no app for " + target);
+ Slog.w(TAG, "finishInstrumentation: no app for " + target);
return;
}
final long origId = Binder.clearCallingIdentity();
@@ -12857,10 +13442,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
changes = newConfig.updateFrom(values);
if (changes != 0) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Log.i(TAG, "Updating configuration to: " + values);
+ Slog.i(TAG, "Updating configuration to: " + values);
}
- EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
+ EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (values.locale != null) {
saveLocaleLocked(values.locale,
@@ -12868,24 +13453,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
values.userSetLocale);
}
+ mConfigurationSeq++;
+ if (mConfigurationSeq <= 0) {
+ mConfigurationSeq = 1;
+ }
+ newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
- Log.i(TAG, "Config changed: " + newConfig);
+ Slog.i(TAG, "Config changed: " + newConfig);
AttributeCache ac = AttributeCache.instance();
if (ac != null) {
ac.updateConfiguration(mConfiguration);
}
- Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
- msg.obj = new Configuration(mConfiguration);
- mHandler.sendMessage(msg);
+ if (Settings.System.hasInterestingConfigurationChanges(changes)) {
+ 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);
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
try {
if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
+ app.processName + " new config " + mConfiguration);
app.thread.scheduleConfigurationChanged(mConfiguration);
}
@@ -12893,7 +13484,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
@@ -12918,12 +13510,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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
+ if (DEBUG_SWITCH) Slog.i(TAG, "Config didn't destroy " + starting
+ ", ensuring others are correct.");
ensureActivitiesVisibleLocked(starting, changes);
}
}
+ if (values != null && mWindowManager != null) {
+ mWindowManager.setNewConfiguration(mConfiguration);
+ }
+
return kept;
}
@@ -12935,17 +13531,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
results = r.results;
newIntents = r.newIntents;
}
- if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
+ if (DEBUG_SWITCH) Slog.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),
+ EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
+ : EventLogTags.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);
+ if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
changes, !andResume, mConfiguration);
// Note: don't need to call pauseIfSleepingLocked() here, because
@@ -12973,21 +13569,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
int globalChanges) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (mConfigWillChange) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ "Skipping config check (will change): " + r);
+ return true;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(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 || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Configuration unchanged in " + r);
return true;
}
// We don't worry about activities that are finishing.
if (r.finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Configuration doesn't matter in finishing " + r);
r.stopFreezingScreenLocked(false);
return true;
@@ -13001,7 +13603,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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 || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Configuration doesn't matter not running " + r);
r.stopFreezingScreenLocked(false);
return true;
@@ -13014,7 +13616,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Figure out what has changed between the two configurations.
int changes = oldConfig.diff(newConfig);
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
+ Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
+ Integer.toHexString(changes) + ", handles=0x"
+ Integer.toHexString(r.info.configChanges)
+ ", newConfig=" + newConfig);
@@ -13024,14 +13626,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.configChangeFlags |= changes;
r.startFreezingScreenLocked(r.app, globalChanges);
if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(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.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is skipping already pausing " + r);
r.configDestroy = true;
return true;
@@ -13040,12 +13642,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// and we need to restart the top, resumed activity.
// Instead of doing the normal handshaking, just say
// "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is restarting resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, true);
r.configChangeFlags = 0;
} else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is restarting non-resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, false);
r.configChangeFlags = 0;
@@ -13064,7 +13666,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// it last got.
if (r.app != null && r.app.thread != null) {
try {
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
r.app.thread.scheduleActivityConfigurationChanged(r);
} catch (RemoteException e) {
// If process died, whatever.
@@ -13095,15 +13697,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// LIFETIME MANAGEMENT
// =========================================================
- private final int computeOomAdjLocked(
- ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
+ private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
+ ProcessRecord TOP_APP, boolean recursed) {
if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed.
+ // This adjustment has already been computed. If we are calling
+ // from the top, we may have already computed our adjustment with
+ // an earlier hidden adjustment that isn't really for us... if
+ // so, use the new hidden adjustment.
+ if (!recursed && app.hidden) {
+ app.curAdj = hiddenAdj;
+ }
return app.curAdj;
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
+ app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
return (app.curAdj=EMPTY_APP_ADJ);
}
@@ -13120,84 +13729,107 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
+ app.empty = false;
+ app.hidden = false;
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
int adj;
+ int schedGroup;
int N;
if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
} else if (app.persistentActivities > 0) {
// Special persistent activities... shouldn't be used these days.
adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "persistent";
} 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;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "broadcast";
} 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;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "exec-service";
} else if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = VISIBLE_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "foreground-service";
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = VISIBLE_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "force-foreground";
app.adjSource = app.forcingToForeground;
} else if (app == mHomeProcess) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
adj = HOME_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "home";
} else if ((N=app.activities.size()) != 0) {
// This app is in the background with paused activities.
+ app.hidden = true;
adj = hiddenAdj;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "bg-activities";
+ N = app.activities.size();
for (int j=0; j<N; j++) {
if (((HistoryRecord)app.activities.get(j)).visible) {
// This app has a visible activity!
+ app.hidden = false;
adj = VISIBLE_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "visible";
break;
}
}
} else {
- // A very not-needed process.
- adj = EMPTY_APP_ADJ;
- app.adjType = "empty";
+ // A very not-needed process. If this is lower in the lru list,
+ // we will push it in to the empty bucket.
+ app.hidden = true;
+ app.empty = true;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ adj = hiddenAdj;
+ app.adjType = "bg-empty";
}
+ //Slog.i(TAG, "OOM " + app + ": initial adj=" + adj);
+
// By default, we use the computed adjustment. 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 (mBackupTarget != null && app == mBackupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > BACKUP_APP_ADJ) {
- if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
+ if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
adj = BACKUP_APP_ADJ;
app.adjType = "backup";
+ app.hidden = false;
}
}
- if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
+ if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
final long now = SystemClock.uptimeMillis();
// This process is more important if the top activity is
// bound to the service.
@@ -13212,10 +13844,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (adj > SECONDARY_SERVER_ADJ) {
adj = SECONDARY_SERVER_ADJ;
app.adjType = "started-services";
+ app.hidden = false;
}
}
+ // If we have let the service slide into the background
+ // state, still have some text describing what it is doing
+ // even though the service no longer has an impact.
+ if (adj > SECONDARY_SERVER_ADJ) {
+ app.adjType = "started-bg-services";
+ }
}
- if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
+ if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
Iterator<ConnectionRecord> kt
= s.connections.values().iterator();
while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
@@ -13237,25 +13877,35 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
int clientAdj = computeOomAdjLocked(
- client, myHiddenAdj, TOP_APP);
+ client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
adj = clientAdj > VISIBLE_APP_ADJ
? clientAdj : VISIBLE_APP_ADJ;
+ if (!client.hidden) {
+ app.hidden = false;
+ }
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
app.adjTarget = s.serviceInfo.name;
}
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ }
}
HistoryRecord a = cr.activity;
//if (a != null) {
- // Log.i(TAG, "Connection to " + a ": state=" + a.state);
+ // Slog.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;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.hidden = false;
app.adjType = "service";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE;
@@ -13273,13 +13923,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// its services we may bump it up from there.
if (adj > hiddenAdj) {
adj = hiddenAdj;
+ app.hidden = false;
app.adjType = "bg-services";
}
}
- if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
+ if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
Iterator jt = app.pubProviders.values().iterator();
- while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+ while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
if (cpr.clients.size() != 0) {
Iterator<ProcessRecord> kt = cpr.clients.iterator();
@@ -13298,16 +13951,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
int clientAdj = computeOomAdjLocked(
- client, myHiddenAdj, TOP_APP);
+ client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
adj = clientAdj > FOREGROUND_APP_ADJ
? clientAdj : FOREGROUND_APP_ADJ;
+ if (!client.hidden) {
+ app.hidden = false;
+ }
app.adjType = "provider";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
app.adjTarget = cpr.info.name;
}
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
}
}
// If the provider has external (non-framework) process
@@ -13316,34 +13975,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (cpr.externals != 0) {
if (adj > FOREGROUND_APP_ADJ) {
adj = FOREGROUND_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.hidden = false;
app.adjType = "provider";
app.adjTarget = cpr.info.name;
}
}
}
-
- // Finally, 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;
- app.adjType = "pub-providers";
- }
}
app.curRawAdj = adj;
- //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
+ //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
if (adj > app.maxAdj) {
adj = app.maxAdj;
+ if (app.maxAdj <= VISIBLE_APP_ADJ) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
}
app.curAdj = adj;
- app.curSchedGroup = adj > VISIBLE_APP_ADJ
- ? Process.THREAD_GROUP_BG_NONINTERACTIVE
- : Process.THREAD_GROUP_DEFAULT;
+ app.curSchedGroup = schedGroup;
return adj;
}
@@ -13486,9 +14139,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
+ int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
- if (app.pid != 0 && app.pid != MY_PID) {
+ if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
if (app.curRawAdj != app.setRawAdj) {
if (app.curRawAdj > FOREGROUND_APP_ADJ
&& app.setRawAdj <= FOREGROUND_APP_ADJ) {
@@ -13505,7 +14158,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (adj != app.setAdj) {
if (Process.setOomAdj(app.pid, adj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set app " + app.processName +
" oom adj to " + adj);
app.setAdj = adj;
@@ -13515,7 +14168,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (app.setSchedGroup != app.curSchedGroup) {
app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
"Setting process group of " + app.processName
+ " to " + app.curSchedGroup);
if (true) {
@@ -13523,7 +14176,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
Process.setProcessGroup(app.pid, app.curSchedGroup);
} catch (Exception e) {
- Log.w(TAG, "Failed setting process group of " + app.pid
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ " to " + app.curSchedGroup);
e.printStackTrace();
} finally {
@@ -13585,30 +14238,60 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (false) {
RuntimeException e = new RuntimeException();
e.fillInStackTrace();
- Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
+ Slog.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
}
mAdjSeq++;
+ // Let's determine how many processes we have running vs.
+ // how many slots we have for background processes; we may want
+ // to put multiple processes in a slot of there are enough of
+ // them.
+ int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
+ int factor = (mLruProcesses.size()-4)/numSlots;
+ if (factor < 1) factor = 1;
+ int step = 0;
+ int numHidden = 0;
+
// First try updating the OOM adjustment for each of the
// application processes based on their current state.
- int i = mLRUProcesses.size();
+ int i = mLruProcesses.size();
int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
while (i > 0) {
i--;
- ProcessRecord app = mLRUProcesses.get(i);
+ ProcessRecord app = mLruProcesses.get(i);
+ //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
- if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
+ if (curHiddenAdj < EMPTY_APP_ADJ
&& app.curAdj == curHiddenAdj) {
- curHiddenAdj++;
+ step++;
+ if (step >= factor) {
+ step = 0;
+ curHiddenAdj++;
+ }
+ }
+ if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+ if (!app.killedBackground) {
+ numHidden++;
+ if (numHidden > MAX_HIDDEN_APPS) {
+ Slog.i(TAG, "Kill " + app.processName
+ + " (pid " + app.pid + "): hidden #" + numHidden
+ + " beyond limit " + MAX_HIDDEN_APPS);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcess(app.pid);
+ }
+ }
}
} 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.
+ // If we return false, we will fall back on killing processes to
+ // have a fixed limit. Do this if a limit has been requested; else
+ // only return false if one of the adjustments failed.
return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
}
@@ -13622,7 +14305,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final ProcessRecord app = mRemovedProcesses.get(i);
if (app.activities.size() == 0
&& app.curReceiver == null && app.services.size() == 0) {
- Log.i(
+ Slog.i(
TAG, "Exiting empty application process "
+ app.processName + " ("
+ (app.thread != null ? app.thread.asBinder() : null)
@@ -13655,15 +14338,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Count how many processes are running services.
int numServiceProcs = 0;
- for (i=mLRUProcesses.size()-1; i>=0; i--) {
- final ProcessRecord app = mLRUProcesses.get(i);
+ 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(
+ if (localLOGV) Slog.v(
TAG, "Not trimming app " + app + " with services: "
+ app.services);
numServiceProcs++;
@@ -13681,15 +14364,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// process count. First remove any processes that no longer
// have activites running in them.
for ( i=0;
- i<mLRUProcesses.size()
- && mLRUProcesses.size() > curMaxProcs;
+ i<mLruProcesses.size()
+ && mLruProcesses.size() > curMaxProcs;
i++) {
- final ProcessRecord app = mLRUProcesses.get(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(
+ Slog.i(
TAG, "Exiting empty application process "
+ app.processName + " ("
+ (app.thread != null ? app.thread.asBinder() : null)
@@ -13714,14 +14397,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// 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() +
+ if (Config.LOGV) Slog.v(
+ TAG, "*** NOW HAVE " + mLruProcesses.size() +
" of " + curMaxProcs + " processes");
for ( i=0;
- i<mLRUProcesses.size()
- && mLRUProcesses.size() > curMaxProcs;
+ i<mLruProcesses.size()
+ && mLruProcesses.size() > curMaxProcs;
i++) {
- final ProcessRecord app = mLRUProcesses.get(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
@@ -13729,11 +14412,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
&& app.persistentActivities == 0;
int NUMA = app.activities.size();
int j;
- if (Config.LOGV) Log.v(
+ if (Config.LOGV) Slog.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(
+ if (Config.LOGV) Slog.v(
TAG, " " + r.intent.getComponent().flattenToShortString()
+ ": frozen=" + r.haveState + ", visible=" + r.visible);
canQuit = (r.haveState || !r.stateNotNeeded)
@@ -13748,7 +14431,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
r.resultTo = null;
}
- Log.i(TAG, "Exiting application process "
+ Slog.i(TAG, "Exiting application process "
+ app.processName + " ("
+ (app.thread != null ? app.thread.asBinder() : null)
+ ")\n");
@@ -13820,8 +14503,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
}
- for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLRUProcesses.get(i);
+ 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);
}
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 33894d6..3a1aad6 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -23,7 +23,7 @@ import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
-import android.util.Log;
+import android.util.Slog;
class AppErrorDialog extends BaseErrorDialog {
private final static String TAG = "AppErrorDialog";
@@ -33,15 +33,12 @@ class AppErrorDialog extends BaseErrorDialog {
// Event 'what' codes
static final int FORCE_QUIT = 0;
- static final int DEBUG = 1;
- static final int FORCE_QUIT_AND_REPORT = 2;
+ static final int FORCE_QUIT_AND_REPORT = 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) {
+ public AppErrorDialog(Context context, AppErrorResult result, ProcessRecord app) {
super(context);
Resources res = context.getResources();
@@ -67,12 +64,6 @@ class AppErrorDialog extends BaseErrorDialog {
res.getText(com.android.internal.R.string.force_close),
mHandler.obtainMessage(FORCE_QUIT));
- if ((flags&1) != 0) {
- setButton(DialogInterface.BUTTON_NEUTRAL,
- res.getText(com.android.internal.R.string.debug),
- mHandler.obtainMessage(DEBUG));
- }
-
if (app.errorReportReceiver != null) {
setButton(DialogInterface.BUTTON_NEGATIVE,
res.getText(com.android.internal.R.string.report),
@@ -88,7 +79,7 @@ class AppErrorDialog extends BaseErrorDialog {
mHandler.obtainMessage(FORCE_QUIT),
DISMISS_TIMEOUT);
}
-
+
public void onStop() {
}
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index 03c2a04..9702f91 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -26,7 +26,7 @@ import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
-import android.util.Log;
+import android.util.Slog;
class AppNotRespondingDialog extends BaseErrorDialog {
private static final String TAG = "AppNotRespondingDialog";
@@ -104,8 +104,7 @@ class AppNotRespondingDialog extends BaseErrorDialog {
switch (msg.what) {
case FORCE_CLOSE:
// Kill the application.
- mService.killAppAtUsersRequest(mProc,
- AppNotRespondingDialog.this, true);
+ mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this);
break;
case WAIT_AND_REPORT:
case WAIT:
@@ -114,7 +113,8 @@ class AppNotRespondingDialog extends BaseErrorDialog {
ProcessRecord app = mProc;
if (msg.what == WAIT_AND_REPORT) {
- appErrorIntent = mService.createAppErrorIntentLocked(app);
+ appErrorIntent = mService.createAppErrorIntentLocked(app,
+ System.currentTimeMillis(), null);
}
app.notResponding = false;
@@ -130,7 +130,7 @@ class AppNotRespondingDialog extends BaseErrorDialog {
try {
getContext().startActivity(appErrorIntent);
} catch (ActivityNotFoundException e) {
- Log.w(TAG, "bug report receiver dissappeared", e);
+ Slog.w(TAG, "bug report receiver dissappeared", e);
}
}
}
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 0992d4d..8e9818d 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -62,8 +62,7 @@ class AppWaitingForDebuggerDialog extends BaseErrorDialog {
switch (msg.what) {
case 1:
// Kill the application.
- mService.killAppAtUsersRequest(mProc,
- AppWaitingForDebuggerDialog.this, true);
+ mService.killAppAtUsersRequest(mProc, AppWaitingForDebuggerDialog.this);
break;
}
}
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/java/com/android/server/am/BackupRecord.java
index 5ac8e0d..6590b91 100644
--- a/services/java/com/android/server/am/BackupRecord.java
+++ b/services/java/com/android/server/am/BackupRecord.java
@@ -54,4 +54,4 @@ class BackupRecord {
.append(' ').append(appInfo.backupAgentName).append('}');
return stringName = sb.toString();
}
-} \ No newline at end of file
+}
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java
index bed2768..03e3272 100644
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -45,10 +45,10 @@ class BaseErrorDialog extends AlertDialog {
public boolean dispatchKeyEvent(KeyEvent event) {
if (mConsuming) {
- //Log.i(TAG, "Consuming: " + event);
+ //Slog.i(TAG, "Consuming: " + event);
return true;
}
- //Log.i(TAG, "Dispatching: " + event);
+ //Slog.i(TAG, "Dispatching: " + event);
return super.dispatchKeyEvent(event);
}
@@ -61,6 +61,10 @@ class BaseErrorDialog extends AlertDialog {
if (b != null) {
b.setEnabled(enabled);
}
+ b = (Button)findViewById(R.id.button3);
+ if (b != null) {
+ b.setEnabled(enabled);
+ }
}
private Handler mHandler = new Handler() {
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index d59aead..33bbc13 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -24,7 +24,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
import android.telephony.SignalStrength;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsImpl;
@@ -57,7 +57,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
public void shutdown() {
- Log.w("BatteryStats", "Writing battery stats before shutdown...");
+ Slog.w("BatteryStats", "Writing battery stats before shutdown...");
synchronized (mStats) {
mStats.writeLocked();
}
@@ -84,8 +84,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
public byte[] getStatistics() {
mContext.enforceCallingPermission(
android.Manifest.permission.BATTERY_STATS, null);
- //Log.i("foo", "SENDING BATTERY INFO:");
- //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo"));
+ //Slog.i("foo", "SENDING BATTERY INFO:");
+ //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
mStats.writeToParcel(out, 0);
byte[] data = out.marshall();
@@ -158,9 +158,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
public void noteInputEvent() {
enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteInputEventLocked();
- }
+ mStats.noteInputEventAtomic();
}
public void noteUserActivity(int uid, int event) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 75c9600..c3f0b3e 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -126,7 +126,9 @@ class BroadcastRecord extends Binder {
pw.println(prefix + "curApp=" + curApp);
pw.println(prefix + "curComponent="
+ (curComponent != null ? curComponent.toShortString() : "--"));
- pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir);
+ if (curReceiver != null && curReceiver.applicationInfo != null) {
+ pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir);
+ }
}
String stateStr = " (?)";
switch (state) {
diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java
index ce07430..5f3b0ce 100644
--- a/services/java/com/android/server/am/DeviceMonitor.java
+++ b/services/java/com/android/server/am/DeviceMonitor.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import android.util.Log;
+import android.util.Slog;
import java.io.*;
import java.util.Arrays;
@@ -65,7 +65,7 @@ class DeviceMonitor {
try {
dump();
} catch (IOException e) {
- Log.w(LOG_TAG, "Dump failed.", e);
+ Slog.w(LOG_TAG, "Dump failed.", e);
}
pause();
}
@@ -100,7 +100,7 @@ class DeviceMonitor {
Arrays.sort(files);
for (int i = 0; i < count; i++) {
if (!files[i].delete()) {
- Log.w(LOG_TAG, "Couldn't delete " + files[i] + ".");
+ Slog.w(LOG_TAG, "Couldn't delete " + files[i] + ".");
}
}
}
@@ -178,7 +178,7 @@ class DeviceMonitor {
closeable.close();
}
} catch (IOException e) {
- Log.w(LOG_TAG, e);
+ Slog.w(LOG_TAG, e);
}
}
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
new file mode 100644
index 0000000..aadd37d
--- /dev/null
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -0,0 +1,85 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.server.am
+
+2719 configuration_changed (config mask|1|5)
+2721 cpu (total|1|6),(user|1|6),(system|1|6),(iowait|1|6),(irq|1|6),(softirq|1|6)
+
+# ActivityManagerService.systemReady() starts:
+3040 boot_progress_ams_ready (time|2|3)
+# ActivityManagerService calls enableScreenAfterBoot():
+3050 boot_progress_enable_screen (time|2|3)
+
+# Do not change these names without updating the checkin_events setting in
+# google3/googledata/wireless/android/provisioning/gservices.config !!
+#
+# An activity is being finished:
+30001 am_finish_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+# A task is being brought to the front of the screen:
+30002 am_task_to_front (Task|1|5)
+# An existing activity is being given a new intent:
+30003 am_new_intent (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# A new task is being created:
+30004 am_create_task (Task ID|1|5)
+# A new activity is being created in an existing task:
+30005 am_create_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# An activity has been resumed into the foreground but was not already running:
+30006 am_restart_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been resumed and is now in the foreground:
+30007 am_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+# Application Not Responding
+30008 am_anr (pid|1|5),(Package Name|3),(Flags|1|5),(reason|3)
+# Activity launch time
+30009 activity_launch_time (Token|1|5),(Component Name|3),(time|2|3)
+# Application process bound to work
+30010 am_proc_bound (PID|1|5),(Process Name|3)
+# Application process died
+30011 am_proc_died (PID|1|5),(Process Name|3)
+# The Activity Manager failed to pause the given activity.
+30012 am_failed_to_pause (Token|1|5),(Wanting to pause|3),(Currently pausing|3)
+# Attempting to pause the current activity
+30013 am_pause_activity (Token|1|5),(Component Name|3)
+# Application process has been started
+30014 am_proc_start (PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
+# An application process has been marked as bad
+30015 am_proc_bad (UID|1|5),(Process Name|3)
+# An application process that was bad is now marked as good
+30016 am_proc_good (UID|1|5),(Process Name|3)
+# Reporting to applications that memory is low
+30017 am_low_memory (Num Processes|1|1)
+# An activity is being destroyed:
+30018 am_destroy_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been relaunched, resumed, and is now in the foreground:
+30019 am_relaunch_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been relaunched:
+30020 am_relaunch_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+# The activity's onPause has been called.
+30021 am_on_paused_called (Component Name|3)
+# The activity's onResume has been called.
+30022 am_on_resume_called (Component Name|3)
+# Kill a process to reclaim memory.
+30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
+# Discard an undelivered serialized broadcast (timeout/ANR/crash)
+30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
+30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
+# A service is being created
+30030 am_create_service (Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
+# A service is being destroyed
+30031 am_destroy_service (Service Record|1|5),(Name|3),(PID|1|5)
+# A process has crashed too many times, it is being cleared
+30032 am_process_crashed_too_much (Name|3),(PID|1|5)
+# An unknown process is trying to attach to the activity manager
+30033 am_drop_process (PID|1|5)
+# A service has crashed too many times, it is being stopped
+30034 am_service_crashed_too_much (Crash Count|1|1),(Component Name|3),(PID|1|5)
+# A service is going to be restarted after its process went away
+30035 am_schedule_service_restart (Component Name|3),(Time|2|3)
+# A client was waiting for a content provider, but its process was lost
+30036 am_provider_lost_process (Package Name|3),(UID|1|5),(Name|3)
+# The activity manager gave up on a new process taking too long to start
+30037 am_process_start_timeout (PID|1|5),(UID|1|5),(Process Name|3)
+
+# Unhandled exception
+30039 am_crash (PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
+# Log.wtf() called
+30040 am_wtf (PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 84ded22..dca7a99 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -373,7 +373,7 @@ class HistoryRecord extends IApplicationToken.Stub {
final long totalTime = service.mInitialStartTime != 0
? (curTime - service.mInitialStartTime) : thisTime;
if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
- EventLog.writeEvent(ActivityManagerService.LOG_ACTIVITY_LAUNCH_TIME,
+ EventLog.writeEvent(EventLogTags.ACTIVITY_LAUNCH_TIME,
System.identityHashCode(this), shortComponentName,
thisTime, totalTime);
StringBuilder sb = service.mStringBuilder;
@@ -387,12 +387,14 @@ class HistoryRecord extends IApplicationToken.Stub {
sb.append(" ms)");
Log.i(ActivityManagerService.TAG, sb.toString());
}
+ service.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
if (totalTime > 0) {
service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
}
startTime = 0;
service.mInitialStartTime = 0;
}
+ service.reportActivityVisibleLocked(this);
if (ActivityManagerService.DEBUG_SWITCH) Log.v(
ActivityManagerService.TAG, "windowsVisible(): " + this);
if (!nowVisible) {
@@ -456,8 +458,10 @@ class HistoryRecord extends IApplicationToken.Stub {
}
public boolean keyDispatchingTimedOut() {
+ HistoryRecord r;
+ ProcessRecord anrApp = null;
synchronized(service) {
- HistoryRecord r = getWaitingHistoryRecordLocked();
+ r = getWaitingHistoryRecordLocked();
if (r != null && r.app != null) {
if (r.app.debugging) {
return false;
@@ -470,8 +474,7 @@ class HistoryRecord extends IApplicationToken.Stub {
}
if (r.app.instrumentationClass == null) {
- service.appNotRespondingLocked(r.app, r, this,
- "keyDispatchingTimedOut");
+ anrApp = r.app;
} else {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
@@ -480,8 +483,14 @@ class HistoryRecord extends IApplicationToken.Stub {
r.app, Activity.RESULT_CANCELED, info);
}
}
- return true;
}
+
+ if (anrApp != null) {
+ service.appNotResponding(anrApp, r, this,
+ "keyDispatchingTimedOut");
+ }
+
+ return true;
}
/** Returns the key dispatching timeout for this application token. */
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index b3086d5..847e91b 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -24,7 +24,7 @@ import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
+import android.util.Slog;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -81,7 +81,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
hash = (ODD_PRIME_NUMBER*hash) + _t;
hashCode = hash;
- //Log.i(ActivityManagerService.TAG, this + " hashCode=0x"
+ //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
// + Integer.toHexString(hashCode));
}
@@ -145,8 +145,9 @@ class PendingIntentRecord extends IIntentSender.Stub {
public String toString() {
return "Key{" + typeName() + " pkg=" + packageName
- + " intent=" + requestIntent.toShortString(true, false) + " flags=0x"
- + Integer.toHexString(flags) + "}";
+ + " intent="
+ + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>")
+ + " flags=0x" + Integer.toHexString(flags) + "}";
}
String typeName() {
@@ -212,7 +213,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
finalIntent, resolvedType,
resultTo, resultWho, requestCode, false);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG,
+ Slog.w(ActivityManagerService.TAG,
"Unable to send startActivity intent", e);
}
break;
@@ -230,7 +231,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
(finishedReceiver != null), false);
sendFinish = false;
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG,
+ Slog.w(ActivityManagerService.TAG,
"Unable to send startActivity intent", e);
}
break;
@@ -239,7 +240,7 @@ class PendingIntentRecord extends IIntentSender.Stub {
owner.startServiceInPackage(uid,
finalIntent, resolvedType);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG,
+ Slog.w(ActivityManagerService.TAG,
"Unable to send startService intent", e);
}
break;
@@ -262,17 +263,26 @@ class PendingIntentRecord extends IIntentSender.Stub {
}
protected void finalize() throws Throwable {
- if (!canceled) {
- synchronized(owner) {
- WeakReference<PendingIntentRecord> current =
- owner.mIntentSenderRecords.get(key);
- if (current == ref) {
- owner.mIntentSenderRecords.remove(key);
- }
+ try {
+ if (!canceled) {
+ owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
+ ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
}
+ } finally {
+ super.finalize();
}
}
+ public void completeFinalize() {
+ synchronized(owner) {
+ WeakReference<PendingIntentRecord> current =
+ owner.mIntentSenderRecords.get(key);
+ if (current == ref) {
+ owner.mIntentSenderRecords.remove(key);
+ }
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("uid="); pw.print(uid);
pw.print(" packageName="); pw.print(key.packageName);
@@ -286,8 +296,10 @@ class PendingIntentRecord extends IIntentSender.Stub {
pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
}
- pw.print(prefix); pw.print("requestIntent=");
- pw.println(key.requestIntent.toShortString(true, true));
+ if (key.requestIntent != null) {
+ pw.print(prefix); pw.print("requestIntent=");
+ pw.println(key.requestIntent.toShortString(true, true));
+ }
if (sent || canceled) {
pw.print(prefix); pw.print("sent="); pw.print(sent);
pw.print(" canceled="); pw.println(canceled);
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 6202257..7620468 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -28,6 +28,7 @@ import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.PrintWriterPrinter;
import java.io.PrintWriter;
@@ -50,6 +51,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
// 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
+ long lastActivityTime; // For managing the LRU list
+ long lruWeight; // Weight for ordering in LRU list
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
@@ -61,6 +64,7 @@ class ProcessRecord implements Watchdog.PssRequestor {
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
+ boolean killedBackground; // True when proc has been killed due to too many bg
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
@@ -73,6 +77,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
long lastRequestedGc; // When we last asked the app to do a gc
long lastLowMemory; // When we last told the app that memory is low
boolean reportLowMemory; // Set to true when waiting to report low mem
+ boolean empty; // Is this an empty background process?
+ boolean hidden; // Is this a hidden process?
int lastPss; // Last pss size reported by app.
String adjType; // Debugging: primary thing impacting oom_adj.
int adjTypeCode; // Debugging: adj code to report to app.
@@ -108,6 +114,7 @@ class ProcessRecord implements Watchdog.PssRequestor {
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
+ String shortStringName; // caching of toShortString() result.
String stringName; // caching of toString() result.
// These reports are generated & stored when an app gets into an error condition.
@@ -120,6 +127,7 @@ class ProcessRecord implements Watchdog.PssRequestor {
ComponentName errorReportReceiver;
void dump(PrintWriter pw, String prefix) {
+ long now = SystemClock.uptimeMillis();
if (info.className != null) {
pw.print(prefix); pw.print("class="); pw.println(info.className);
}
@@ -149,6 +157,10 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.print(" curReceiver="); pw.println(curReceiver);
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
+ pw.print(prefix); pw.print("lastActivityTime="); pw.print(lastActivityTime);
+ pw.print(" lruWeight="); pw.println(lruWeight);
+ pw.print(" hidden="); pw.print(hidden);
+ pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" hidden="); pw.print(hiddenAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
@@ -163,6 +175,9 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.print(prefix); pw.print("persistent="); pw.print(persistent);
pw.print(" removed="); pw.print(removed);
pw.print(" persistentActivities="); pw.println(persistentActivities);
+ if (killedBackground) {
+ pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
+ }
if (debugging || crashing || crashDialog != null || notResponding
|| anrDialog != null || bad) {
pw.print(prefix); pw.print("debugging="); pw.print(debugging);
@@ -220,6 +235,7 @@ class ProcessRecord implements Watchdog.PssRequestor {
public void setPid(int _pid) {
pid = _pid;
+ shortStringName = null;
stringName = null;
}
@@ -256,12 +272,16 @@ class ProcessRecord implements Watchdog.PssRequestor {
}
}
- public String toString() {
- if (stringName != null) {
- return stringName;
+ public String toShortString() {
+ if (shortStringName != null) {
+ return shortStringName;
}
StringBuilder sb = new StringBuilder(128);
- sb.append("ProcessRecord{");
+ toShortString(sb);
+ return shortStringName = sb.toString();
+ }
+
+ void toShortString(StringBuilder sb) {
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(' ');
sb.append(pid);
@@ -269,6 +289,15 @@ class ProcessRecord implements Watchdog.PssRequestor {
sb.append(processName);
sb.append('/');
sb.append(info.uid);
+ }
+
+ public String toString() {
+ if (stringName != null) {
+ return stringName;
+ }
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("ProcessRecord{");
+ toShortString(sb);
sb.append('}');
return stringName = sb.toString();
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 2f2cc32..0542497 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -29,7 +29,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.util.Log;
+import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -269,8 +269,12 @@ class ServiceRecord extends Binder {
inm.enqueueNotification(localPackageName, localForegroundId,
localForegroundNoti, outId);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG, "Error showing notification for service",
- e);
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for service", e);
+ // If it gave us a garbage notification, it doesn't
+ // get to be foreground.
+ ams.setServiceForeground(name, ServiceRecord.this,
+ localForegroundId, null, true);
} catch (RemoteException e) {
}
}
@@ -293,8 +297,8 @@ class ServiceRecord extends Binder {
try {
inm.cancelNotification(localPackageName, localForegroundId);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG, "Error canceling notification for"
- + " service", e);
+ Slog.w(ActivityManagerService.TAG,
+ "Error canceling notification for service", e);
} catch (RemoteException e) {
}
}
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index f99ca96..1b9e1c7 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -27,7 +27,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.util.Log;
+import android.util.Slog;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -149,14 +149,14 @@ public final class UsageStatsService extends IUsageStats.Stub {
PkgUsageStatsExtended(Parcel in) {
mLaunchCount = in.readInt();
mUsageTime = in.readLong();
- if (localLOGV) Log.v(TAG, "Launch count: " + mLaunchCount
+ if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
+ ", Usage time:" + mUsageTime);
final int N = in.readInt();
- if (localLOGV) Log.v(TAG, "Reading comps: " + N);
+ if (localLOGV) Slog.v(TAG, "Reading comps: " + N);
for (int i=0; i<N; i++) {
String comp = in.readString();
- if (localLOGV) Log.v(TAG, "Component: " + comp);
+ if (localLOGV) Slog.v(TAG, "Component: " + comp);
TimeStats times = new TimeStats(in);
mLaunchTimes.put(comp, times);
}
@@ -231,7 +231,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
while (i > 0) {
i--;
if (fList[i].startsWith(prefix)) {
- Log.i(TAG, "Deleting old usage file: " + fList[i]);
+ Slog.i(TAG, "Deleting old usage file: " + fList[i]);
(new File(parentDir, fList[i])).delete();
}
}
@@ -291,7 +291,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
newFile.createNewFile();
}
} catch (IOException e) {
- Log.w(TAG,"Error : " + e + " reading data from file:" + newFile);
+ Slog.w(TAG,"Error : " + e + " reading data from file:" + newFile);
}
}
}
@@ -300,7 +300,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
Parcel in = getParcelForFile(file);
int vers = in.readInt();
if (vers != VERSION) {
- Log.w(TAG, "Usage stats version changed; dropping");
+ Slog.w(TAG, "Usage stats version changed; dropping");
return;
}
int N = in.readInt();
@@ -310,7 +310,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (pkgName == null) {
break;
}
- if (localLOGV) Log.v(TAG, "Reading package #" + N + ": " + pkgName);
+ if (localLOGV) Slog.v(TAG, "Reading package #" + N + ": " + pkgName);
PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
synchronized (mStatsLock) {
mStats.put(pkgName, pus);
@@ -356,7 +356,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
for (int i = 0; i < count; i++) {
String fileName = fileList.get(i);
File file = new File(mDir, fileName);
- Log.i(TAG, "Deleting usage file : " + fileName);
+ Slog.i(TAG, "Deleting usage file : " + fileName);
file.delete();
}
}
@@ -383,9 +383,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
File backupFile = null;
if (mFile != null && mFile.exists()) {
backupFile = new File(mFile.getPath() + ".bak");
- if (!mFile.renameTo(backupFile)) {
- Log.w(TAG, "Failed to persist new stats");
- return;
+ if (!backupFile.exists()) {
+ if (!mFile.renameTo(backupFile)) {
+ Slog.w(TAG, "Failed to persist new stats");
+ return;
+ }
+ } else {
+ mFile.delete();
}
}
@@ -407,7 +411,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
backupFile.delete();
}
} catch (IOException e) {
- Log.w(TAG, "Failed writing stats to file:" + mFile);
+ Slog.w(TAG, "Failed writing stats to file:" + mFile);
if (backupFile != null) {
mFile.delete();
backupFile.renameTo(mFile);
@@ -448,7 +452,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
public void shutdown() {
- Log.w(TAG, "Writing usage stats before shutdown...");
+ Slog.w(TAG, "Writing usage stats before shutdown...");
writeStatsToFile(true);
}
@@ -475,7 +479,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (mLastResumedPkg != null) {
// We last resumed some other package... just pause it now
// to recover.
- Log.i(TAG, "Unexpected resume of " + pkgName
+ Slog.i(TAG, "Unexpected resume of " + pkgName
+ " while already resumed in " + mLastResumedPkg);
PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
if (pus != null) {
@@ -491,7 +495,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
mLastResumedPkg = pkgName;
mLastResumedComp = componentName.getClassName();
- if (localLOGV) Log.i(TAG, "started component:" + pkgName);
+ if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
pus = new PkgUsageStatsExtended();
@@ -514,18 +518,18 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
if (!mIsResumed) {
- Log.i(TAG, "Something wrong here, didn't expect "
+ Slog.i(TAG, "Something wrong here, didn't expect "
+ pkgName + " to be paused");
return;
}
mIsResumed = false;
- if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
+ if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
// Weird some error here
- Log.i(TAG, "No package stats for pkg:"+pkgName);
+ Slog.i(TAG, "No package stats for pkg:"+pkgName);
return;
}
pus.updatePause();
@@ -642,10 +646,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
dFile.delete();
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
+ Slog.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);
+ Slog.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
}
}
}
@@ -829,7 +833,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
} else if (isCheckinRequest) {
// If checkin doesn't specify any packages, then we simply won't
// show anything.
- Log.w(TAG, "Checkin without packages");
+ Slog.w(TAG, "Checkin without packages");
return;
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
new file mode 100644
index 0000000..b43b86c
--- /dev/null
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -0,0 +1,1453 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+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.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.InterfaceConfiguration;
+import android.net.IConnectivityManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.NetworkInfo;
+import android.net.NetworkUtils;
+import android.os.BatteryManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+/**
+ * @hide
+ *
+ * Timeout
+ *
+ * TODO - look for parent classes and code sharing
+ */
+
+public class Tethering extends INetworkManagementEventObserver.Stub {
+
+ private Context mContext;
+ private final String TAG = "Tethering";
+
+ private boolean mBooted = false;
+ //used to remember if we got connected before boot finished
+ private boolean mDeferedUsbConnection = false;
+
+ // TODO - remove both of these - should be part of interface inspection/selection stuff
+ private String[] mTetherableUsbRegexs;
+ private String[] mTetherableWifiRegexs;
+ private String[] mUpstreamIfaceRegexs;
+
+ private Looper mLooper;
+ private HandlerThread mThread;
+
+ private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
+
+ private BroadcastReceiver mStateReceiver;
+
+ private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
+ private static final String USB_NETMASK = "255.255.255.0";
+
+ // FYI - the default wifi is 192.168.43.1 and 255.255.255.0
+
+ private String[] mDhcpRange;
+ private static final String DHCP_DEFAULT_RANGE1_START = "192.168.42.2";
+ private static final String DHCP_DEFAULT_RANGE1_STOP = "192.168.42.254";
+ private static final String DHCP_DEFAULT_RANGE2_START = "192.168.43.2";
+ private static final String DHCP_DEFAULT_RANGE2_STOP = "192.168.43.254";
+
+ private String[] mDnsServers;
+ private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
+ private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
+
+ private boolean mDunRequired; // configuration info - must use DUN apn on 3g
+
+ private HierarchicalStateMachine mTetherMasterSM;
+
+ private Notification mTetheredNotification;
+
+ // whether we can tether is the && of these two - they come in as separate
+ // broadcasts so track them so we can decide what to do when either changes
+ private boolean mUsbMassStorageOff; // track the status of USB Mass Storage
+ private boolean mUsbConnected; // track the status of USB connection
+
+ public Tethering(Context context, Looper looper) {
+ Log.d(TAG, "Tethering starting");
+ mContext = context;
+ mLooper = looper;
+
+ // register for notifications from NetworkManagement Service
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.registerObserver(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error registering observer :" + e);
+ }
+
+ mIfaces = new HashMap<String, TetherInterfaceSM>();
+
+ // make our own thread so we don't anr the system
+ mThread = new HandlerThread("Tethering");
+ mThread.start();
+ mLooper = mThread.getLooper();
+ mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
+ mTetherMasterSM.start();
+
+ mStateReceiver = new StateReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ mContext.registerReceiver(mStateReceiver, filter);
+
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+ filter.addDataScheme("file");
+ mContext.registerReceiver(mStateReceiver, filter);
+
+ mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals(
+ Environment.getExternalStorageState());
+
+ mDhcpRange = context.getResources().getStringArray(
+ com.android.internal.R.array.config_tether_dhcp_range);
+ if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
+ mDhcpRange = new String[4];
+ mDhcpRange[0] = DHCP_DEFAULT_RANGE1_START;
+ mDhcpRange[1] = DHCP_DEFAULT_RANGE1_STOP;
+ mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
+ mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
+ }
+ mDunRequired = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_tether_dun_required);
+
+ mTetherableUsbRegexs = context.getResources().getStringArray(
+ com.android.internal.R.array.config_tether_usb_regexs);
+ mTetherableWifiRegexs = context.getResources().getStringArray(
+ com.android.internal.R.array.config_tether_wifi_regexs);
+ mUpstreamIfaceRegexs = context.getResources().getStringArray(
+ com.android.internal.R.array.config_tether_upstream_regexs);
+
+ // TODO - remove and rely on real notifications of the current iface
+ mDnsServers = new String[2];
+ mDnsServers[0] = DNS_DEFAULT_SERVER1;
+ mDnsServers[1] = DNS_DEFAULT_SERVER2;
+ }
+
+ public void interfaceLinkStatusChanged(String iface, boolean link) {
+ Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
+ boolean found = false;
+ boolean usb = false;
+ if (isWifi(iface)) {
+ found = true;
+ } else if (isUsb(iface)) {
+ found = true;
+ usb = true;
+ }
+ if (found == false) return;
+
+ synchronized (mIfaces) {
+ TetherInterfaceSM sm = mIfaces.get(iface);
+ if (link) {
+ if (sm == null) {
+ sm = new TetherInterfaceSM(iface, mLooper, usb);
+ mIfaces.put(iface, sm);
+ sm.start();
+ }
+ } else {
+ if (sm != null) {
+ sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
+ mIfaces.remove(iface);
+ }
+ }
+ }
+ }
+
+ private boolean isUsb(String iface) {
+ for (String regex : mTetherableUsbRegexs) {
+ if (iface.matches(regex)) return true;
+ }
+ return false;
+ }
+
+ public boolean isWifi(String iface) {
+ for (String regex : mTetherableWifiRegexs) {
+ if (iface.matches(regex)) return true;
+ }
+ return false;
+ }
+
+ public void interfaceAdded(String iface) {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ boolean found = false;
+ boolean usb = false;
+ if (isWifi(iface)) {
+ found = true;
+ }
+ if (isUsb(iface)) {
+ found = true;
+ usb = true;
+ }
+ if (found == false) {
+ Log.d(TAG, iface + " is not a tetherable iface, ignoring");
+ return;
+ }
+
+ synchronized (mIfaces) {
+ TetherInterfaceSM sm = mIfaces.get(iface);
+ if (sm != null) {
+ Log.e(TAG, "active iface (" + iface + ") reported as added, ignoring");
+ return;
+ }
+ sm = new TetherInterfaceSM(iface, mLooper, usb);
+ mIfaces.put(iface, sm);
+ sm.start();
+ }
+ Log.d(TAG, "interfaceAdded :" + iface);
+ }
+
+ public void interfaceRemoved(String iface) {
+ synchronized (mIfaces) {
+ TetherInterfaceSM sm = mIfaces.get(iface);
+ if (sm == null) {
+ Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
+ return;
+ }
+ sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
+ mIfaces.remove(iface);
+ }
+ }
+
+ public int tether(String iface) {
+ Log.d(TAG, "Tethering " + iface);
+ TetherInterfaceSM sm = null;
+ synchronized (mIfaces) {
+ sm = mIfaces.get(iface);
+ }
+ if (sm == null) {
+ Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ }
+ if (!sm.isAvailable() && !sm.isErrored()) {
+ Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ }
+ sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
+ return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ }
+
+ public int untether(String iface) {
+ Log.d(TAG, "Untethering " + iface);
+ TetherInterfaceSM sm = null;
+ synchronized (mIfaces) {
+ sm = mIfaces.get(iface);
+ }
+ if (sm == null) {
+ Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ }
+ if (sm.isErrored()) {
+ Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ }
+ sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
+ return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ }
+
+ public int getLastTetherError(String iface) {
+ TetherInterfaceSM sm = null;
+ synchronized (mIfaces) {
+ sm = mIfaces.get(iface);
+ }
+ if (sm == null) {
+ Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + ", ignoring");
+ return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ }
+ return sm.getLastError();
+ }
+
+ private void sendTetherStateChangedBroadcast() {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ try {
+ if (!service.isTetheringSupported()) return;
+ } catch (RemoteException e) {
+ return;
+ }
+
+ ArrayList<String> availableList = new ArrayList<String>();
+ ArrayList<String> activeList = new ArrayList<String>();
+ ArrayList<String> erroredList = new ArrayList<String>();
+
+ boolean wifiTethered = false;
+ boolean usbTethered = false;
+
+ synchronized (mIfaces) {
+ Set ifaces = mIfaces.keySet();
+ for (Object iface : ifaces) {
+ TetherInterfaceSM sm = mIfaces.get(iface);
+ if (sm != null) {
+ if(sm.isErrored()) {
+ erroredList.add((String)iface);
+ } else if (sm.isAvailable()) {
+ availableList.add((String)iface);
+ } else if (sm.isTethered()) {
+ if (isUsb((String)iface)) {
+ usbTethered = true;
+ } else if (isWifi((String)iface)) {
+ wifiTethered = true;
+ }
+ activeList.add((String)iface);
+ }
+ }
+ }
+ }
+ Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
+ availableList);
+ broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
+ broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
+ erroredList);
+ mContext.sendStickyBroadcast(broadcast);
+ Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
+ activeList.size() + ", " + erroredList.size());
+
+ if (usbTethered) {
+ if (wifiTethered) {
+ showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
+ } else {
+ showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
+ }
+ } else if (wifiTethered) {
+ showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
+ } else {
+ clearTetheredNotification();
+ }
+ }
+
+ private void showTetheredNotification(int icon) {
+ NotificationManager notificationManager =
+ (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager == null) {
+ return;
+ }
+
+ if (mTetheredNotification != null) {
+ if (mTetheredNotification.icon == icon) {
+ return;
+ }
+ notificationManager.cancel(mTetheredNotification.icon);
+ }
+
+ Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ Resources r = Resources.getSystem();
+ CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
+ CharSequence message = r.getText(com.android.internal.R.string.
+ tethered_notification_message);
+
+ if(mTetheredNotification == null) {
+ mTetheredNotification = new Notification();
+ mTetheredNotification.when = 0;
+ }
+ mTetheredNotification.icon = icon;
+ mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ mTetheredNotification.tickerText = title;
+ mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
+
+ notificationManager.notify(mTetheredNotification.icon, mTetheredNotification);
+ }
+
+ private void clearTetheredNotification() {
+ NotificationManager notificationManager =
+ (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null && mTetheredNotification != null) {
+ notificationManager.cancel(mTetheredNotification.icon);
+ mTetheredNotification = null;
+ }
+ }
+
+ private void updateUsbStatus() {
+ boolean enable = mUsbConnected && mUsbMassStorageOff;
+
+ if (mBooted) {
+ enableUsbIfaces(enable);
+ }
+ }
+
+ private class StateReceiver extends BroadcastReceiver {
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ mUsbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
+ == BatteryManager.BATTERY_PLUGGED_USB);
+ Tethering.this.updateUsbStatus();
+ } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
+ mUsbMassStorageOff = false;
+ updateUsbStatus();
+ }
+ else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
+ mUsbMassStorageOff = true;
+ updateUsbStatus();
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+ } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
+ mBooted = true;
+ updateUsbStatus();
+ }
+ }
+ }
+
+ // used on cable insert/remove
+ private void enableUsbIfaces(boolean enable) {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ String[] ifaces = new String[0];
+ try {
+ ifaces = service.listInterfaces();
+ } catch (Exception e) {
+ Log.e(TAG, "Error listing Interfaces :" + e);
+ return;
+ }
+ for (String iface : ifaces) {
+ if (isUsb(iface)) {
+ if (enable) {
+ interfaceAdded(iface);
+ } else {
+ interfaceRemoved(iface);
+ }
+ }
+ }
+ }
+
+ // toggled when we enter/leave the fully teathered state
+ private boolean enableUsbRndis(boolean enabled) {
+ Log.d(TAG, "enableUsbRndis(" + enabled + ")");
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ try {
+ if (enabled) {
+ synchronized (this) {
+ if (!service.isUsbRNDISStarted()) {
+ service.startUsbRNDIS();
+ }
+ }
+ } else {
+ if (service.isUsbRNDISStarted()) {
+ service.stopUsbRNDIS();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error toggling usb RNDIS :" + e);
+ return false;
+ }
+ return true;
+ }
+
+ // configured when we start tethering and unconfig'd on error or conclusion
+ private boolean configureUsbIface(boolean enabled) {
+ Log.d(TAG, "configureUsbIface(" + enabled + ")");
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ // bring toggle the interfaces
+ String[] ifaces = new String[0];
+ try {
+ ifaces = service.listInterfaces();
+ } catch (Exception e) {
+ Log.e(TAG, "Error listing Interfaces :" + e);
+ return false;
+ }
+ for (String iface : ifaces) {
+ if (isUsb(iface)) {
+ InterfaceConfiguration ifcg = null;
+ try {
+ ifcg = service.getInterfaceConfig(iface);
+ if (ifcg != null) {
+ String[] addr = USB_NEAR_IFACE_ADDR.split("\\.");
+ ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) +
+ (Integer.parseInt(addr[1]) << 16) +
+ (Integer.parseInt(addr[2]) << 8) +
+ (Integer.parseInt(addr[3]));
+ addr = USB_NETMASK.split("\\.");
+ ifcg.netmask = (Integer.parseInt(addr[0]) << 24) +
+ (Integer.parseInt(addr[1]) << 16) +
+ (Integer.parseInt(addr[2]) << 8) +
+ (Integer.parseInt(addr[3]));
+ if (enabled) {
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
+ } else {
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
+ }
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," ");
+ service.setInterfaceConfig(iface, ifcg);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public String[] getTetherableUsbRegexs() {
+ return mTetherableUsbRegexs;
+ }
+
+ public String[] getTetherableWifiRegexs() {
+ return mTetherableWifiRegexs;
+ }
+
+ public String[] getUpstreamIfaceRegexs() {
+ return mUpstreamIfaceRegexs;
+ }
+
+ public boolean isDunRequired() {
+ return mDunRequired;
+ }
+
+ public String[] getTetheredIfaces() {
+ ArrayList<String> list = new ArrayList<String>();
+ synchronized (mIfaces) {
+ Set keys = mIfaces.keySet();
+ for (Object key : keys) {
+ TetherInterfaceSM sm = mIfaces.get(key);
+ if (sm.isTethered()) {
+ list.add((String)key);
+ }
+ }
+ }
+ String[] retVal = new String[list.size()];
+ for (int i=0; i < list.size(); i++) {
+ retVal[i] = list.get(i);
+ }
+ return retVal;
+ }
+
+ public String[] getTetherableIfaces() {
+ ArrayList<String> list = new ArrayList<String>();
+ synchronized (mIfaces) {
+ Set keys = mIfaces.keySet();
+ for (Object key : keys) {
+ TetherInterfaceSM sm = mIfaces.get(key);
+ if (sm.isAvailable()) {
+ list.add((String)key);
+ }
+ }
+ }
+ String[] retVal = new String[list.size()];
+ for (int i=0; i < list.size(); i++) {
+ retVal[i] = list.get(i);
+ }
+ return retVal;
+ }
+
+ public String[] getErroredIfaces() {
+ ArrayList<String> list = new ArrayList<String>();
+ synchronized (mIfaces) {
+ Set keys = mIfaces.keySet();
+ for (Object key : keys) {
+ TetherInterfaceSM sm = mIfaces.get(key);
+ if (sm.isErrored()) {
+ list.add((String)key);
+ }
+ }
+ }
+ String[] retVal = new String[list.size()];
+ for (int i= 0; i< list.size(); i++) {
+ retVal[i] = list.get(i);
+ }
+ return retVal;
+ }
+
+
+ class TetherInterfaceSM extends HierarchicalStateMachine {
+ // notification from the master SM that it's not in tether mode
+ static final int CMD_TETHER_MODE_DEAD = 1;
+ // request from the user that it wants to tether
+ static final int CMD_TETHER_REQUESTED = 2;
+ // request from the user that it wants to untether
+ static final int CMD_TETHER_UNREQUESTED = 3;
+ // notification that this interface is down
+ static final int CMD_INTERFACE_DOWN = 4;
+ // notification that this interface is up
+ static final int CMD_INTERFACE_UP = 5;
+ // notification from the master SM that it had an error turning on cellular dun
+ static final int CMD_CELL_DUN_ERROR = 6;
+ // notification from the master SM that it had trouble enabling IP Forwarding
+ static final int CMD_IP_FORWARDING_ENABLE_ERROR = 7;
+ // notification from the master SM that it had trouble disabling IP Forwarding
+ static final int CMD_IP_FORWARDING_DISABLE_ERROR = 8;
+ // notification from the master SM that it had trouble staring tethering
+ static final int CMD_START_TETHERING_ERROR = 9;
+ // notification from the master SM that it had trouble stopping tethering
+ static final int CMD_STOP_TETHERING_ERROR = 10;
+ // notification from the master SM that it had trouble setting the DNS forwarders
+ static final int CMD_SET_DNS_FORWARDERS_ERROR = 11;
+ // the upstream connection has changed
+ static final int CMD_TETHER_CONNECTION_CHANGED = 12;
+
+ private HierarchicalState mDefaultState;
+
+ private HierarchicalState mInitialState;
+ private HierarchicalState mStartingState;
+ private HierarchicalState mTetheredState;
+
+ private HierarchicalState mUnavailableState;
+
+ private boolean mAvailable;
+ private boolean mTethered;
+ int mLastError;
+
+ String mIfaceName;
+ String mMyUpstreamIfaceName; // may change over time
+
+ boolean mUsb;
+
+ TetherInterfaceSM(String name, Looper looper, boolean usb) {
+ super(name, looper);
+ mIfaceName = name;
+ mUsb = usb;
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
+
+ mInitialState = new InitialState();
+ addState(mInitialState);
+ mStartingState = new StartingState();
+ addState(mStartingState);
+ mTetheredState = new TetheredState();
+ addState(mTetheredState);
+ mUnavailableState = new UnavailableState();
+ addState(mUnavailableState);
+
+ setInitialState(mInitialState);
+ }
+
+ public String toString() {
+ String res = new String();
+ res += mIfaceName + " - ";
+ HierarchicalState current = getCurrentState();
+ if (current == mInitialState) res += "InitialState";
+ if (current == mStartingState) res += "StartingState";
+ if (current == mTetheredState) res += "TetheredState";
+ if (current == mUnavailableState) res += "UnavailableState";
+ if (mAvailable) res += " - Available";
+ if (mTethered) res += " - Tethered";
+ res += " - lastError =" + mLastError;
+ return res;
+ }
+
+ public synchronized int getLastError() {
+ return mLastError;
+ }
+
+ private synchronized void setLastError(int error) {
+ mLastError = error;
+
+ if (isErrored()) {
+ if (mUsb) {
+ // note everything's been unwound by this point so nothing to do on
+ // further error..
+ Tethering.this.configureUsbIface(false);
+ }
+ }
+ }
+
+ // synchronized between this getter and the following setter
+ public synchronized boolean isAvailable() {
+ return mAvailable;
+ }
+
+ private synchronized void setAvailable(boolean available) {
+ mAvailable = available;
+ }
+
+ // synchronized between this getter and the following setter
+ public synchronized boolean isTethered() {
+ return mTethered;
+ }
+
+ private synchronized void setTethered(boolean tethered) {
+ mTethered = tethered;
+ }
+
+ // synchronized between this getter and the following setter
+ public synchronized boolean isErrored() {
+ return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
+ }
+
+ class InitialState extends HierarchicalState {
+ @Override
+ public void enter() {
+ setAvailable(true);
+ setTethered(false);
+ sendTetherStateChangedBroadcast();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ Log.d(TAG, "InitialState.processMessage what=" + message.what);
+ boolean retValue = true;
+ switch (message.what) {
+ case CMD_TETHER_REQUESTED:
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
+ TetherInterfaceSM.this);
+ transitionTo(mStartingState);
+ break;
+ case CMD_INTERFACE_DOWN:
+ transitionTo(mUnavailableState);
+ break;
+ default:
+ retValue = false;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class StartingState extends HierarchicalState {
+ @Override
+ public void enter() {
+ setAvailable(false);
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(true)) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
+ TetherInterfaceSM.this);
+ setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+
+ transitionTo(mInitialState);
+ return;
+ }
+ }
+ sendTetherStateChangedBroadcast();
+
+ // Skipping StartingState
+ transitionTo(mTetheredState);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ Log.d(TAG, "StartingState.processMessage what=" + message.what);
+ boolean retValue = true;
+ switch (message.what) {
+ // maybe a parent class?
+ case CMD_TETHER_UNREQUESTED:
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
+ TetherInterfaceSM.this);
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+ break;
+ }
+ }
+ transitionTo(mInitialState);
+ break;
+ case CMD_CELL_DUN_ERROR:
+ case CMD_IP_FORWARDING_ENABLE_ERROR:
+ case CMD_IP_FORWARDING_DISABLE_ERROR:
+ case CMD_START_TETHERING_ERROR:
+ case CMD_STOP_TETHERING_ERROR:
+ case CMD_SET_DNS_FORWARDERS_ERROR:
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
+ break;
+ case CMD_INTERFACE_DOWN:
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
+ TetherInterfaceSM.this);
+ transitionTo(mUnavailableState);
+ break;
+ default:
+ retValue = false;
+ }
+ return retValue;
+ }
+ }
+
+ class TetheredState extends HierarchicalState {
+ @Override
+ public void enter() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.tetherInterface(mIfaceName);
+ } catch (Exception e) {
+ setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
+
+ transitionTo(mInitialState);
+ return;
+ }
+ if (mUsb) Tethering.this.enableUsbRndis(true);
+ Log.d(TAG, "Tethered " + mIfaceName);
+ setAvailable(false);
+ setTethered(true);
+ sendTetherStateChangedBroadcast();
+ }
+ @Override
+ public void exit() {
+ if (mUsb) Tethering.this.enableUsbRndis(false);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ Log.d(TAG, "TetheredState.processMessage what=" + message.what);
+ boolean retValue = true;
+ boolean error = false;
+ switch (message.what) {
+ case CMD_TETHER_UNREQUESTED:
+ case CMD_INTERFACE_DOWN:
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ if (mMyUpstreamIfaceName != null) {
+ try {
+ service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+ mMyUpstreamIfaceName = null;
+ } catch (Exception e) {
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
+ break;
+ }
+ }
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception e) {
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
+ break;
+ }
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
+ TetherInterfaceSM.this);
+ if (message.what == CMD_TETHER_UNREQUESTED) {
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ setLastError(
+ ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+ }
+ }
+ transitionTo(mInitialState);
+ } else if (message.what == CMD_INTERFACE_DOWN) {
+ transitionTo(mUnavailableState);
+ }
+ Log.d(TAG, "Untethered " + mIfaceName);
+ break;
+ case CMD_TETHER_CONNECTION_CHANGED:
+ String newUpstreamIfaceName = (String)(message.obj);
+ b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ service = INetworkManagementService.Stub.asInterface(b);
+
+ if (mMyUpstreamIfaceName != null) {
+ try {
+ service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+ mMyUpstreamIfaceName = null;
+ } catch (Exception e) {
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
+ break;
+ }
+ }
+ if (newUpstreamIfaceName != null) {
+ try {
+ service.enableNat(mIfaceName, newUpstreamIfaceName);
+ } catch (Exception e) {
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
+ transitionTo(mInitialState);
+ return true;
+ }
+ }
+ mMyUpstreamIfaceName = newUpstreamIfaceName;
+ break;
+ case CMD_CELL_DUN_ERROR:
+ case CMD_IP_FORWARDING_ENABLE_ERROR:
+ case CMD_IP_FORWARDING_DISABLE_ERROR:
+ case CMD_START_TETHERING_ERROR:
+ case CMD_STOP_TETHERING_ERROR:
+ case CMD_SET_DNS_FORWARDERS_ERROR:
+ error = true;
+ // fall through
+ case CMD_TETHER_MODE_DEAD:
+ b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ service = INetworkManagementService.Stub.asInterface(b);
+ if (mMyUpstreamIfaceName != null) {
+ try {
+ service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+ mMyUpstreamIfaceName = null;
+ } catch (Exception e) {
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception ee) {}
+
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
+ break;
+ }
+ }
+ try {
+ service.untetherInterface(mIfaceName);
+ } catch (Exception e) {
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
+ break;
+ }
+ if (error) {
+ setLastErrorAndTransitionToInitialState(
+ ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
+ break;
+ }
+ Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
+ sendTetherStateChangedBroadcast();
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+ }
+ }
+ transitionTo(mInitialState);
+ break;
+ default:
+ retValue = false;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class UnavailableState extends HierarchicalState {
+ @Override
+ public void enter() {
+ setAvailable(false);
+ setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
+ setTethered(false);
+ sendTetherStateChangedBroadcast();
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = true;
+ switch (message.what) {
+ case CMD_INTERFACE_UP:
+ transitionTo(mInitialState);
+ break;
+ default:
+ retValue = false;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ void setLastErrorAndTransitionToInitialState(int error) {
+ setLastError(error);
+ transitionTo(mInitialState);
+ }
+
+ }
+
+ class TetherMasterSM extends HierarchicalStateMachine {
+ // an interface SM has requested Tethering
+ static final int CMD_TETHER_MODE_REQUESTED = 1;
+ // an interface SM has unrequested Tethering
+ static final int CMD_TETHER_MODE_UNREQUESTED = 2;
+ // upstream connection change - do the right thing
+ static final int CMD_UPSTREAM_CHANGED = 3;
+ // we received notice that the cellular DUN connection is up
+ static final int CMD_CELL_CONNECTION_RENEW = 4;
+ // we don't have a valid upstream conn, check again after a delay
+ static final int CMD_RETRY_UPSTREAM = 5;
+
+ // This indicates what a timeout event relates to. A state that
+ // sends itself a delayed timeout event and handles incoming timeout events
+ // should inc this when it is entered and whenever it sends a new timeout event.
+ // We do not flush the old ones.
+ private int mSequenceNumber;
+
+ private HierarchicalState mInitialState;
+ private HierarchicalState mTetherModeAliveState;
+
+ private HierarchicalState mSetIpForwardingEnabledErrorState;
+ private HierarchicalState mSetIpForwardingDisabledErrorState;
+ private HierarchicalState mStartTetheringErrorState;
+ private HierarchicalState mStopTetheringErrorState;
+ private HierarchicalState mSetDnsForwardersErrorState;
+
+ private ArrayList mNotifyList;
+
+ private boolean mConnectionRequested = false;
+
+ private String mUpstreamIfaceName = null;
+
+ private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
+ private static final int CELL_CONNECTION_RENEW_MS = 40000;
+
+ TetherMasterSM(String name, Looper looper) {
+ super(name, looper);
+
+ //Add states
+ mInitialState = new InitialState();
+ addState(mInitialState);
+ mTetherModeAliveState = new TetherModeAliveState();
+ addState(mTetherModeAliveState);
+
+ mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
+ addState(mSetIpForwardingEnabledErrorState);
+ mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
+ addState(mSetIpForwardingDisabledErrorState);
+ mStartTetheringErrorState = new StartTetheringErrorState();
+ addState(mStartTetheringErrorState);
+ mStopTetheringErrorState = new StopTetheringErrorState();
+ addState(mStopTetheringErrorState);
+ mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
+ addState(mSetDnsForwardersErrorState);
+
+ mNotifyList = new ArrayList();
+ setInitialState(mInitialState);
+ }
+
+ class TetherMasterUtilState extends HierarchicalState {
+ protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
+ protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false;
+
+ @Override
+ public boolean processMessage(Message m) {
+ return false;
+ }
+ protected int turnOnMobileConnection() {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ int retValue = Phone.APN_REQUEST_FAILED;
+ try {
+ retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ (mDunRequired ? Phone.FEATURE_ENABLE_DUN : Phone.FEATURE_ENABLE_HIPRI),
+ new Binder());
+ } catch (Exception e) {
+ }
+ switch (retValue) {
+ case Phone.APN_ALREADY_ACTIVE:
+ case Phone.APN_REQUEST_STARTED:
+ sendMessageDelayed(CMD_CELL_CONNECTION_RENEW, CELL_CONNECTION_RENEW_MS);
+ mConnectionRequested = true;
+ break;
+ case Phone.APN_REQUEST_FAILED:
+ default:
+ mConnectionRequested = false;
+ break;
+ }
+
+ return retValue;
+ }
+ protected boolean turnOffMobileConnection() {
+ if (mConnectionRequested) {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service =
+ IConnectivityManager.Stub.asInterface(b);
+ try {
+ service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ (mDunRequired? Phone.FEATURE_ENABLE_DUN :
+ Phone.FEATURE_ENABLE_HIPRI));
+ } catch (Exception e) {
+ return false;
+ }
+ mConnectionRequested = false;
+ }
+ return true;
+ }
+ protected boolean turnOnMasterTetherSettings() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.setIpForwardingEnabled(true);
+ } catch (Exception e) {
+ transitionTo(mSetIpForwardingEnabledErrorState);
+ return false;
+ }
+ try {
+ service.startTethering(mDhcpRange);
+ } catch (Exception e) {
+ transitionTo(mStartTetheringErrorState);
+ return false;
+ }
+ try {
+ service.setDnsForwarders(mDnsServers);
+ } catch (Exception e) {
+ transitionTo(mSetDnsForwardersErrorState);
+ return false;
+ }
+ return true;
+ }
+ protected boolean turnOffMasterTetherSettings() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.stopTethering();
+ } catch (Exception e) {
+ transitionTo(mStopTetheringErrorState);
+ return false;
+ }
+ try {
+ service.setIpForwardingEnabled(false);
+ } catch (Exception e) {
+ transitionTo(mSetIpForwardingDisabledErrorState);
+ return false;
+ }
+ transitionTo(mInitialState);
+ return true;
+ }
+ protected String findActiveUpstreamIface() {
+ // check for what iface we can use - if none found switch to error.
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ String[] ifaces = new String[0];
+ try {
+ ifaces = service.listInterfaces();
+ } catch (Exception e) {
+ Log.e(TAG, "Error listing Interfaces :" + e);
+ return null;
+ }
+
+ for (String iface : ifaces) {
+ for (String regex : mUpstreamIfaceRegexs) {
+ if (iface.matches(regex)) {
+ // verify it is up!
+ InterfaceConfiguration ifcg = null;
+ try {
+ ifcg = service.getInterfaceConfig(iface);
+ } catch (Exception e) {
+ Log.e(TAG, "Error getting iface config :" + e);
+ // ignore - try next
+ continue;
+ }
+ if (ifcg.interfaceFlags.contains("up")) {
+ return iface;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ protected void chooseUpstreamType(boolean tryCell) {
+ // decide if the current upstream is good or not and if not
+ // do something about it (start up DUN if required or HiPri if not)
+ String iface = findActiveUpstreamIface();
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
+ mConnectionRequested = false;
+ Log.d(TAG, "chooseUpstreamType(" + tryCell + "), dunRequired ="
+ + mDunRequired + ", iface=" + iface);
+ if (iface != null) {
+ try {
+ if (mDunRequired) {
+ // check if Dun is on - we can use that
+ NetworkInfo info = cm.getNetworkInfo(
+ ConnectivityManager.TYPE_MOBILE_DUN);
+ if (info.isConnected()) {
+ Log.d(TAG, "setting dun ifacename =" + iface);
+ // even if we're already connected - it may be somebody else's
+ // refcount, so add our own
+ turnOnMobileConnection();
+ } else {
+ // verify the iface is not the default mobile - can't use that!
+ info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ if (info.isConnected()) {
+ iface = null; // can't accept this one
+ }
+ }
+ } else {
+ Log.d(TAG, "checking if hipri brought us this connection");
+ NetworkInfo info = cm.getNetworkInfo(
+ ConnectivityManager.TYPE_MOBILE_HIPRI);
+ if (info.isConnected()) {
+ Log.d(TAG, "yes - hipri in use");
+ // even if we're already connected - it may be sombody else's
+ // refcount, so add our own
+ turnOnMobileConnection();
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling ConnectivityManager " + e);
+ iface = null;
+ }
+ }
+ // may have been set to null in the if above
+ if (iface == null ) {
+ if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
+ turnOnMobileConnection();
+ }
+ // wait for things to settle and retry
+ sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
+ }
+ notifyTetheredOfNewUpstreamIface(iface);
+ }
+ protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
+ Log.d(TAG, "notifying tethered with iface =" + ifaceName);
+ mUpstreamIfaceName = ifaceName;
+ for (Object o : mNotifyList) {
+ TetherInterfaceSM sm = (TetherInterfaceSM)o;
+ sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
+ ifaceName);
+ }
+ }
+ }
+
+ class InitialState extends TetherMasterUtilState {
+ @Override
+ public void enter() {
+ mConnectionRequested = false;
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
+ boolean retValue = true;
+ switch (message.what) {
+ case CMD_TETHER_MODE_REQUESTED:
+ TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
+ Log.d(TAG, "Tether Mode requested by " + who.toString());
+ mNotifyList.add(who);
+ transitionTo(mTetherModeAliveState);
+ break;
+ case CMD_TETHER_MODE_UNREQUESTED:
+ who = (TetherInterfaceSM)message.obj;
+ Log.d(TAG, "Tether Mode unrequested by " + who.toString());
+ int index = mNotifyList.indexOf(who);
+ if (index != -1) {
+ mNotifyList.remove(who);
+ }
+ break;
+ default:
+ retValue = false;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class TetherModeAliveState extends TetherMasterUtilState {
+ boolean mTryCell = WAIT_FOR_NETWORK_TO_SETTLE;
+ @Override
+ public void enter() {
+ mTryCell = WAIT_FOR_NETWORK_TO_SETTLE; // first pass lets just see what we have.
+ chooseUpstreamType(mTryCell);
+ mTryCell = !mTryCell;
+ turnOnMasterTetherSettings(); // may transition us out
+ }
+ @Override
+ public void exit() {
+ turnOffMobileConnection();
+ notifyTetheredOfNewUpstreamIface(null);
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
+ boolean retValue = true;
+ switch (message.what) {
+ case CMD_TETHER_MODE_REQUESTED:
+ TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
+ mNotifyList.add(who);
+ who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
+ mUpstreamIfaceName);
+ break;
+ case CMD_TETHER_MODE_UNREQUESTED:
+ who = (TetherInterfaceSM)message.obj;
+ int index = mNotifyList.indexOf(who);
+ if (index != -1) {
+ mNotifyList.remove(index);
+ if (mNotifyList.isEmpty()) {
+ turnOffMasterTetherSettings(); // transitions appropriately
+ }
+ }
+ break;
+ case CMD_UPSTREAM_CHANGED:
+ mTryCell = WAIT_FOR_NETWORK_TO_SETTLE;
+ chooseUpstreamType(mTryCell);
+ mTryCell = !mTryCell;
+ break;
+ case CMD_CELL_CONNECTION_RENEW:
+ // make sure we're still using a requested connection - may have found
+ // wifi or something since then.
+ if (mConnectionRequested) {
+ Log.d(TAG, "renewing mobile connection - requeuing for another " +
+ CELL_CONNECTION_RENEW_MS + "ms");
+ turnOnMobileConnection();
+ }
+ break;
+ case CMD_RETRY_UPSTREAM:
+ chooseUpstreamType(mTryCell);
+ mTryCell = !mTryCell;
+ break;
+ default:
+ retValue = false;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class ErrorState extends HierarchicalState {
+ int mErrorNotification;
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = true;
+ switch (message.what) {
+ case CMD_TETHER_MODE_REQUESTED:
+ TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
+ who.sendMessage(mErrorNotification);
+ break;
+ default:
+ retValue = false;
+ }
+ return retValue;
+ }
+ void notify(int msgType) {
+ mErrorNotification = msgType;
+ for (Object o : mNotifyList) {
+ TetherInterfaceSM sm = (TetherInterfaceSM)o;
+ sm.sendMessage(msgType);
+ }
+ }
+
+ }
+ class SetIpForwardingEnabledErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error in setIpForwardingEnabled");
+ notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
+ }
+ }
+
+ class SetIpForwardingDisabledErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error in setIpForwardingDisabled");
+ notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
+ }
+ }
+
+ class StartTetheringErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error in startTethering");
+ notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.setIpForwardingEnabled(false);
+ } catch (Exception e) {}
+ }
+ }
+
+ class StopTetheringErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error in stopTethering");
+ notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.setIpForwardingEnabled(false);
+ } catch (Exception e) {}
+ }
+ }
+
+ class SetDnsForwardersErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error in setDnsForwarders");
+ notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.stopTethering();
+ } catch (Exception e) {}
+ try {
+ service.setIpForwardingEnabled(false);
+ } catch (Exception e) {}
+ }
+ }
+ }
+
+ 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 ConnectivityService.Tether " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
+ return;
+ }
+
+ pw.println();
+ pw.println("Tether state:");
+ synchronized (mIfaces) {
+ for (Object o : mIfaces.values()) {
+ pw.println(" "+o.toString());
+ }
+ }
+ pw.println();
+ return;
+ }
+}
diff --git a/services/java/com/android/server/status/AnimatedImageView.java b/services/java/com/android/server/status/AnimatedImageView.java
index cd581c4..97df065 100644
--- a/services/java/com/android/server/status/AnimatedImageView.java
+++ b/services/java/com/android/server/status/AnimatedImageView.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
diff --git a/services/java/com/android/server/status/CloseDragHandle.java b/services/java/com/android/server/status/CloseDragHandle.java
index fabf2ba..ad1ac4d 100644
--- a/services/java/com/android/server/status/CloseDragHandle.java
+++ b/services/java/com/android/server/status/CloseDragHandle.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
diff --git a/services/java/com/android/server/status/DateView.java b/services/java/com/android/server/status/DateView.java
index 78bfd5e..c04fb45 100644
--- a/services/java/com/android/server/status/DateView.java
+++ b/services/java/com/android/server/status/DateView.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.BroadcastReceiver;
@@ -5,7 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.widget.TextView;
import android.view.MotionEvent;
diff --git a/services/java/com/android/server/status/ExpandedView.java b/services/java/com/android/server/status/ExpandedView.java
index d0f14cb..cb37f90 100644
--- a/services/java/com/android/server/status/ExpandedView.java
+++ b/services/java/com/android/server/status/ExpandedView.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
@@ -7,21 +23,15 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.LinearLayout;
-import android.util.Log;
+import android.util.Slog;
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
@@ -36,26 +46,13 @@ public class ExpandedView extends LinearLayout {
}
@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);
+ //Slog.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
index fe5abca..dbfcb2c 100644
--- a/services/java/com/android/server/status/FixedSizeDrawable.java
+++ b/services/java/com/android/server/status/FixedSizeDrawable.java
@@ -1,10 +1,26 @@
+/*
+ * 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 android.graphics.drawable.Drawable;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
-import android.util.Log;
+import android.util.Slog;
class FixedSizeDrawable extends Drawable {
Drawable mDrawable;
diff --git a/services/java/com/android/server/status/IconData.java b/services/java/com/android/server/status/IconData.java
index 8a61eb5..fd226f9 100644
--- a/services/java/com/android/server/status/IconData.java
+++ b/services/java/com/android/server/status/IconData.java
@@ -1,6 +1,22 @@
+/*
+ * 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 android.util.Log;
+import android.util.Slog;
public class IconData {
/**
diff --git a/services/java/com/android/server/status/IconMerger.java b/services/java/com/android/server/status/IconMerger.java
index 5b80638..aa702ae 100644
--- a/services/java/com/android/server/status/IconMerger.java
+++ b/services/java/com/android/server/status/IconMerger.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
diff --git a/services/java/com/android/server/status/LatestItemView.java b/services/java/com/android/server/status/LatestItemView.java
index a47f6ad..fe8d164 100644
--- a/services/java/com/android/server/status/LatestItemView.java
+++ b/services/java/com/android/server/status/LatestItemView.java
@@ -1,8 +1,24 @@
+/*
+ * 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 android.content.Context;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.view.MotionEvent;
import android.widget.FrameLayout;
diff --git a/services/java/com/android/server/status/NotificationData.java b/services/java/com/android/server/status/NotificationData.java
index 0a3411a..71f01ca 100644
--- a/services/java/com/android/server/status/NotificationData.java
+++ b/services/java/com/android/server/status/NotificationData.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.app.PendingIntent;
@@ -19,7 +35,7 @@ public class NotificationData {
public PendingIntent deleteIntent;
public String toString() {
- return "NotificationData(package=" + pkg + " tickerText=" + tickerText
+ return "NotificationData(package=" + pkg + " id=" + id + " tickerText=" + tickerText
+ " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent
+ " deleteIntent=" + deleteIntent
+ " clearable=" + clearable
diff --git a/services/java/com/android/server/status/NotificationLinearLayout.java b/services/java/com/android/server/status/NotificationLinearLayout.java
index ac2e44d..2fdf956 100644
--- a/services/java/com/android/server/status/NotificationLinearLayout.java
+++ b/services/java/com/android/server/status/NotificationLinearLayout.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java
index 6229292..1bb56a7 100644
--- a/services/java/com/android/server/status/NotificationViewList.java
+++ b/services/java/com/android/server/status/NotificationViewList.java
@@ -1,7 +1,23 @@
+/*
+ * 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 android.os.IBinder;
-import android.util.Log;
+import android.util.Slog;
import android.view.View;
import java.util.ArrayList;
@@ -104,10 +120,25 @@ class NotificationViewList {
return null;
}
- // gets the index of the notification in its expanded parent view
+ // gets the index of the notification's view 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;
+ final IBinder key = notification.key;
+ int index = 0;
+ // (the view order is backwards from this list order)
+ for (int i=list.size()-1; i>=0; i--) {
+ StatusBarNotification item = list.get(i);
+ if (item.key == key) {
+ return index;
+ }
+ if (item.view != null) {
+ index++;
+ }
+ }
+ Slog.e(StatusBarService.TAG, "Couldn't find notification in NotificationViewList.");
+ Slog.e(StatusBarService.TAG, "notification=" + notification);
+ dump(notification);
+ return 0;
}
void clearViews() {
@@ -142,6 +173,12 @@ class NotificationViewList {
}
void add(StatusBarNotification notification) {
+ if (StatusBarService.SPEW) {
+ Slog.d(StatusBarService.TAG, "before add NotificationViewList"
+ + " notification.data.ongoingEvent=" + notification.data.ongoingEvent);
+ dump(notification);
+ }
+
ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
long when = notification.data.when;
final int N = list.size();
@@ -156,19 +193,31 @@ class NotificationViewList {
list.add(index, notification);
if (StatusBarService.SPEW) {
+ Slog.d(StatusBarService.TAG, "after add NotificationViewList index=" + index);
+ dump(notification);
+ }
+ }
+
+ void dump(StatusBarNotification notification) {
+ if (StatusBarService.SPEW) {
+ boolean showTime = false;
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 (showTime) {
+ s += that.data.when;
+ } else {
+ s += that.data.pkg + "/" + that.data.id + "/" + that.view;
+ }
if (that.key == notification.key) {
s += "]";
}
s += " ";
}
- Log.d(StatusBarService.TAG, "NotificationViewList ongoing index=" + index + ": " + s);
+ Slog.d(StatusBarService.TAG, "NotificationViewList ongoing: " + s);
s = "";
for (int i=0; i<mLatest.size(); i++) {
@@ -176,13 +225,17 @@ class NotificationViewList {
if (that.key == notification.key) {
s += "[";
}
- s += that.data.when;
+ if (showTime) {
+ s += that.data.when;
+ } else {
+ s += that.data.pkg + "/" + that.data.id + "/" + that.view;
+ }
if (that.key == notification.key) {
s += "]";
}
s += " ";
}
- Log.d(StatusBarService.TAG, "NotificationViewList latest index=" + index + ": " + s);
+ Slog.d(StatusBarService.TAG, "NotificationViewList latest: " + s);
}
}
diff --git a/services/java/com/android/server/status/StatusBarException.java b/services/java/com/android/server/status/StatusBarException.java
index 8e93ca7..be58f59 100644
--- a/services/java/com/android/server/status/StatusBarException.java
+++ b/services/java/com/android/server/status/StatusBarException.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
public class StatusBarException extends RuntimeException {
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
index 857784b..6f8b8a8 100644
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ b/services/java/com/android/server/status/StatusBarIcon.java
@@ -1,18 +1,32 @@
+/*
+ * 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 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.util.Slog;
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;
@@ -41,7 +55,7 @@ class StatusBarIcon {
mTextView = t;
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.FILL_PARENT);
+ LinearLayout.LayoutParams.MATCH_PARENT);
t.setTextSize(16);
t.setTextColor(0xff000000);
t.setTypeface(Typeface.DEFAULT_BOLD);
@@ -142,7 +156,7 @@ class StatusBarIcon {
try {
r = context.getPackageManager().getResourcesForApplication(data.iconPackage);
} catch (PackageManager.NameNotFoundException ex) {
- Log.e(StatusBarService.TAG, "Icon package not found: " + data.iconPackage, ex);
+ Slog.e(StatusBarService.TAG, "Icon package not found: " + data.iconPackage, ex);
return null;
}
} else {
@@ -150,14 +164,14 @@ class StatusBarIcon {
}
if (data.iconId == 0) {
- Log.w(StatusBarService.TAG, "No icon ID for slot " + data.slot);
+ Slog.w(StatusBarService.TAG, "No icon ID for slot " + data.slot);
return null;
}
try {
return r.getDrawable(data.iconId);
} catch (RuntimeException e) {
- Log.w(StatusBarService.TAG, "Icon not found in "
+ Slog.w(StatusBarService.TAG, "Icon not found in "
+ (data.iconPackage != null ? data.iconId : "<system>")
+ ": " + Integer.toHexString(data.iconId));
}
diff --git a/services/java/com/android/server/status/StatusBarNotification.java b/services/java/com/android/server/status/StatusBarNotification.java
index 4636cba..e5773f7 100644
--- a/services/java/com/android/server/status/StatusBarNotification.java
+++ b/services/java/com/android/server/status/StatusBarNotification.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.os.IBinder;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index bee0930..94d1cb4 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothPbap;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -30,20 +31,27 @@ import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
import android.net.NetworkInfo;
+import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
-import android.util.Log;
+import android.text.style.RelativeSizeSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.util.Slog;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -61,6 +69,7 @@ import com.android.internal.telephony.cdma.EriInfo;
import com.android.internal.telephony.cdma.TtyIntent;
import com.android.server.am.BatteryStatsService;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
@@ -84,9 +93,14 @@ public class StatusBarPolicy {
// clock
private Calendar mCalendar;
+ private String mClockFormatString;
+ private SimpleDateFormat mClockFormat;
private IBinder mClockIcon;
private IconData mClockData;
+ // storage
+ private StorageManager mStorageManager;
+
// battery
private IBinder mBatteryIcon;
private IconData mBatteryData;
@@ -99,6 +113,7 @@ public class StatusBarPolicy {
private int mBatteryViewSequence;
private boolean mBatteryShowLowOnEndCall = false;
private static final boolean SHOW_LOW_BATTERY_WARNING = true;
+ private static final boolean SHOW_BATTERY_WARNINGS_IN_CALL = true;
// phone
private TelephonyManager mPhone;
@@ -346,6 +361,9 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
+ if (mClockFormat != null) {
+ mClockFormat.setTimeZone(mCalendar.getTimeZone());
+ }
updateClock();
}
else if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
@@ -401,6 +419,11 @@ public class StatusBarPolicy {
mClockIcon = service.addIcon(mClockData, null);
updateClock();
+ // storage
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ mStorageManager.registerListener(
+ new com.android.server.status.StorageNotification(context));
+
// battery
mBatteryData = IconData.makeIcon("battery",
null, com.android.internal.R.drawable.stat_sys_battery_unknown, 0, 0);
@@ -532,10 +555,80 @@ public class StatusBarPolicy {
sInstance = new StatusBarPolicy(context, service);
}
+ private final CharSequence getSmallTime() {
+ boolean b24 = DateFormat.is24HourFormat(mContext);
+ int res;
+
+ if (b24) {
+ res = R.string.twenty_four_hour_time_format;
+ } else {
+ res = R.string.twelve_hour_time_format;
+ }
+
+ final char MAGIC1 = '\uEF00';
+ final char MAGIC2 = '\uEF01';
+
+ SimpleDateFormat sdf;
+ String format = mContext.getString(res);
+ if (!format.equals(mClockFormatString)) {
+ /*
+ * Search for an unquoted "a" in the format string, so we can
+ * add dummy characters around it to let us find it again after
+ * formatting and change its size.
+ */
+ int a = -1;
+ boolean quoted = false;
+ for (int i = 0; i < format.length(); i++) {
+ char c = format.charAt(i);
+
+ if (c == '\'') {
+ quoted = !quoted;
+ }
+
+ if (!quoted && c == 'a') {
+ a = i;
+ break;
+ }
+ }
+
+ if (a >= 0) {
+ // Move a back so any whitespace before the AM/PM is also in the alternate size.
+ final int b = a;
+ while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
+ a--;
+ }
+ format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
+ + "a" + MAGIC2 + format.substring(b + 1);
+ }
+
+ mClockFormat = sdf = new SimpleDateFormat(format);
+ mClockFormatString = format;
+ } else {
+ sdf = mClockFormat;
+ }
+ String result = sdf.format(mCalendar.getTime());
+
+ int magic1 = result.indexOf(MAGIC1);
+ int magic2 = result.indexOf(MAGIC2);
+
+ if (magic1 >= 0 && magic2 > magic1) {
+ SpannableStringBuilder formatted = new SpannableStringBuilder(result);
+
+ formatted.setSpan(new RelativeSizeSpan(0.7f), magic1, magic2,
+ Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+ formatted.delete(magic2, magic2 + 1);
+ formatted.delete(magic1, magic1 + 1);
+
+ return formatted;
+ } else {
+ return result;
+ }
+ }
+
private final void updateClock() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
- mClockData.text = DateFormat.getTimeFormat(mContext)
- .format(mCalendar.getTime());
+ mClockData.text = getSmallTime();
mService.updateIcon(mClockIcon, mClockData, null);
}
@@ -560,7 +653,7 @@ public class StatusBarPolicy {
boolean plugged = intent.getIntExtra("plugged", 0) != 0;
int level = intent.getIntExtra("level", -1);
if (false) {
- Log.d(TAG, "updateBattery level=" + level
+ Slog.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
@@ -589,19 +682,19 @@ public class StatusBarPolicy {
}
*/
if (false) {
- Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
+ Slog.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
}
private void onBatteryLow(Intent intent) {
if (SHOW_LOW_BATTERY_WARNING) {
if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
+ Slog.d(TAG, "mPhoneState=" + mPhoneState
+ " mLowBatteryDialog=" + mLowBatteryDialog
+ " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
- if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
showLowBatteryWarning();
} else {
mBatteryShowLowOnEndCall = true;
@@ -725,12 +818,30 @@ public class StatusBarPolicy {
d.show();
mLowBatteryDialog = d;
}
+
+ final ContentResolver cr = mContext.getContentResolver();
+ if (Settings.System.getInt(cr,
+ Settings.System.POWER_SOUNDS_ENABLED, 1) == 1)
+ {
+ final String soundPath = Settings.System.getString(cr,
+ Settings.System.LOW_BATTERY_SOUND);
+ if (soundPath != null) {
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
+ }
+ }
+ }
+ }
}
private final void updateCallState(int state) {
mPhoneState = state;
if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
+ Slog.d(TAG, "mPhoneState=" + mPhoneState
+ " mLowBatteryDialog=" + mLowBatteryDialog
+ " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
@@ -864,8 +975,9 @@ public class StatusBarPolicy {
int iconLevel = -1;
int[] iconList;
- if (!hasService()) {
- //Log.d(TAG, "updateSignalStrength: no service");
+ // Display signal strength while in "emergency calls only" mode
+ if (!hasService() && !mServiceState.isEmergencyOnly()) {
+ //Slog.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;
@@ -883,10 +995,10 @@ public class StatusBarPolicy {
// 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) iconLevel = 0;
- else if (asu >= 16) iconLevel = 4;
+ if (asu <= 2 || asu == 99) iconLevel = 0;
+ else if (asu >= 12) iconLevel = 4;
else if (asu >= 8) iconLevel = 3;
- else if (asu >= 4) iconLevel = 2;
+ else if (asu >= 5) iconLevel = 2;
else iconLevel = 1;
// Though mPhone is a Manager, this call is not an IPC
@@ -904,7 +1016,7 @@ public class StatusBarPolicy {
if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
iconLevel = getEvdoLevel();
if (false) {
- Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+ Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
}
} else {
iconLevel = getCdmaLevel();
@@ -1067,7 +1179,7 @@ public class StatusBarPolicy {
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)
+ final int iconId = (ringerMode == AudioManager.RINGER_MODE_VIBRATE)
? com.android.internal.R.drawable.stat_sys_ringer_vibrate
: com.android.internal.R.drawable.stat_sys_ringer_silent;
@@ -1198,16 +1310,16 @@ public class StatusBarPolicy {
final String action = intent.getAction();
final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
- if (false) Log.v(TAG, "updateTTY: enabled: " + enabled);
+ if (false) Slog.v(TAG, "updateTTY: enabled: " + enabled);
if (enabled) {
// TTY is on
- if (false) Log.v(TAG, "updateTTY: set TTY on");
+ if (false) Slog.v(TAG, "updateTTY: set TTY on");
mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
mService.setIconVisibility(mTTYModeIcon, true);
} else {
// TTY is off
- if (false) Log.v(TAG, "updateTTY: set TTY off");
+ if (false) Slog.v(TAG, "updateTTY: set TTY off");
mService.setIconVisibility(mTTYModeIcon, false);
}
}
@@ -1228,17 +1340,17 @@ public class StatusBarPolicy {
int iconMode = state.getCdmaEriIconMode();
if (iconIndex == -1) {
- Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
+ Slog.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
return;
}
if (iconMode == -1) {
- Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
+ Slog.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
return;
}
if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
- if (false) Log.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
+ if (false) Slog.v(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
return;
}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 34921d6..93c8d34 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -41,7 +41,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Telephony;
-import android.util.Log;
+import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -116,7 +116,7 @@ public class StatusBarService extends IStatusBar.Stub
IBinder token;
public void binderDied() {
- Log.i(TAG, "binder died for pkg=" + pkg);
+ Slog.i(TAG, "binder died for pkg=" + pkg);
disable(0, token, pkg);
token.unlinkToDeath(this, 0);
}
@@ -153,6 +153,7 @@ public class StatusBarService extends IStatusBar.Stub
StatusBarView mStatusBarView;
int mPixelFormat;
H mHandler = new H();
+ Object mQueueLock = new Object();
ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>();
NotificationCallbacks mNotificationCallbacks;
@@ -187,8 +188,9 @@ public class StatusBarService extends IStatusBar.Stub
TextView mSpnLabel;
TextView mPlmnLabel;
TextView mClearButton;
+ View mExpandedContents;
CloseDragHandle mCloseView;
- int[] mCloseLocation = new int[2];
+ int[] mPositionTmp = new int[2];
boolean mExpanded;
boolean mExpandedVisible;
@@ -198,7 +200,7 @@ public class StatusBarService extends IStatusBar.Stub
// the tracker view
TrackingView mTrackingView;
WindowManager.LayoutParams mTrackingParams;
- int mTrackingPosition;
+ int mTrackingPosition; // the position of the top of the tracking view.
// ticker
private Ticker mTicker;
@@ -206,6 +208,7 @@ public class StatusBarService extends IStatusBar.Stub
private boolean mTicking;
// Tracking finger for opening/closing.
+ int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
boolean mTracking;
VelocityTracker mVelocityTracker;
@@ -273,6 +276,7 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedDialog = new ExpandedDialog(context);
mExpandedView = expanded;
+ mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
@@ -299,6 +303,8 @@ public class StatusBarService extends IStatusBar.Stub
mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
mCloseView.mService = this;
+ mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
// add the more icon for the notifications
IconData moreData = IconData.makeIcon(null, context.getPackageName(),
R.drawable.stat_notify_more, 0, 42);
@@ -329,7 +335,7 @@ public class StatusBarService extends IStatusBar.Stub
public void systemReady() {
final StatusBarView view = mStatusBarView;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
view.getContext().getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height),
WindowManager.LayoutParams.TYPE_STATUS_BAR,
@@ -435,7 +441,7 @@ public class StatusBarService extends IStatusBar.Stub
}
private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) {
- synchronized (mQueue) {
+ synchronized (mQueueLock) {
PendingOp op = new PendingOp();
op.key = key;
op.code = code;
@@ -450,7 +456,7 @@ public class StatusBarService extends IStatusBar.Stub
}
private void addPendingOp(int code, IBinder key, boolean visible) {
- synchronized (mQueue) {
+ synchronized (mQueueLock) {
PendingOp op = new PendingOp();
op.key = key;
op.code = code;
@@ -463,7 +469,7 @@ public class StatusBarService extends IStatusBar.Stub
}
private void addPendingOp(int code, int integer) {
- synchronized (mQueue) {
+ synchronized (mQueueLock) {
PendingOp op = new PendingOp();
op.code = code;
op.integer = integer;
@@ -477,7 +483,7 @@ public class StatusBarService extends IStatusBar.Stub
// lock on mDisableRecords
void manageDisableListLocked(int what, IBinder token, String pkg) {
if (SPEW) {
- Log.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what)
+ Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what)
+ " pkg=" + pkg);
}
// update the list
@@ -552,100 +558,105 @@ public class StatusBarService extends IStatusBar.Stub
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--;
- }
- }
- }
+ ArrayList<PendingOp> queue;
+ synchronized (mQueueLock) {
+ queue = mQueue;
+ mQueue = new ArrayList<PendingOp>();
+ }
+
+ 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 = queue.size();
+ while (N > 0) {
+ PendingOp op = queue.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;
+ }
- 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 (alwaysHandle(op.code)) {
+ // coalesce these
+ for (int i=1; i<N; i++) {
+ PendingOp o = queue.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;
+ }
+ queue.remove(i);
+ i--;
+ N--;
}
}
- 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();
+ queue.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 (doDisable) {
- performDisableActions(disableWhat);
+ if (doVisibility && op.code != OP_REMOVE_ICON) {
+ performSetIconVisibility(op.key, visible);
}
}
+
+ if (queue.size() != 0) {
+ throw new RuntimeException("Assertion failed: queue.size=" + queue.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);
+ }
}
}
@@ -656,7 +667,7 @@ public class StatusBarService extends IStatusBar.Stub
/* private */ void performAddUpdateIcon(IBinder key, IconData data, NotificationData n)
throws StatusBarException {
if (SPEW) {
- Log.d(TAG, "performAddUpdateIcon icon=" + data + " notification=" + n + " key=" + key);
+ Slog.d(TAG, "performAddUpdateIcon icon=" + data + " notification=" + n + " key=" + key);
}
// notification
if (n != null) {
@@ -687,7 +698,8 @@ public class StatusBarService extends IStatusBar.Stub
&& (oldData == null
|| oldData.tickerText == null
|| !CharSequences.equals(oldData.tickerText, n.tickerText))) {
- if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
+ if (0 == (mDisabled &
+ (StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
mTicker.addEntry(n, StatusBarIcon.getIcon(mContext, data), n.tickerText);
}
}
@@ -719,7 +731,7 @@ public class StatusBarService extends IStatusBar.Stub
rightIcons[slotIndex] = icon;
mStatusIcons.addView(icon.view, pos);
} else {
- Log.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot);
+ Slog.e(TAG, "duplicate icon in slot " + slotIndex + "/" + data.slot);
mIconMap.remove(key);
mIconList.remove(icon);
return ;
@@ -748,7 +760,7 @@ public class StatusBarService extends IStatusBar.Stub
/* private */ void performSetIconVisibility(IBinder key, boolean visible) {
synchronized (mIconMap) {
if (SPEW) {
- Log.d(TAG, "performSetIconVisibility key=" + key + " visible=" + visible);
+ Slog.d(TAG, "performSetIconVisibility key=" + key + " visible=" + visible);
}
StatusBarIcon icon = mIconMap.get(key);
icon.view.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -758,7 +770,7 @@ public class StatusBarService extends IStatusBar.Stub
/* private */ void performRemoveIcon(IBinder key) {
synchronized (this) {
if (SPEW) {
- Log.d(TAG, "performRemoveIcon key=" + key);
+ Slog.d(TAG, "performRemoveIcon key=" + key);
}
StatusBarIcon icon = mIconMap.remove(key);
mIconList.remove(icon);
@@ -845,7 +857,7 @@ public class StatusBarService extends IStatusBar.Stub
exception = e;
}
if (child == null) {
- Log.e(TAG, "couldn't inflate view for package " + n.pkg, exception);
+ Slog.e(TAG, "couldn't inflate view for package " + n.pkg, exception);
return null;
}
content.addView(child);
@@ -882,11 +894,14 @@ public class StatusBarService extends IStatusBar.Stub
void updateNotificationView(StatusBarNotification notification, NotificationData oldData) {
NotificationData n = notification.data;
if (oldData != null && n != null
+ && n.when == oldData.when
+ && n.ongoingEvent == oldData.ongoingEvent
&& 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()) {
+ && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()
+ && notification.view != null) {
mNotificationData.update(notification);
try {
n.contentView.reapply(mContext, notification.contentView);
@@ -901,7 +916,7 @@ public class StatusBarService extends IStatusBar.Stub
}
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);
+ Slog.w(TAG, "couldn't reapply views for package " + n.contentView.getPackage(), e);
removeNotificationView(notification);
}
} else {
@@ -942,7 +957,7 @@ public class StatusBarService extends IStatusBar.Stub
}
private void makeExpandedVisible() {
- if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+ if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
if (mExpandedVisible) {
return;
}
@@ -962,7 +977,7 @@ public class StatusBarService extends IStatusBar.Stub
}
void animateExpand() {
- if (SPEW) Log.d(TAG, "Animate expand: expanded=" + mExpanded);
+ if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
return ;
}
@@ -970,15 +985,17 @@ public class StatusBarService extends IStatusBar.Stub
return;
}
- prepareTracking(0);
+ prepareTracking(0, true);
performFling(0, 2000.0f, true);
}
void animateCollapse() {
if (SPEW) {
- Log.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible
+ + " mExpanded=" + mExpanded
+ " mAnimating=" + mAnimating
+ + " mAnimY=" + mAnimY
+ " mAnimVel=" + mAnimVel);
}
@@ -986,17 +1003,21 @@ public class StatusBarService extends IStatusBar.Stub
return;
}
+ int y;
if (mAnimating) {
- return;
+ y = (int)mAnimY;
+ } else {
+ y = mDisplay.getHeight()-1;
}
-
- int y = mDisplay.getHeight()-1;
- prepareTracking(y);
+ // Let the fling think that we're open so it goes in the right direction
+ // and doesn't try to re-open the windowshade.
+ mExpanded = true;
+ prepareTracking(y, false);
performFling(y, -2000.0f, true);
}
void performExpand() {
- if (SPEW) Log.d(TAG, "performExpand: mExpanded=" + mExpanded);
+ if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
return ;
}
@@ -1021,7 +1042,7 @@ public class StatusBarService extends IStatusBar.Stub
}
void performCollapse() {
- if (SPEW) Log.d(TAG, "performCollapse: mExpanded=" + mExpanded
+ if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible);
if (!mExpandedVisible) {
@@ -1047,18 +1068,18 @@ public class StatusBarService extends IStatusBar.Stub
void doAnimation() {
if (mAnimating) {
- if (SPEW) Log.d(TAG, "doAnimation");
- if (SPEW) Log.d(TAG, "doAnimation before mAnimY=" + mAnimY);
+ if (SPEW) Slog.d(TAG, "doAnimation");
+ if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
incrementAnim();
- if (SPEW) Log.d(TAG, "doAnimation after mAnimY=" + mAnimY);
+ if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY);
if (mAnimY >= mDisplay.getHeight()-1) {
- if (SPEW) Log.d(TAG, "Animation completed to expanded state.");
+ if (SPEW) Slog.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.");
+ if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
mAnimating = false;
updateExpandedViewPos(0);
performCollapse();
@@ -1086,7 +1107,7 @@ public class StatusBarService extends IStatusBar.Stub
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
+ //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
// + " mAnimAccel=" + mAnimAccel);
}
@@ -1106,10 +1127,9 @@ public class StatusBarService extends IStatusBar.Stub
}
}
- void prepareTracking(int y) {
+ void prepareTracking(int y, boolean opening) {
mTracking = true;
mVelocityTracker = VelocityTracker.obtain();
- boolean opening = !mExpanded;
if (opening) {
mAnimAccel = 2000.0f;
mAnimVel = 200;
@@ -1143,7 +1163,7 @@ public class StatusBarService extends IStatusBar.Stub
mAnimY = y;
mAnimVel = vel;
- //Log.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
+ //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
if (mExpanded) {
if (!always && (
@@ -1183,7 +1203,7 @@ public class StatusBarService extends IStatusBar.Stub
}
}
}
- //Log.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
+ //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
// + " mAnimAccel=" + mAnimAccel);
long now = SystemClock.uptimeMillis();
@@ -1197,16 +1217,19 @@ public class StatusBarService extends IStatusBar.Stub
}
boolean interceptTouchEvent(MotionEvent event) {
- if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event);
+ if (SPEW) {
+ Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+ + mDisabled);
+ }
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
- return true;
+ return false;
}
final int statusBarSize = mStatusBarView.getHeight();
final int hitSize = statusBarSize*2;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
- int y = (int)event.getRawY();
+ final int y = (int)event.getRawY();
if (!mExpanded) {
mViewDelta = statusBarSize - y;
@@ -1216,8 +1239,16 @@ public class StatusBarService extends IStatusBar.Stub
}
if ((!mExpanded && y < hitSize) ||
(mExpanded && y > (mDisplay.getHeight()-hitSize))) {
- prepareTracking(y);
- mVelocityTracker.addMovement(event);
+
+ // We drop events at the edge of the screen to make the windowshade come
+ // down by accident less, especially when pushing open a device with a keyboard
+ // that rotates (like g1 and droid)
+ int x = (int)event.getRawX();
+ final int edgeBorder = mEdgeBorder;
+ if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+ prepareTracking(y, !mExpanded);// opening if we're not already fully visible
+ mVelocityTracker.addMovement(event);
+ }
}
} else if (mTracking) {
mVelocityTracker.addMovement(event);
@@ -1288,7 +1319,7 @@ public class StatusBarService extends IStatusBar.Stub
mNotificationCallbacks.onNotificationClick(mPkg, mTag, 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);
+ Slog.w(TAG, "Sending contentIntent failed: " + e);
}
deactivate();
}
@@ -1367,7 +1398,7 @@ public class StatusBarService extends IStatusBar.Stub
return;
}
- synchronized (mQueue) {
+ synchronized (mQueueLock) {
pw.println("Current Status Bar state:");
pw.println(" mExpanded=" + mExpanded
+ ", mExpandedVisible=" + mExpandedVisible);
@@ -1452,19 +1483,19 @@ public class StatusBarService extends IStatusBar.Stub
mHandler.post(new Runnable() {
public void run() {
mStatusBarView.getLocationOnScreen(mAbsPos);
- Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ Slog.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]
+ Slog.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]
+ Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1]
+ ") " + mTrackingView.getWidth() + "x"
+ mTrackingView.getHeight());
mTrackingView.debug();
@@ -1479,15 +1510,15 @@ public class StatusBarService extends IStatusBar.Stub
Drawable bg;
/// ---------- Tracking View --------------
- pixelFormat = PixelFormat.TRANSLUCENT;
+ pixelFormat = PixelFormat.RGBX_8888;
bg = mTrackingView.getBackground();
if (bg != null) {
pixelFormat = bg.getOpacity();
}
lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -1496,6 +1527,7 @@ public class StatusBarService extends IStatusBar.Stub
// lp.token = mStatusBarView.getWindowToken();
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("TrackingView");
+ lp.y = mTrackingPosition;
mTrackingParams = lp;
WindowManagerImpl.getDefault().addView(mTrackingView, lp);
@@ -1508,20 +1540,11 @@ public class StatusBarService extends IStatusBar.Stub
/// ---------- Expanded View --------------
pixelFormat = PixelFormat.TRANSLUCENT;
- bg = mExpandedView.getBackground();
- if (bg != null) {
- pixelFormat = bg.getOpacity();
- if (pixelFormat != PixelFormat.TRANSLUCENT) {
- // we want good-looking gradients, so we force a 8-bits per
- // pixel format.
- pixelFormat = PixelFormat.RGBX_8888;
- }
- }
final int disph = mDisplay.getHeight();
lp = mExpandedDialog.getWindow().getAttributes();
- lp.width = ViewGroup.LayoutParams.FILL_PARENT;
- lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ lp.height = getExpandedHeight();
lp.x = 0;
mTrackingPosition = lp.y = -disph; // sufficiently large negative
lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
@@ -1539,11 +1562,11 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
mExpandedDialog.setContentView(mExpandedView,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mExpandedDialog.getWindow().setBackgroundDrawable(null);
mExpandedDialog.show();
FrameLayout hack = (FrameLayout)mExpandedView.getParent();
- hack.setForeground(null);
}
void setDateViewVisibility(boolean visible, int anim) {
@@ -1563,7 +1586,7 @@ public class StatusBarService extends IStatusBar.Stub
void updateExpandedViewPos(int expandedPosition) {
if (SPEW) {
- Log.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+ Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
+ " mTrackingParams.y=" + mTrackingParams.y
+ " mTrackingPosition=" + mTrackingPosition);
}
@@ -1575,8 +1598,11 @@ public class StatusBarService extends IStatusBar.Stub
// Maybe the view was resized.
if (!mExpandedVisible) {
if (mTrackingView != null) {
- mTrackingPosition = mTrackingParams.y = -disph;
- WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+ mTrackingPosition = -disph;
+ if (mTrackingParams != null) {
+ mTrackingParams.y = mTrackingPosition;
+ WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+ }
}
if (mExpandedParams != null) {
mExpandedParams.y = -disph;
@@ -1605,11 +1631,15 @@ public class StatusBarService extends IStatusBar.Stub
mTrackingParams.height = disph-h;
WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
- mCloseView.getLocationInWindow(mCloseLocation);
-
if (mExpandedParams != null) {
+ mCloseView.getLocationInWindow(mPositionTmp);
+ final int closePos = mPositionTmp[1];
+
+ mExpandedContents.getLocationInWindow(mPositionTmp);
+ final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
mExpandedParams.y = pos + mTrackingView.getHeight()
- - (mTrackingParams.height-mCloseLocation[1]) - mExpandedView.getHeight();
+ - (mTrackingParams.height-closePos) - contentsBottom;
int max = h;
if (mExpandedParams.y > max) {
mExpandedParams.y = max;
@@ -1619,30 +1649,33 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedParams.y = min;
}
- /*
- Log.d(TAG, "mTrackingPosition=" + mTrackingPosition
- + " mTrackingView.height=" + mTrackingView.getHeight()
- + " diff=" + (mTrackingPosition + mTrackingView.getHeight())
- + " h=" + h);
- */
- panelSlightlyVisible((mTrackingPosition + mTrackingView.getHeight()) > h);
+ boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+ if (!visible) {
+ // if the contents aren't visible, move the expanded view way off screen
+ // because the window itself extends below the content view.
+ mExpandedParams.y = -disph;
+ }
+ panelSlightlyVisible(visible);
mExpandedDialog.getWindow().setAttributes(mExpandedParams);
}
if (SPEW) {
- Log.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition
+ Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition
+ " mTrackingParams.y=" + mTrackingParams.y
+ " mTrackingPosition=" + mTrackingPosition
- + " mExpandedParams.y=" + mExpandedParams.y);
+ + " mExpandedParams.y=" + mExpandedParams.y
+ + " mExpandedParams.height=" + mExpandedParams.height);
}
}
- void updateAvailableHeight() {
+ int getExpandedHeight() {
+ return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+ }
+
+ void updateExpandedHeight() {
if (mExpandedView != null) {
- int disph = mDisplay.getHeight();
- int h = mStatusBarView.getHeight();
- int max = disph - (mCloseView.getHeight() + h);
- mExpandedView.setMaxHeight(max);
+ mExpandedParams.height = getExpandedHeight();
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
}
}
@@ -1672,15 +1705,13 @@ public class StatusBarService extends IStatusBar.Stub
// act accordingly
if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
- Log.d(TAG, "DISABLE_EXPAND: yes");
- mAnimating = false;
- updateExpandedViewPos(0);
- performCollapse();
+ Slog.d(TAG, "DISABLE_EXPAND: yes");
+ animateCollapse();
}
}
if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- Log.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
if (mTicking) {
mNotificationIcons.setVisibility(View.INVISIBLE);
mTicker.halt();
@@ -1688,11 +1719,15 @@ public class StatusBarService extends IStatusBar.Stub
setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
}
} else {
- Log.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+ Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
if (!mExpandedVisible) {
setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
}
}
+ } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
+ mTicker.halt();
+ }
}
}
@@ -1724,7 +1759,7 @@ public class StatusBarService extends IStatusBar.Stub
void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
if (false) {
- Log.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ Slog.d(TAG, "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ " showPlmn=" + showPlmn + " plmn=" + plmn);
}
boolean something = false;
@@ -1757,11 +1792,16 @@ public class StatusBarService extends IStatusBar.Stub
* meantime, just update the things that we know change.
*/
void updateResources() {
+ Resources res = mContext.getResources();
+
mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
mOngoingTitle.setText(mContext.getText(R.string.status_bar_ongoing_events_title));
mLatestTitle.setText(mContext.getText(R.string.status_bar_latest_events_title));
mNoNotificationsTitle.setText(mContext.getText(R.string.status_bar_no_notifications_title));
- if (false) Log.v(TAG, "updateResources");
+
+ mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
+
+ if (false) Slog.v(TAG, "updateResources");
}
//
@@ -1782,7 +1822,7 @@ public class StatusBarService extends IStatusBar.Stub
public void run() {
vibrate();
SystemClock.sleep(250);
- Log.d(TAG, "startTracing");
+ Slog.d(TAG, "startTracing");
android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
mHandler.postDelayed(mStopTracing, 10000);
}
@@ -1791,7 +1831,7 @@ public class StatusBarService extends IStatusBar.Stub
Runnable mStopTracing = new Runnable() {
public void run() {
android.os.Debug.stopMethodTracing();
- Log.d(TAG, "stopTracing");
+ Slog.d(TAG, "stopTracing");
vibrate();
}
};
@@ -1803,16 +1843,30 @@ public class StatusBarService extends IStatusBar.Stub
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(this, sdFilter);
}
@Override
public void onReceive(Context context, Intent intent) {
- ArrayList<StatusBarNotification> list = null;
- synchronized (StatusBarService.this) {
+ String pkgList[] = null;
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else {
Uri data = intent.getData();
if (data != null) {
String pkg = data.getSchemeSpecificPart();
- list = mNotificationData.notificationsForPackage(pkg);
+ if (pkg != null) {
+ pkgList = new String[]{pkg};
+ }
+ }
+ }
+ ArrayList<StatusBarNotification> list = null;
+ if (pkgList != null) {
+ synchronized (StatusBarService.this) {
+ for (String pkg : pkgList) {
+ list = mNotificationData.notificationsForPackage(pkg);
+ }
}
}
diff --git a/services/java/com/android/server/status/StatusBarView.java b/services/java/com/android/server/status/StatusBarView.java
index 35dfb81..5e1f572 100644
--- a/services/java/com/android/server/status/StatusBarView.java
+++ b/services/java/com/android/server/status/StatusBarView.java
@@ -1,9 +1,26 @@
+/*
+ * 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 android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.os.SystemClock;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -15,6 +32,8 @@ import com.android.internal.R;
public class StatusBarView extends FrameLayout {
private static final String TAG = "StatusBarView";
+ static final int DIM_ANIM_TIME = 400;
+
StatusBarService mService;
boolean mTracking;
int mStartX, mStartY;
@@ -22,6 +41,10 @@ public class StatusBarView extends FrameLayout {
ViewGroup mStatusIcons;
View mDate;
FixedSizeDrawable mBackground;
+
+ boolean mNightMode = false;
+ int mStartAlpha = 0, mEndAlpha = 0;
+ long mEndTime = 0;
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -44,7 +67,30 @@ public class StatusBarView extends FrameLayout {
super.onAttachedToWindow();
mService.onBarViewAttached();
}
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ if (mNightMode != nightMode) {
+ mNightMode = nightMode;
+ mStartAlpha = getCurAlpha();
+ mEndAlpha = mNightMode ? 0x80 : 0x00;
+ mEndTime = SystemClock.uptimeMillis() + DIM_ANIM_TIME;
+ invalidate();
+ }
+ }
+ int getCurAlpha() {
+ long time = SystemClock.uptimeMillis();
+ if (time > mEndTime) {
+ return mEndAlpha;
+ }
+ return mEndAlpha
+ - (int)(((mEndAlpha-mStartAlpha) * (mEndTime-time) / DIM_ANIM_TIME));
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -81,6 +127,18 @@ public class StatusBarView extends FrameLayout {
mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t));
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ int alpha = getCurAlpha();
+ if (alpha != 0) {
+ canvas.drawARGB(alpha, 0, 0, 0);
+ }
+ if (alpha != mEndAlpha) {
+ invalidate();
+ }
+ }
+
/**
* Gets the left position of v in this view. Throws if v is not
* a child of this.
diff --git a/services/java/com/android/server/status/StorageNotification.java b/services/java/com/android/server/status/StorageNotification.java
new file mode 100644
index 0000000..8da8cd3
--- /dev/null
+++ b/services/java/com/android/server/status/StorageNotification.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.storage.IMountService;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageResultCode;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class StorageNotification extends StorageEventListener {
+ private static final String TAG = "StorageNotification";
+
+ private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
+
+ /**
+ * Binder context for this service
+ */
+ private Context mContext;
+
+ /**
+ * 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 mUmsAvailable;
+ private StorageManager mStorageManager;
+
+ public StorageNotification(Context context) {
+ mContext = context;
+
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ mUmsAvailable = mStorageManager.isUsbMassStorageConnected();
+ Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,
+ Environment.getExternalStorageState()));
+ }
+
+ /*
+ * @override com.android.os.storage.StorageEventListener
+ */
+ @Override
+ public void onUsbMassStorageConnectionChanged(boolean connected) {
+ mUmsAvailable = connected;
+ /*
+ * Even though we may have a UMS host connected, we the SD card
+ * may not be in a state for export.
+ */
+ String st = Environment.getExternalStorageState();
+
+ Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st));
+
+ if (connected && (st.equals(
+ Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
+ /*
+ * No card or card being checked = don't display
+ */
+ connected = false;
+ }
+ updateUsbMassStorageNotification(connected);
+ }
+
+ /*
+ * @override com.android.os.storage.StorageEventListener
+ */
+ @Override
+ public void onStorageStateChanged(String path, String oldState, String newState) {
+ Slog.i(TAG, String.format(
+ "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
+ if (newState.equals(Environment.MEDIA_SHARED)) {
+ /*
+ * Storage is now shared. Modify the UMS notification
+ * for stopping UMS.
+ */
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.server.status.UsbStorageActivity.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);
+ } else if (newState.equals(Environment.MEDIA_CHECKING)) {
+ /*
+ * Storage is now checking. Update media notification and disable
+ * UMS notification.
+ */
+ 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_sdcard_prepare, true, false, null);
+ updateUsbMassStorageNotification(false);
+ } else if (newState.equals(Environment.MEDIA_MOUNTED)) {
+ /*
+ * Storage is now mounted. Dismiss any media notifications,
+ * and enable UMS notification if connected.
+ */
+ setMediaStorageNotification(0, 0, 0, false, false, null);
+ updateUsbMassStorageNotification(mUmsAvailable);
+ } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) {
+ /*
+ * Storage is now unmounted. We may have been unmounted
+ * because the user is enabling/disabling UMS, in which case we don't
+ * want to display the 'safe to unmount' notification.
+ */
+ if (!mStorageManager.isUsbMassStorageEnabled()) {
+ if (oldState.equals(Environment.MEDIA_SHARED)) {
+ /*
+ * The unmount was due to UMS being enabled. Dismiss any
+ * media notifications, and enable UMS notification if connected
+ */
+ setMediaStorageNotification(0, 0, 0, false, false, null);
+ updateUsbMassStorageNotification(mUmsAvailable);
+ } else {
+ /*
+ * Show safe to unmount media notification, and enable UMS
+ * notification if connected.
+ */
+ 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_sdcard, true, true, null);
+ updateUsbMassStorageNotification(mUmsAvailable);
+ }
+ } else {
+ /*
+ * The unmount was due to UMS being enabled. Dismiss any
+ * media notifications, and disable the UMS notification
+ */
+ setMediaStorageNotification(0, 0, 0, false, false, null);
+ updateUsbMassStorageNotification(false);
+ }
+ } else if (newState.equals(Environment.MEDIA_NOFS)) {
+ /*
+ * Storage has no filesystem. Show blank media notification,
+ * and enable UMS notification if connected.
+ */
+ 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_notify_sdcard_usb, true, false, pi);
+ updateUsbMassStorageNotification(mUmsAvailable);
+ } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) {
+ /*
+ * Storage is corrupt. Show corrupt media notification,
+ * and enable UMS notification if connected.
+ */
+ 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_notify_sdcard_usb, true, false, pi);
+ updateUsbMassStorageNotification(mUmsAvailable);
+ } else if (newState.equals(Environment.MEDIA_REMOVED)) {
+ /*
+ * Storage has been removed. Show nomedia media notification,
+ * and disable UMS notification regardless of connection state.
+ */
+ 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_notify_sdcard_usb,
+ true, false, null);
+ updateUsbMassStorageNotification(false);
+ } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) {
+ /*
+ * Storage has been removed unsafely. Show bad removal media notification,
+ * and disable UMS notification regardless of connection state.
+ */
+ 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);
+ updateUsbMassStorageNotification(false);
+ } else {
+ Slog.w(TAG, String.format("Ignoring unknown state {%s}", newState));
+ }
+ }
+
+ /**
+ * Update the state of the USB mass storage notification
+ */
+ void updateUsbMassStorageNotification(boolean available) {
+
+ if (available) {
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.server.status.UsbStorageActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final boolean adbOn = 1 == Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ADB_ENABLED,
+ 0);
+
+ 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,
+ false, true, pi);
+
+ if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+ // We assume that developers don't want to enable UMS every
+ // time they attach a device to a USB host. The average user,
+ // however, is looking to charge the phone (in which case this
+ // is harmless) or transfer files (in which case this coaches
+ // the user about how to complete that task and saves several
+ // steps).
+ mContext.startActivity(intent);
+ }
+ } else {
+ setUsbStorageNotification(0, 0, 0, false, false, null);
+ }
+ }
+
+ /**
+ * 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) {
+ 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;
+ }
+
+ 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/status/Ticker.java b/services/java/com/android/server/status/Ticker.java
index c93ee0d..e47185b 100644
--- a/services/java/com/android/server/status/Ticker.java
+++ b/services/java/com/android/server/status/Ticker.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
@@ -9,7 +25,7 @@ import android.text.StaticLayout;
import android.text.Layout.Alignment;
import android.text.TextPaint;
import android.text.TextUtils;
-import android.util.Log;
+import android.util.Slog;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
diff --git a/services/java/com/android/server/status/TickerView.java b/services/java/com/android/server/status/TickerView.java
index 349c7f4..099dffb 100644
--- a/services/java/com/android/server/status/TickerView.java
+++ b/services/java/com/android/server/status/TickerView.java
@@ -1,3 +1,18 @@
+/*
+ * 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;
diff --git a/services/java/com/android/server/status/TrackingPatternView.java b/services/java/com/android/server/status/TrackingPatternView.java
index 4cb8eff..2c91aa4 100644
--- a/services/java/com/android/server/status/TrackingPatternView.java
+++ b/services/java/com/android/server/status/TrackingPatternView.java
@@ -19,7 +19,7 @@ package com.android.server.status;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.view.View;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
diff --git a/services/java/com/android/server/status/TrackingView.java b/services/java/com/android/server/status/TrackingView.java
index 722d10c..8ec39c0 100644
--- a/services/java/com/android/server/status/TrackingView.java
+++ b/services/java/com/android/server/status/TrackingView.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.content.Context;
@@ -23,7 +39,7 @@ public class TrackingView extends LinearLayout {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mService.updateAvailableHeight();
+ mService.updateExpandedHeight();
}
@Override
diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
new file mode 100644
index 0000000..e8631c5
--- /dev/null
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageEventListener;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.ImageView;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.view.View;
+import android.view.Window;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * This activity is shown to the user for him/her to enable USB mass storage
+ * on-demand (that is, when the USB cable is connected). It uses the alert
+ * dialog style. It will be launched from a notification.
+ */
+public class UsbStorageActivity extends Activity
+ implements View.OnClickListener, OnCancelListener {
+ private static final String TAG = "UsbStorageActivity";
+
+ private Button mMountButton;
+ private Button mUnmountButton;
+ private ProgressBar mProgressBar;
+ private TextView mBanner;
+ private TextView mMessage;
+ private ImageView mIcon;
+ private StorageManager mStorageManager = null;
+ private static final int DLG_CONFIRM_KILL_STORAGE_USERS = 1;
+ private static final int DLG_ERROR_SHARING = 2;
+ static final boolean localLOGV = false;
+
+ /** Used to detect when the USB cable is unplugged, so we can call finish() */
+ private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) {
+ handleBatteryChanged(intent);
+ }
+ }
+ };
+
+ private StorageEventListener mStorageListener = new StorageEventListener() {
+ @Override
+ public void onStorageStateChanged(String path, String oldState, String newState) {
+ final boolean on = newState.equals(Environment.MEDIA_SHARED);
+ switchDisplay(on);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (mStorageManager == null) {
+ mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ if (mStorageManager == null) {
+ Log.w(TAG, "Failed to get StorageManager");
+ }
+ }
+
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setProgressBarIndeterminateVisibility(true);
+
+ setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
+
+ setContentView(com.android.internal.R.layout.usb_storage_activity);
+
+ mIcon = (ImageView) findViewById(com.android.internal.R.id.icon);
+ mBanner = (TextView) findViewById(com.android.internal.R.id.banner);
+ mMessage = (TextView) findViewById(com.android.internal.R.id.message);
+
+ mMountButton = (Button) findViewById(com.android.internal.R.id.mount_button);
+ mMountButton.setOnClickListener(this);
+ mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button);
+ mUnmountButton.setOnClickListener(this);
+ mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress);
+ }
+
+ private void switchDisplay(boolean usbStorageInUse) {
+ if (usbStorageInUse) {
+ mProgressBar.setVisibility(View.GONE);
+ mUnmountButton.setVisibility(View.VISIBLE);
+ mMountButton.setVisibility(View.GONE);
+ mIcon.setImageResource(com.android.internal.R.drawable.usb_android_connected);
+ mBanner.setText(com.android.internal.R.string.usb_storage_stop_title);
+ mMessage.setText(com.android.internal.R.string.usb_storage_stop_message);
+ } else {
+ mProgressBar.setVisibility(View.GONE);
+ mUnmountButton.setVisibility(View.GONE);
+ mMountButton.setVisibility(View.VISIBLE);
+ mIcon.setImageResource(com.android.internal.R.drawable.usb_android);
+ mBanner.setText(com.android.internal.R.string.usb_storage_title);
+ mMessage.setText(com.android.internal.R.string.usb_storage_message);
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mStorageManager.registerListener(mStorageListener);
+ registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ try {
+ switchDisplay(mStorageManager.isUsbMassStorageEnabled());
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to read UMS enable state", ex);
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mBatteryReceiver);
+ if (mStorageManager == null && mStorageListener != null) {
+ mStorageManager.unregisterListener(mStorageListener);
+ }
+ }
+
+ private void handleBatteryChanged(Intent intent) {
+ int pluggedType = intent.getIntExtra("plugged", 0);
+ if (pluggedType == 0) {
+ // It was disconnected from the plug, so finish
+ finish();
+ }
+ }
+
+ private IMountService getMountService() {
+ IBinder service = ServiceManager.getService("mount");
+ if (service != null) {
+ return IMountService.Stub.asInterface(service);
+ }
+ return null;
+ }
+
+ @Override
+ public Dialog onCreateDialog(int id, Bundle args) {
+ switch (id) {
+ case DLG_CONFIRM_KILL_STORAGE_USERS:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.dlg_confirm_kill_storage_users_title)
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ switchUsbMassStorageAsync(true);
+ }})
+ .setNegativeButton(R.string.cancel, null)
+ .setMessage(R.string.dlg_confirm_kill_storage_users_text)
+ .setOnCancelListener(this)
+ .create();
+ case DLG_ERROR_SHARING:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.dlg_error_title)
+ .setNeutralButton(R.string.dlg_ok, null)
+ .setMessage(R.string.usb_storage_error_message)
+ .setOnCancelListener(this)
+ .create();
+ }
+ return null;
+ }
+
+ private void showDialogInner(int id) {
+ removeDialog(id);
+ showDialog(id);
+ }
+
+ private void switchUsbMassStorageAsync(boolean on) {
+ mUnmountButton.setVisibility(View.GONE);
+ mMountButton.setVisibility(View.GONE);
+
+ mProgressBar.setVisibility(View.VISIBLE);
+ // will be hidden once USB mass storage kicks in (or fails)
+
+ final boolean _on = on;
+ new Thread() {
+ public void run() {
+ if (_on) {
+ mStorageManager.enableUsbMassStorage();
+ } else {
+ mStorageManager.disableUsbMassStorage();
+ }
+ }
+ }.start();
+ }
+
+ private void checkStorageUsers() {
+ IMountService ims = getMountService();
+ if (ims == null) {
+ // Display error dialog
+ showDialogInner(DLG_ERROR_SHARING);
+ }
+ String extStoragePath = Environment.getExternalStorageDirectory().toString();
+ boolean showDialog = false;
+ try {
+ int[] stUsers = ims.getStorageUsers(extStoragePath);
+ if (stUsers != null && stUsers.length > 0) {
+ showDialog = true;
+ } else {
+ // List of applications on sdcard.
+ ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ List<ApplicationInfo> infoList = am.getRunningExternalApplications();
+ if (infoList != null && infoList.size() > 0) {
+ showDialog = true;
+ }
+ }
+ } catch (RemoteException e) {
+ // Display error dialog
+ showDialogInner(DLG_ERROR_SHARING);
+ }
+ if (showDialog) {
+ // Display dialog to user
+ showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
+ } else {
+ if (localLOGV) Log.i(TAG, "Enabling UMS");
+ switchUsbMassStorageAsync(true);
+ }
+ }
+
+ public void onClick(View v) {
+ if (v == mMountButton) {
+ // Check for list of storage users and display dialog if needed.
+ checkStorageUsers();
+ } else if (v == mUnmountButton) {
+ if (localLOGV) Log.i(TAG, "Disabling UMS");
+ switchUsbMassStorageAsync(false);
+ }
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 2f48edf..9d2760e 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,10 +4,11 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
- com_android_server_HardwareService.cpp \
com_android_server_KeyInputQueue.cpp \
+ com_android_server_LightsService.cpp \
com_android_server_SensorService.cpp \
com_android_server_SystemServer.cpp \
+ com_android_server_VibratorService.cpp \
onload.cpp
LOCAL_C_INCLUDES += \
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 85d63c9..0e162bd 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -38,10 +38,6 @@
#include <linux/android_alarm.h>
#endif
-#define ONE_NANOSECOND 1000000000LL
-#define NANOSECONDS_TO_SECONDS(x) (x / ONE_NANOSECOND)
-#define SECONDS_TO_NANOSECONDS(x) (x * ONE_NANOSECOND)
-
namespace android {
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
@@ -82,17 +78,17 @@ static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, j
#endif
}
-static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong nanoseconds)
+static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
{
#if HAVE_ANDROID_OS
struct timespec ts;
- ts.tv_sec = NANOSECONDS_TO_SECONDS(nanoseconds);
- ts.tv_nsec = nanoseconds - SECONDS_TO_NANOSECONDS(ts.tv_sec);
+ ts.tv_sec = seconds;
+ ts.tv_nsec = nanoseconds;
int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
if (result < 0)
{
- LOGE("Unable to set alarm to %lld: %s\n", nanoseconds, strerror(errno));
+ LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
}
#endif
}
@@ -121,7 +117,7 @@ static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"init", "()I", (void*)android_server_AlarmManagerService_init},
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
- {"set", "(IIJ)V", (void*)android_server_AlarmManagerService_set},
+ {"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};
diff --git a/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_LightsService.cpp
index 253e655..9ed4951 100644
--- a/services/jni/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_LightsService.cpp
@@ -1,21 +1,20 @@
-/* //device/libs/android_runtime/android_os_Vibrator.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "HardwareService"
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "LightsService"
#include "jni.h"
#include "JNIHelp.h"
@@ -23,18 +22,16 @@
#include <utils/misc.h>
#include <utils/Log.h>
-#include <hardware_legacy/vibrator.h>
#include <hardware/hardware.h>
#include <hardware/lights.h>
#include <stdio.h>
-//#include <string.h>
namespace android
{
// These values must correspond with the LIGHT_ID constants in
-// HardwareService.java
+// LightsService.java
enum {
LIGHT_INDEX_BACKLIGHT = 0,
LIGHT_INDEX_KEYBOARD = 1,
@@ -42,6 +39,8 @@ enum {
LIGHT_INDEX_BATTERY = 3,
LIGHT_INDEX_NOTIFICATIONS = 4,
LIGHT_INDEX_ATTENTION = 5,
+ LIGHT_INDEX_BLUETOOTH = 6,
+ LIGHT_INDEX_WIFI = 7,
LIGHT_COUNT
};
@@ -83,6 +82,10 @@ static jint init_native(JNIEnv *env, jobject clazz)
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
+ devices->lights[LIGHT_INDEX_BLUETOOTH]
+ = get_device(module, LIGHT_ID_BLUETOOTH);
+ devices->lights[LIGHT_INDEX_WIFI]
+ = get_device(module, LIGHT_ID_WIFI);
} else {
memset(devices, 0, sizeof(Devices));
}
@@ -120,29 +123,15 @@ static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
devices->lights[light]->set_light(devices->lights[light], &state);
}
-static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
-{
- // LOGI("vibratorOn\n");
- vibrator_on(timeout_ms);
-}
-
-static void vibratorOff(JNIEnv *env, jobject clazz)
-{
- // LOGI("vibratorOff\n");
- vibrator_off();
-}
-
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },
{ "finalize_native", "(I)V", (void*)finalize_native },
{ "setLight_native", "(IIIIIII)V", (void*)setLight_native },
- { "vibratorOn", "(J)V", (void*)vibratorOn },
- { "vibratorOff", "()V", (void*)vibratorOff }
};
-int register_android_server_HardwareService(JNIEnv *env)
+int register_android_server_LightsService(JNIEnv *env)
{
- return jniRegisterNativeMethods(env, "com/android/server/HardwareService",
+ return jniRegisterNativeMethods(env, "com/android/server/LightsService",
method_table, NELEM(method_table));
}
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 3911d1f..77db6da 100644
--- a/services/jni/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "SensorService"
-#define LOG_NDEBUG 0
#include "utils/Log.h"
#include <hardware/sensors.h>
diff --git a/services/jni/com_android_server_VibratorService.cpp b/services/jni/com_android_server_VibratorService.cpp
new file mode 100644
index 0000000..6ec5c07
--- /dev/null
+++ b/services/jni/com_android_server_VibratorService.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "VibratorService"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <hardware_legacy/vibrator.h>
+
+#include <stdio.h>
+
+namespace android
+{
+
+static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
+{
+ // LOGI("vibratorOn\n");
+ vibrator_on(timeout_ms);
+}
+
+static void vibratorOff(JNIEnv *env, jobject clazz)
+{
+ // LOGI("vibratorOff\n");
+ vibrator_off();
+}
+
+static JNINativeMethod method_table[] = {
+ { "vibratorOn", "(J)V", (void*)vibratorOn },
+ { "vibratorOff", "()V", (void*)vibratorOff }
+};
+
+int register_android_server_VibratorService(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 26200d3..c16fdb8 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -7,8 +7,9 @@ namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_BatteryService(JNIEnv* env);
int register_android_server_KeyInputQueue(JNIEnv* env);
-int register_android_server_HardwareService(JNIEnv* env);
+int register_android_server_LightsService(JNIEnv* env);
int register_android_server_SensorService(JNIEnv* env);
+int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
};
@@ -26,10 +27,11 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
LOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_KeyInputQueue(env);
- register_android_server_HardwareService(env);
+ register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_BatteryService(env);
register_android_server_SensorService(env);
+ register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
return JNI_VERSION_1_4;
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
new file mode 100644
index 0000000..b07a10b
--- /dev/null
+++ b/services/tests/servicestests/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+
+LOCAL_JAVA_LIBRARIES := android.test.runner services
+LOCAL_PACKAGE_NAME := FrameworksServicesTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
new file mode 100644
index 0000000..5ce109f
--- /dev/null
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.servicestests">
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.frameworks.servicestests"
+ android:label="Frameworks Services Tests" />
+</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
new file mode 100644
index 0000000..78a90fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2009 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.os.DropBoxManager;
+import android.os.ServiceManager;
+import android.os.StatFs;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+import com.android.server.DropBoxManagerService;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.util.Random;
+import java.util.zip.GZIPOutputStream;
+
+/** Test {@link DropBoxManager} functionality. */
+public class DropBoxTest extends AndroidTestCase {
+ public void tearDown() throws Exception {
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "");
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "");
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, "");
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
+ }
+
+ public void testAddText() throws Exception {
+ DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
+ Context.DROPBOX_SERVICE);
+ long before = System.currentTimeMillis();
+ Thread.sleep(5);
+ dropbox.addText("DropBoxTest", "TEST0");
+ Thread.sleep(5);
+ long between = System.currentTimeMillis();
+ Thread.sleep(5);
+ dropbox.addText("DropBoxTest", "TEST1");
+ dropbox.addText("DropBoxTest", "TEST2");
+ Thread.sleep(5);
+ long after = System.currentTimeMillis();
+
+ DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
+
+ assertTrue(e0.getTimeMillis() > before);
+ assertTrue(e0.getTimeMillis() < between);
+ assertTrue(e1.getTimeMillis() > between);
+ assertTrue(e1.getTimeMillis() < e2.getTimeMillis());
+ assertTrue(e2.getTimeMillis() < after);
+
+ assertEquals("TEST0", e0.getText(80));
+ assertEquals("TEST1", e1.getText(80));
+ assertEquals("TES", e2.getText(3));
+
+ e0.close();
+ e1.close();
+ e2.close();
+ }
+
+ public void testAddData() throws Exception {
+ DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
+ Context.DROPBOX_SERVICE);
+ long before = System.currentTimeMillis();
+ dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
+ long after = System.currentTimeMillis();
+
+ DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", before);
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
+
+ assertEquals("DropBoxTest", e.getTag());
+ assertTrue(e.getTimeMillis() >= before);
+ assertEquals(0, e.getFlags());
+ assertTrue(null == e.getText(80));
+
+ byte[] buf = new byte[80];
+ assertEquals("TEST", new String(buf, 0, e.getInputStream().read(buf)));
+
+ e.close();
+ }
+
+ public void testAddFile() throws Exception {
+ File dir = getEmptyDir("testAddFile");
+ long before = System.currentTimeMillis();
+
+ File f0 = new File(dir, "f0.txt");
+ File f1 = new File(dir, "f1.txt.gz");
+ File f2 = new File(dir, "f2.dat");
+ File f3 = new File(dir, "f2.dat.gz");
+
+ FileWriter w0 = new FileWriter(f0);
+ GZIPOutputStream gz1 = new GZIPOutputStream(new FileOutputStream(f1));
+ FileOutputStream os2 = new FileOutputStream(f2);
+ GZIPOutputStream gz3 = new GZIPOutputStream(new FileOutputStream(f3));
+
+ w0.write("FILE0");
+ gz1.write("FILE1".getBytes());
+ os2.write("DATA2".getBytes());
+ gz3.write("DATA3".getBytes());
+
+ w0.close();
+ gz1.close();
+ os2.close();
+ gz3.close();
+
+ DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
+ Context.DROPBOX_SERVICE);
+
+ dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
+ dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
+ dropbox.addFile("DropBoxTest", f2, 0);
+ dropbox.addFile("DropBoxTest", f3, DropBoxManager.IS_GZIPPED);
+
+ DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
+ DropBoxManager.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
+
+ assertTrue(e0.getTimeMillis() > before);
+ assertTrue(e1.getTimeMillis() > e0.getTimeMillis());
+ assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
+ assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
+
+ assertEquals(DropBoxManager.IS_TEXT, e0.getFlags());
+ assertEquals(DropBoxManager.IS_TEXT, e1.getFlags());
+ assertEquals(0, e2.getFlags());
+ assertEquals(0, e3.getFlags());
+
+ assertEquals("FILE0", e0.getText(80));
+
+ byte[] buf1 = new byte[80];
+ assertEquals("FILE1", new String(buf1, 0, e1.getInputStream().read(buf1)));
+
+ assertTrue(null == e2.getText(80));
+ byte[] buf2 = new byte[80];
+ assertEquals("DATA2", new String(buf2, 0, e2.getInputStream().read(buf2)));
+
+ assertTrue(null == e3.getText(80));
+ byte[] buf3 = new byte[80];
+ assertEquals("DATA3", new String(buf3, 0, e3.getInputStream().read(buf3)));
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+ }
+
+ public void testAddEntriesInTheFuture() throws Exception {
+ File dir = getEmptyDir("testAddEntriesInTheFuture");
+ long before = System.currentTimeMillis();
+
+ // Near future: should be allowed to persist
+ FileWriter w0 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 5000) + ".txt"));
+ w0.write("FUTURE0");
+ w0.close();
+
+ // Far future: should be collapsed
+ FileWriter w1 = new FileWriter(new File(dir, "DropBoxTest@" + (before + 100000) + ".txt"));
+ w1.write("FUTURE1");
+ w1.close();
+
+ // Another far future item, this one gzipped
+ File f2 = new File(dir, "DropBoxTest@" + (before + 100001) + ".txt.gz");
+ GZIPOutputStream gz2 = new GZIPOutputStream(new FileOutputStream(f2));
+ gz2.write("FUTURE2".getBytes());
+ gz2.close();
+
+ // Tombstone in the far future
+ new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
+
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+
+ // Until a write, the timestamps are taken at face value
+ DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+ DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
+
+ assertEquals("FUTURE0", e0.getText(80));
+ assertEquals("FUTURE1", e1.getText(80));
+ assertEquals("FUTURE2", e2.getText(80));
+ assertEquals(null, e3.getText(80));
+
+ assertEquals(before + 5000, e0.getTimeMillis());
+ assertEquals(before + 100000, e1.getTimeMillis());
+ assertEquals(before + 100001, e2.getTimeMillis());
+ assertEquals(before + 100002, e3.getTimeMillis());
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+
+ // Write something to force a collapse
+ dropbox.addText("NotDropBoxTest", "FUTURE");
+ e0 = dropbox.getNextEntry(null, before);
+ e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+ e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
+
+ assertEquals("FUTURE0", e0.getText(80));
+ assertEquals("FUTURE1", e1.getText(80));
+ assertEquals("FUTURE2", e2.getText(80));
+ assertEquals(null, e3.getText(80));
+
+ assertEquals(before + 5000, e0.getTimeMillis());
+ assertEquals(before + 5001, e1.getTimeMillis());
+ assertEquals(before + 5002, e2.getTimeMillis());
+ assertEquals(before + 5003, e3.getTimeMillis());
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+ service.stop();
+ }
+
+ public void testIsTagEnabled() throws Exception {
+ DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
+ Context.DROPBOX_SERVICE);
+ long before = System.currentTimeMillis();
+ dropbox.addText("DropBoxTest", "TEST-ENABLED");
+ assertTrue(dropbox.isTagEnabled("DropBoxTest"));
+
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest",
+ "disabled");
+
+ dropbox.addText("DropBoxTest", "TEST-DISABLED");
+ assertFalse(dropbox.isTagEnabled("DropBoxTest"));
+
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest",
+ "");
+
+ dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
+ assertTrue(dropbox.isTagEnabled("DropBoxTest"));
+
+ DropBoxManager.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
+
+ assertEquals("TEST-ENABLED", e0.getText(80));
+ assertEquals("TEST-ENABLED-AGAIN", e1.getText(80));
+
+ e0.close();
+ e1.close();
+ }
+
+ public void testGetNextEntry() throws Exception {
+ File dir = getEmptyDir("testGetNextEntry");
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+
+ long before = System.currentTimeMillis();
+ dropbox.addText("DropBoxTest.A", "A0");
+ dropbox.addText("DropBoxTest.B", "B0");
+ dropbox.addText("DropBoxTest.A", "A1");
+
+ DropBoxManager.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
+ DropBoxManager.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
+
+ DropBoxManager.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
+
+ DropBoxManager.Entry x0 = dropbox.getNextEntry(null, before);
+ DropBoxManager.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
+ DropBoxManager.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
+
+ assertEquals("DropBoxTest.A", a0.getTag());
+ assertEquals("DropBoxTest.A", a1.getTag());
+ assertEquals("A0", a0.getText(80));
+ assertEquals("A1", a1.getText(80));
+
+ assertEquals("DropBoxTest.B", b0.getTag());
+ assertEquals("B0", b0.getText(80));
+
+ assertEquals("DropBoxTest.A", x0.getTag());
+ assertEquals("DropBoxTest.B", x1.getTag());
+ assertEquals("DropBoxTest.A", x2.getTag());
+ assertEquals("A0", x0.getText(80));
+ assertEquals("B0", x1.getText(80));
+ assertEquals("A1", x2.getText(80));
+
+ a0.close();
+ a1.close();
+ b0.close();
+ x0.close();
+ x1.close();
+ x2.close();
+ service.stop();
+ }
+
+ public void testSizeLimits() throws Exception {
+ File dir = getEmptyDir("testSizeLimits");
+ int blockSize = new StatFs(dir.getPath()).getBlockSize();
+
+ // Limit storage to 10 blocks
+ int kb = blockSize * 10 / 1024;
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, Integer.toString(kb));
+
+ // Three tags using a total of 12 blocks:
+ // DropBoxTest0 [ ][ ]
+ // DropBoxTest1 [x][ ][ ][ ][xxx(20 blocks)xxx]
+ // DropBoxTest2 [xxxxxxxxxx][ ][ ]
+ //
+ // The blocks marked "x" will be removed due to storage restrictions.
+ // Use random fill (so it doesn't compress), subtract a little for gzip overhead
+
+ final int overhead = 64;
+ long before = System.currentTimeMillis();
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+
+ addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
+ addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
+
+ addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
+ addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
+ addRandomEntry(dropbox, "DropBoxTest1", blockSize * 2 - overhead);
+ addRandomEntry(dropbox, "DropBoxTest1", blockSize - overhead);
+ addRandomEntry(dropbox, "DropBoxTest1", blockSize * 20 - overhead);
+
+ addRandomEntry(dropbox, "DropBoxTest2", blockSize * 4 - overhead);
+ addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
+ addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
+
+ DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+ DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+ DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
+ DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
+ DropBoxManager.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
+ DropBoxManager.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
+ DropBoxManager.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
+ DropBoxManager.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
+
+ assertEquals("DropBoxTest0", e0.getTag());
+ assertEquals("DropBoxTest0", e1.getTag());
+ assertEquals(blockSize - overhead, getEntrySize(e0));
+ assertEquals(blockSize - overhead, getEntrySize(e1));
+
+ assertEquals("DropBoxTest1", e2.getTag());
+ assertEquals("DropBoxTest1", e3.getTag());
+ assertEquals("DropBoxTest1", e4.getTag());
+ assertEquals("DropBoxTest1", e5.getTag());
+ assertEquals("DropBoxTest1", e6.getTag());
+ assertEquals(-1, getEntrySize(e2)); // Tombstone
+ assertEquals(blockSize - overhead, getEntrySize(e3));
+ assertEquals(blockSize * 2 - overhead, getEntrySize(e4));
+ assertEquals(blockSize - overhead, getEntrySize(e5));
+ assertEquals(-1, getEntrySize(e6));
+
+ assertEquals("DropBoxTest2", e7.getTag());
+ assertEquals("DropBoxTest2", e8.getTag());
+ assertEquals("DropBoxTest2", e9.getTag());
+ assertEquals(-1, getEntrySize(e7)); // Tombstone
+ assertEquals(blockSize - overhead, getEntrySize(e8));
+ assertEquals(blockSize - overhead, getEntrySize(e9));
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+ e4.close();
+ e5.close();
+ e6.close();
+ e7.close();
+ e8.close();
+ e9.close();
+
+ // Specifying a tag name skips tombstone records.
+
+ DropBoxManager.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
+ DropBoxManager.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
+ DropBoxManager.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
+
+ assertEquals("DropBoxTest1", t0.getTag());
+ assertEquals("DropBoxTest1", t1.getTag());
+ assertEquals("DropBoxTest1", t2.getTag());
+
+ assertEquals(blockSize - overhead, getEntrySize(t0));
+ assertEquals(blockSize * 2 - overhead, getEntrySize(t1));
+ assertEquals(blockSize - overhead, getEntrySize(t2));
+
+ t0.close();
+ t1.close();
+ t2.close();
+ service.stop();
+ }
+
+ public void testAgeLimits() throws Exception {
+ File dir = getEmptyDir("testAgeLimits");
+ int blockSize = new StatFs(dir.getPath()).getBlockSize();
+
+ // Limit storage to 10 blocks with an expiration of 1 second
+ int kb = blockSize * 10 / 1024;
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "1");
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, Integer.toString(kb));
+
+ // Write one normal entry and another so big that it is instantly tombstoned
+ long before = System.currentTimeMillis();
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+
+ dropbox.addText("DropBoxTest", "TEST");
+ addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
+
+ // Verify that things are as expected
+ DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
+
+ assertEquals("TEST", e0.getText(80));
+ assertEquals(null, e1.getText(80));
+ assertEquals(-1, getEntrySize(e1));
+
+ e0.close();
+ e1.close();
+
+ // Wait a second and write another entry -- old ones should be expunged
+ Thread.sleep(2000);
+ dropbox.addText("DropBoxTest", "TEST1");
+
+ e0 = dropbox.getNextEntry(null, before);
+ assertTrue(null == dropbox.getNextEntry(null, e0.getTimeMillis()));
+ assertEquals("TEST1", e0.getText(80));
+ e0.close();
+ }
+
+ public void testFileCountLimits() throws Exception {
+ File dir = getEmptyDir("testFileCountLimits");
+
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+ dropbox.addText("DropBoxTest", "TEST0");
+ dropbox.addText("DropBoxTest", "TEST1");
+ dropbox.addText("DropBoxTest", "TEST2");
+ dropbox.addText("DropBoxTest", "TEST3");
+ dropbox.addText("DropBoxTest", "TEST4");
+ dropbox.addText("DropBoxTest", "TEST5");
+
+ // Verify 6 files added
+ DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+ DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+ DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
+ DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
+ assertEquals("TEST0", e0.getText(80));
+ assertEquals("TEST5", e5.getText(80));
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+ e4.close();
+ e5.close();
+
+ // Limit to 3 files and add one more entry
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "3");
+ dropbox.addText("DropBoxTest", "TEST6");
+
+ // Verify only 3 files left
+ DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
+ DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
+ DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
+ assertEquals("TEST4", f0.getText(80));
+ assertEquals("TEST5", f1.getText(80));
+ assertEquals("TEST6", f2.getText(80));
+
+ f0.close();
+ f1.close();
+ f2.close();
+ }
+
+ public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
+ // If created with an invalid directory, the DropBoxManager should suffer quietly
+ // and fail all operations (this is how it survives a full disk).
+ // Once the directory becomes possible to create, it will start working.
+
+ File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
+ new FileOutputStream(dir).close(); // Create an empty file
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+
+ dropbox.addText("DropBoxTest", "should be ignored");
+ dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", 0));
+
+ dir.delete(); // Remove the file so a directory can be created
+ dropbox.addText("DropBoxTest", "TEST");
+ DropBoxManager.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
+ assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
+ assertEquals("DropBoxTest", e.getTag());
+ assertEquals("TEST", e.getText(80));
+ e.close();
+ service.stop();
+ }
+
+ private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
+ byte[] bytes = new byte[size];
+ new Random(System.currentTimeMillis()).nextBytes(bytes);
+
+ File f = new File(getEmptyDir("addRandomEntry"), "random.dat");
+ FileOutputStream os = new FileOutputStream(f);
+ os.write(bytes);
+ os.close();
+
+ dropbox.addFile(tag, f, 0);
+ }
+
+ private int getEntrySize(DropBoxManager.Entry e) throws Exception {
+ InputStream is = e.getInputStream();
+ if (is == null) return -1;
+ int length = 0;
+ while (is.read() != -1) length++;
+ return length;
+ }
+
+ private void recursiveDelete(File file) {
+ if (!file.delete() && file.isDirectory()) {
+ for (File f : file.listFiles()) recursiveDelete(f);
+ file.delete();
+ }
+ }
+
+ private File getEmptyDir(String name) {
+ File dir = getContext().getDir("DropBoxTest." + name, 0);
+ for (File f : dir.listFiles()) recursiveDelete(f);
+ assertTrue(dir.listFiles().length == 0);
+ return dir;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
new file mode 100644
index 0000000..636ba21
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/EntropyServiceTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+/**
+ * Tests for {@link com.android.server.EntropyService}
+ */
+public class EntropyServiceTest extends AndroidTestCase {
+
+ public void testInitialWrite() throws Exception {
+ File dir = getContext().getDir("testInitialWrite", Context.MODE_PRIVATE);
+ File file = File.createTempFile("testInitialWrite", "dat", dir);
+ file.deleteOnExit();
+ assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
+
+ // The constructor has the side effect of writing to file
+ new EntropyService("/dev/null", file.getCanonicalPath());
+
+ assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
+ }
+}