summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/AccessibilityManagerService.java668
-rw-r--r--services/java/com/android/server/AppWidgetService.java47
-rw-r--r--services/java/com/android/server/AttributeCache.java114
-rw-r--r--services/java/com/android/server/BackupManagerService.java1543
-rw-r--r--services/java/com/android/server/EntropyService.java148
-rw-r--r--services/java/com/android/server/HeadsetObserver.java3
-rw-r--r--services/java/com/android/server/IntentResolver.java20
-rw-r--r--services/java/com/android/server/LocationManagerService.java59
-rw-r--r--services/java/com/android/server/NotificationManagerService.java141
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java413
-rw-r--r--services/java/com/android/server/PackageManagerService.java369
-rw-r--r--services/java/com/android/server/PowerManagerService.java5
-rw-r--r--services/java/com/android/server/ProcessStats.java16
-rw-r--r--services/java/com/android/server/RandomBlock.java100
-rw-r--r--services/java/com/android/server/SensorService.java6
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java224
-rw-r--r--services/java/com/android/server/WallpaperService.java13
-rw-r--r--services/java/com/android/server/Watchdog.java2
-rw-r--r--services/java/com/android/server/WifiService.java169
-rw-r--r--services/java/com/android/server/WindowManagerService.java1292
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1052
-rw-r--r--services/java/com/android/server/am/AppErrorDialog.java21
-rw-r--r--services/java/com/android/server/am/AppNotRespondingDialog.java46
-rw-r--r--services/java/com/android/server/am/BackupRecord.java57
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java49
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java2
-rw-r--r--services/java/com/android/server/am/HistoryRecord.java10
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java4
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java17
-rw-r--r--services/java/com/android/server/am/ReceiverList.java2
-rwxr-xr-xservices/java/com/android/server/am/UsageStatsService.java127
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java490
-rw-r--r--services/java/com/android/server/status/StatusBarService.java11
-rw-r--r--services/jni/com_android_server_SensorService.cpp77
35 files changed, 5875 insertions, 1453 deletions
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
new file mode 100644
index 0000000..c205fc0
--- /dev/null
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -0,0 +1,668 @@
+/*
+ ** Copyright 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 static android.util.Config.LOGV;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.HandlerCaller.SomeArgs;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.accessibilityservice.IEventListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+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.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class is instantiated by the system as a system level service and can be
+ * accessed only by the system. The task of this service is to be a centralized
+ * event dispatch for {@link AccessibilityEvent}s generated across all processes
+ * on the device. Events are dispatched to {@link AccessibilityService}s.
+ *
+ * @hide
+ */
+public class AccessibilityManagerService extends IAccessibilityManager.Stub
+ implements HandlerCaller.Callback {
+
+ private static final String LOG_TAG = "AccessibilityManagerService";
+
+ private static int sIdCounter = 0;
+
+ private static final int OWN_PROCESS_ID = android.os.Process.myPid();
+
+ private static final int DO_SET_SERVICE_INFO = 10;
+
+ final HandlerCaller mCaller;
+
+ final Context mContext;
+
+ final Object mLock = new Object();
+
+ final List<Service> mServices = new ArrayList<Service>();
+
+ final List<IAccessibilityManagerClient> mClients =
+ new ArrayList<IAccessibilityManagerClient>();
+
+ final Map<ComponentName, Service> mComponentNameToServiceMap =
+ new HashMap<ComponentName, Service>();
+
+ private final List<ServiceInfo> mInstalledServices = new ArrayList<ServiceInfo>();
+
+ private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
+
+ private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':');
+
+ private PackageManager mPackageManager;
+
+ private int mHandledFeedbackTypes = 0;
+
+ private boolean mIsEnabled;
+
+ /**
+ * Handler for delayed event dispatch.
+ */
+ private Handler mHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message message) {
+ Service service = (Service) message.obj;
+ int eventType = message.arg1;
+
+ synchronized (mLock) {
+ notifyEventListenerLocked(service, eventType);
+ AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
+ service.mPendingEvents.remove(eventType);
+ tryRecycleLocked(oldEvent);
+ }
+ }
+ };
+
+ /**
+ * Creates a new instance.
+ *
+ * @param context A {@link Context} instance.
+ */
+ AccessibilityManagerService(Context context) {
+ mContext = context;
+ mPackageManager = mContext.getPackageManager();
+ mCaller = new HandlerCaller(context, this);
+
+ registerPackageChangeAndBootCompletedBroadcastReceiver();
+ registerSettingsContentObservers();
+
+ synchronized (mLock) {
+ populateAccessibilityServiceListLocked();
+ }
+ }
+
+ /**
+ * Registers a {@link BroadcastReceiver} for the events of
+ * adding/changing/removing/restarting a package and boot completion.
+ */
+ private void registerPackageChangeAndBootCompletedBroadcastReceiver() {
+ Context context = mContext;
+
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ populateAccessibilityServiceListLocked();
+ manageServicesLocked();
+
+ if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+ mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
+ updateClientsLocked();
+ }
+ }
+ }
+ };
+
+ // 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);
+
+ // boot completed
+ IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ mContext.registerReceiver(broadcastReceiver, bootFiler);
+ }
+
+ /**
+ * {@link ContentObserver}s for {@link Settings.Secure#ACCESSIBILITY_ENABLED}
+ * and {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} settings.
+ */
+ private void registerSettingsContentObservers() {
+ ContentResolver contentResolver = mContext.getContentResolver();
+
+ Uri enabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_ENABLED);
+ contentResolver.registerContentObserver(enabledUri, false,
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
+
+ synchronized (mLock) {
+ if (mIsEnabled) {
+ manageServicesLocked();
+ } else {
+ unbindAllServicesLocked();
+ }
+ updateClientsLocked();
+ }
+ }
+ });
+
+ Uri providersUri =
+ Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ contentResolver.registerContentObserver(providersUri, false,
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ synchronized (mLock) {
+ manageServicesLocked();
+ }
+ }
+ });
+ }
+
+ public void addClient(IAccessibilityManagerClient client) {
+ synchronized (mLock) {
+ try {
+ client.setEnabled(mIsEnabled);
+ mClients.add(client);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Dead AccessibilityManagerClient: " + client, re);
+ }
+ }
+ }
+
+ public boolean sendAccessibilityEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ notifyAccessibilityServicesDelayedLocked(event, false);
+ notifyAccessibilityServicesDelayedLocked(event, true);
+ }
+ // event not scheduled for dispatch => recycle
+ if (mHandledFeedbackTypes == 0) {
+ event.recycle();
+ } else {
+ mHandledFeedbackTypes = 0;
+ }
+
+ return (OWN_PROCESS_ID != Binder.getCallingPid());
+ }
+
+ public List<ServiceInfo> getAccessibilityServiceList() {
+ synchronized (mLock) {
+ return mInstalledServices;
+ }
+ }
+
+ public void interrupt() {
+ synchronized (mLock) {
+ for (int i = 0, count = mServices.size(); i < count; i++) {
+ Service service = mServices.get(i);
+ try {
+ service.mServiceInterface.onInterrupt();
+ } catch (RemoteException re) {
+ if (re instanceof DeadObjectException) {
+ Log.w(LOG_TAG, "Dead " + service.mService + ". Cleaning up.");
+ if (removeDeadServiceLocked(service)) {
+ count--;
+ i--;
+ }
+ } else {
+ Log.e(LOG_TAG, "Error during sending interrupt request to "
+ + service.mService, re);
+ }
+ }
+ }
+ }
+ }
+
+ public void executeMessage(Message message) {
+ switch (message.what) {
+ case DO_SET_SERVICE_INFO:
+ SomeArgs arguments = ((SomeArgs) message.obj);
+
+ AccessibilityServiceInfo info = (AccessibilityServiceInfo) arguments.arg1;
+ Service service = (Service) arguments.arg2;
+
+ synchronized (mLock) {
+ service.mEventTypes = info.eventTypes;
+ service.mFeedbackType = info.feedbackType;
+ String[] packageNames = info.packageNames;
+ if (packageNames != null) {
+ service.mPackageNames.addAll(Arrays.asList(packageNames));
+ }
+ service.mNotificationTimeout = info.notificationTimeout;
+ service.mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0;
+ }
+ return;
+ default:
+ Log.w(LOG_TAG, "Unknown message type: " + message.what);
+ }
+ }
+
+ /**
+ * Populates the cached list of installed {@link AccessibilityService}s.
+ */
+ private void populateAccessibilityServiceListLocked() {
+ mInstalledServices.clear();
+
+ List<ResolveInfo> installedServices = mPackageManager.queryIntentServices(
+ new Intent(AccessibilityService.SERVICE_INTERFACE), PackageManager.GET_SERVICES);
+
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ mInstalledServices.add(installedServices.get(i).serviceInfo);
+ }
+ }
+
+ /**
+ * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
+ * and denotes the period after the last event before notifying the service.
+ *
+ * @param event The event.
+ * @param isDefault True to notify default listeners, not default services.
+ */
+ private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
+ boolean isDefault) {
+ for (int i = 0, count = mServices.size(); i < count; i++) {
+ Service service = mServices.get(i);
+
+ if (service.mIsDefault == isDefault) {
+ if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) {
+ mHandledFeedbackTypes |= service.mFeedbackType;
+ notifyAccessibilityServiceDelayedLocked(service, event);
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs an {@link AccessibilityService} delayed notification. The delay is configurable
+ * and denotes the period after the last event before notifying the service.
+ *
+ * @param service The service.
+ * @param event The event.
+ */
+ private void notifyAccessibilityServiceDelayedLocked(Service service,
+ AccessibilityEvent event) {
+ synchronized (mLock) {
+ int eventType = event.getEventType();
+ AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
+ service.mPendingEvents.put(eventType, event);
+
+ int what = eventType | (service.mId << 16);
+ if (oldEvent != null) {
+ mHandler.removeMessages(what);
+ tryRecycleLocked(oldEvent);
+ }
+
+ Message message = mHandler.obtainMessage(what, service);
+ message.arg1 = event.getEventType();
+ mHandler.sendMessageDelayed(message, service.mNotificationTimeout);
+ }
+ }
+
+ /**
+ * Recycles an event if it can be safely recycled. The condition is that no
+ * not notified service is interested in the event.
+ *
+ * @param event The event.
+ */
+ private void tryRecycleLocked(AccessibilityEvent event) {
+ int eventType = event.getEventType();
+ List<Service> services = mServices;
+
+ // linear in the number of service which is not large
+ for (int i = 0, count = services.size(); i < count; i++) {
+ Service service = services.get(i);
+ if (service.mPendingEvents.get(eventType) == event) {
+ return;
+ }
+ }
+
+ event.recycle();
+ }
+
+ /**
+ * Notifies a service for a scheduled event given the event type.
+ *
+ * @param service The service.
+ * @param eventType The type of the event to dispatch.
+ */
+ private void notifyEventListenerLocked(Service service, int eventType) {
+ IEventListener listener = service.mServiceInterface;
+ AccessibilityEvent event = service.mPendingEvents.get(eventType);
+
+ try {
+ listener.onAccessibilityEvent(event);
+ if (LOGV) {
+ Log.i(LOG_TAG, "Event " + event + " sent to " + listener);
+ }
+ } catch (RemoteException re) {
+ if (re instanceof DeadObjectException) {
+ Log.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);
+ }
+ }
+ }
+
+ /**
+ * Removes a dead service.
+ *
+ * @param service The service.
+ * @return True if the service was removed, false otherwise.
+ */
+ private boolean removeDeadServiceLocked(Service service) {
+ mServices.remove(service);
+ mHandler.removeMessages(service.mId);
+
+ if (LOGV) {
+ Log.i(LOG_TAG, "Dead service " + service.mService + " removed");
+ }
+
+ if (mServices.isEmpty()) {
+ mIsEnabled = false;
+ updateClientsLocked();
+ }
+
+ return true;
+ }
+
+ /**
+ * Determines if given event can be dispatched to a service based on the package of the
+ * event source and already notified services for that event type. Specifically, a
+ * service is notified if it is interested in events from the package and no other service
+ * providing the same feedback type has been notified. Exception are services the
+ * provide generic feedback (feedback type left as a safety net for unforeseen feedback
+ * types) which are always notified.
+ *
+ * @param service The potential receiver.
+ * @param event The event.
+ * @param handledFeedbackTypes The feedback types for which services have been notified.
+ * @return True if the listener should be notified, false otherwise.
+ */
+ private boolean canDispathEventLocked(Service service, AccessibilityEvent event,
+ int handledFeedbackTypes) {
+
+ if (!service.isConfigured()) {
+ return false;
+ }
+
+ if (!service.mService.isBinderAlive()) {
+ removeDeadServiceLocked(service);
+ return false;
+ }
+
+ int eventType = event.getEventType();
+ if ((service.mEventTypes & eventType) != eventType) {
+ return false;
+ }
+
+ Set<String> packageNames = service.mPackageNames;
+ CharSequence packageName = event.getPackageName();
+
+ if (packageNames.isEmpty() || packageNames.contains(packageName)) {
+ int feedbackType = service.mFeedbackType;
+ if ((handledFeedbackTypes & feedbackType) != feedbackType
+ || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Manages services by starting enabled ones and stopping disabled ones.
+ */
+ private void manageServicesLocked() {
+ populateEnabledServicesLocked(mEnabledServices);
+ updateServicesStateLocked(mInstalledServices, mEnabledServices);
+ }
+
+ /**
+ * Unbinds all bound services.
+ */
+ private void unbindAllServicesLocked() {
+ List<Service> services = mServices;
+
+ for (int i = 0, count = services.size(); i < count; i++) {
+ Service service = services.get(i);
+
+ service.unbind();
+ mComponentNameToServiceMap.remove(service.mComponentName);
+ }
+ services.clear();
+ }
+
+ /**
+ * Populates a list with the {@link ComponentName}s of all enabled
+ * {@link AccessibilityService}s.
+ *
+ * @param enabledServices The list.
+ */
+ private void populateEnabledServicesLocked(Set<ComponentName> enabledServices) {
+ enabledServices.clear();
+
+ String servicesValue = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+
+ if (servicesValue != null) {
+ TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(servicesValue);
+ while (splitter.hasNext()) {
+ ComponentName enabledService = ComponentName.unflattenFromString(splitter.next());
+ enabledServices.add(enabledService);
+ }
+ }
+ }
+
+ /**
+ * Updates the state of each service by starting (or keeping running) enabled ones and
+ * stopping the rest.
+ *
+ * @param installedServices All installed {@link AccessibilityService}s.
+ * @param enabledServices The {@link ComponentName}s of the enabled services.
+ */
+ private void updateServicesStateLocked(List<ServiceInfo> installedServices,
+ Set<ComponentName> enabledServices) {
+
+ Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
+ List<Service> services = mServices;
+
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ ServiceInfo intalledService = installedServices.get(i);
+ ComponentName componentName = new ComponentName(intalledService.packageName,
+ intalledService.name);
+ Service service = componentNameToServiceMap.get(componentName);
+
+ if (enabledServices.contains(componentName)) {
+ if (service == null) {
+ new Service(componentName).bind();
+ }
+ } else {
+ if (service != null) {
+ service.unbind();
+ componentNameToServiceMap.remove(componentName);
+ services.remove(service);
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the state of {@link android.view.accessibility.AccessibilityManager} clients.
+ */
+ private void updateClientsLocked() {
+ for (int i = 0, count = mClients.size(); i < count; i++) {
+ try {
+ mClients.get(i).setEnabled(mIsEnabled);
+ } catch (RemoteException re) {
+ mClients.remove(i);
+ count--;
+ }
+ }
+ }
+
+ /**
+ * This class represents an accessibility service. It stores all per service
+ * data required for the service management, provides API for starting/stopping the
+ * service and is responsible for adding/removing the service in the data structures
+ * for service management. The class also exposes configuration interface that is
+ * passed to the service it represents as soon it is bound. It also serves as the
+ * connection for the service.
+ */
+ class Service extends IAccessibilityServiceConnection.Stub implements ServiceConnection {
+ int mId = 0;
+
+ IBinder mService;
+
+ IEventListener mServiceInterface;
+
+ int mEventTypes;
+
+ int mFeedbackType;
+
+ Set<String> mPackageNames = new HashSet<String>();
+
+ boolean mIsDefault;
+
+ long mNotificationTimeout;
+
+ boolean mIsActive;
+
+ ComponentName mComponentName;
+
+ Intent mIntent;
+
+ // the events pending events to be dispatched to this service
+ final SparseArray<AccessibilityEvent> mPendingEvents =
+ new SparseArray<AccessibilityEvent>();
+
+ Service(ComponentName componentName) {
+ mId = sIdCounter++;
+ mComponentName = componentName;
+ mIntent = new Intent().setComponent(mComponentName);
+ }
+
+ /**
+ * Binds to the accessibility service.
+ */
+ public void bind() {
+ if (mService == null) {
+ mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE);
+ }
+ }
+
+ /**
+ * Unbinds form the accessibility service and removes it from the data
+ * structures for service management.
+ */
+ public void unbind() {
+ if (mService != null) {
+ mContext.unbindService(this);
+ }
+ }
+
+ /**
+ * Returns if the service is configured i.e. at least event types of interest
+ * and feedback type must be set.
+ *
+ * @return True if the service is configured, false otherwise.
+ */
+ public boolean isConfigured() {
+ return (mEventTypes != 0 && mFeedbackType != 0);
+ }
+
+ public void setServiceInfo(AccessibilityServiceInfo info) {
+ mCaller.obtainMessageOO(DO_SET_SERVICE_INFO, info, this).sendToTarget();
+ }
+
+ public void onServiceConnected(ComponentName componentName, IBinder service) {
+ mService = service;
+ mServiceInterface = IEventListener.Stub.asInterface(service);
+
+ try {
+ mServiceInterface.setConnection(this);
+ synchronized (mLock) {
+ if (!mServices.contains(this)) {
+ mServices.add(this);
+ mComponentNameToServiceMap.put(componentName, this);
+ }
+ }
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName componentName) {
+ synchronized (mLock) {
+ Service service = mComponentNameToServiceMap.remove(componentName);
+ mServices.remove(service);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index c50ae94..131e156 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -29,7 +29,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.PackageItemInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.net.Uri;
@@ -40,6 +39,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -56,7 +56,6 @@ import java.util.HashSet;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.appwidget.IAppWidgetHost;
-import com.android.internal.util.XmlUtils;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -79,7 +78,7 @@ class AppWidgetService extends IAppWidgetService.Stub
static class Provider {
int uid;
AppWidgetProviderInfo info;
- ArrayList<AppWidgetId> instances = new ArrayList();
+ ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
@@ -90,7 +89,7 @@ class AppWidgetService extends IAppWidgetService.Stub
int uid;
int hostId;
String packageName;
- ArrayList<AppWidgetId> instances = new ArrayList();
+ ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
IAppWidgetHost callbacks;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
@@ -107,10 +106,10 @@ class AppWidgetService extends IAppWidgetService.Stub
Context mContext;
PackageManager mPackageManager;
AlarmManager mAlarmManager;
- ArrayList<Provider> mInstalledProviders = new ArrayList();
+ ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
- ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList();
- ArrayList<Host> mHosts = new ArrayList();
+ final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
+ ArrayList<Host> mHosts = new ArrayList<Host>();
boolean mSafeMode;
AppWidgetService(Context context) {
@@ -174,7 +173,7 @@ class AppWidgetService extends IAppWidgetService.Stub
for (int i=0; i<N; i++) {
AppWidgetId id = mAppWidgetIds.get(i);
pw.print(" ["); pw.print(i); pw.print("] id=");
- pw.println(id.appWidgetId);;
+ pw.println(id.appWidgetId);
pw.print(" hostId=");
pw.print(id.host.hostId); pw.print(' ');
pw.print(id.host.packageName); pw.print('/');
@@ -384,7 +383,7 @@ class AppWidgetService extends IAppWidgetService.Stub
public List<AppWidgetProviderInfo> getInstalledProviders() {
synchronized (mAppWidgetIds) {
final int N = mInstalledProviders.size();
- ArrayList<AppWidgetProviderInfo> result = new ArrayList(N);
+ ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
for (int i=0; i<N; i++) {
Provider p = mInstalledProviders.get(i);
if (!p.zombie) {
@@ -619,7 +618,6 @@ class AppWidgetService extends IAppWidgetService.Stub
// rely on the fact that we've already set it and that
// PendingIntent.getBroadcast will update the extras.
boolean alreadyRegistered = p.broadcast != null;
- int instancesSize = p.instances.size();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
intent.setComponent(p.info.provider);
@@ -695,10 +693,16 @@ class AppWidgetService extends IAppWidgetService.Stub
TypedArray sa = mContext.getResources().obtainAttributes(attrs,
com.android.internal.R.styleable.AppWidgetProviderInfo);
- info.minWidth = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth, 0);
- info.minHeight = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight, 0);
+
+ // These dimensions has to be resolved in the application's context.
+ // We simply send back the raw complex data, which will be
+ // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
+ TypedValue value = sa.peekValue(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
+ info.minWidth = value != null ? value.data : 0;
+ value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
+ info.minHeight = value != null ? value.data : 0;
+
info.updatePeriodMillis = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
info.initialLayout = sa.getResourceId(
@@ -773,10 +777,12 @@ class AppWidgetService extends IAppWidgetService.Stub
if (real.exists()) {
readStateFromFileLocked(real);
if (temp.exists()) {
+ //noinspection ResultOfMethodCallIgnored
temp.delete();
}
} else if (temp.exists()) {
readStateFromFileLocked(temp);
+ //noinspection ResultOfMethodCallIgnored
temp.renameTo(real);
}
}
@@ -792,18 +798,23 @@ class AppWidgetService extends IAppWidgetService.Stub
// use the temporary one until it's fully written, create an empty file
// for real, which will we'll shortly delete.
try {
+ //noinspection ResultOfMethodCallIgnored
real.createNewFile();
} catch (IOException e) {
+ // Ignore
}
}
if (temp.exists()) {
+ //noinspection ResultOfMethodCallIgnored
temp.delete();
}
writeStateToFileLocked(temp);
+ //noinspection ResultOfMethodCallIgnored
real.delete();
+ //noinspection ResultOfMethodCallIgnored
temp.renameTo(real);
}
@@ -866,8 +877,10 @@ class AppWidgetService extends IAppWidgetService.Stub
stream.close();
}
} catch (IOException ex) {
+ // Ignore
}
if (file.exists()) {
+ //noinspection ResultOfMethodCallIgnored
file.delete();
}
}
@@ -885,7 +898,7 @@ class AppWidgetService extends IAppWidgetService.Stub
int type;
int providerIndex = 0;
- HashMap<Integer,Provider> loadedProviders = new HashMap();
+ HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
do {
type = parser.next();
if (type == XmlPullParser.START_TAG) {
@@ -986,6 +999,7 @@ class AppWidgetService extends IAppWidgetService.Stub
stream.close();
}
} catch (IOException e) {
+ // Ignore
}
if (success) {
@@ -1081,7 +1095,7 @@ 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();
+ HashSet<String> keep = new HashSet<String>();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
@@ -1103,7 +1117,6 @@ class AppWidgetService extends IAppWidgetService.Stub
if (parsed != null) {
keep.add(ai.name);
// Use the new AppWidgetProviderInfo.
- AppWidgetProviderInfo oldInfo = p.info;
p.info = parsed.info;
// If it's enabled
final int M = p.instances.size();
diff --git a/services/java/com/android/server/AttributeCache.java b/services/java/com/android/server/AttributeCache.java
index 459ae52..81378dc 100644
--- a/services/java/com/android/server/AttributeCache.java
+++ b/services/java/com/android/server/AttributeCache.java
@@ -17,56 +17,36 @@
package com.android.server;
-import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.provider.Settings;
-import android.util.Config;
-import android.util.Log;
+import android.util.SparseArray;
+import java.util.HashMap;
import java.util.WeakHashMap;
-public final class AttributeCache extends BroadcastReceiver {
+/**
+ * TODO: This should be better integrated into the system so it doesn't need
+ * special calls from the activity manager to clear it.
+ */
+public final class AttributeCache {
private static AttributeCache sInstance = null;
private final Context mContext;
- private final WeakHashMap<Key, Entry> mMap =
- new WeakHashMap<Key, Entry>();
- private final WeakHashMap<String, Context> mContexts =
- new WeakHashMap<String, Context>();
+ private final WeakHashMap<String, Package> mPackages =
+ new WeakHashMap<String, Package>();
+ private final Configuration mConfiguration = new Configuration();
- final static class Key {
- public final String packageName;
- public final int resId;
- public final int[] styleable;
-
- public Key(String inPackageName, int inResId, int[] inStyleable) {
- packageName = inPackageName;
- resId = inResId;
- styleable = inStyleable;
- }
+ public final static class Package {
+ public final Context context;
+ private final SparseArray<HashMap<int[], Entry>> mMap
+ = new SparseArray<HashMap<int[], Entry>>();
- @Override public boolean equals(Object obj) {
- try {
- if (obj != null) {
- Key other = (Key)obj;
- return packageName.equals(other.packageName)
- && resId == other.resId
- && styleable == other.styleable;
- }
- } catch (ClassCastException e) {
- }
- return false;
- }
-
- @Override public int hashCode() {
- return packageName.hashCode() + resId;
+ public Package(Context c) {
+ context = c;
}
}
@@ -94,36 +74,68 @@ public final class AttributeCache extends BroadcastReceiver {
mContext = context;
}
- public Entry get(String packageName, int resId, int[] styleable) {
+ public void removePackage(String packageName) {
synchronized (this) {
- Key key = new Key(packageName, resId, styleable);
- Entry ent = mMap.get(key);
- if (ent != null) {
- return ent;
+ mPackages.remove(packageName);
+ }
+ }
+
+ public void updateConfiguration(Configuration config) {
+ synchronized (this) {
+ int changes = mConfiguration.updateFrom(config);
+ if ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE |
+ ActivityInfo.CONFIG_KEYBOARD_HIDDEN |
+ ActivityInfo.CONFIG_ORIENTATION)) != 0) {
+ // The configurations being masked out are ones that commonly
+ // change so we don't want flushing the cache... all others
+ // will flush the cache.
+ mPackages.clear();
}
- Context context = mContexts.get(packageName);
- if (context == null) {
+ }
+ }
+
+ public Entry get(String packageName, int resId, int[] styleable) {
+ synchronized (this) {
+ Package pkg = mPackages.get(packageName);
+ HashMap<int[], Entry> map = null;
+ Entry ent = null;
+ if (pkg != null) {
+ map = pkg.mMap.get(resId);
+ if (map != null) {
+ ent = map.get(styleable);
+ if (ent != null) {
+ return ent;
+ }
+ }
+ } else {
+ Context context;
try {
context = mContext.createPackageContext(packageName, 0);
if (context == null) {
return null;
}
- mContexts.put(packageName, context);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
+ pkg = new Package(context);
+ mPackages.put(packageName, pkg);
}
+
+ if (map == null) {
+ map = new HashMap<int[], Entry>();
+ pkg.mMap.put(resId, map);
+ }
+
try {
- ent = new Entry(context,
- context.obtainStyledAttributes(resId, styleable));
- mMap.put(key, ent);
+ ent = new Entry(pkg.context,
+ pkg.context.obtainStyledAttributes(resId, styleable));
+ map.put(styleable, ent);
} catch (Resources.NotFoundException e) {
return null;
}
+
return ent;
}
}
- @Override public void onReceive(Context context, Intent intent) {
- }
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 983329b..3b82284 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -16,18 +16,26 @@
package com.android.server;
-import android.backup.BackupService;
-import android.backup.IBackupService;
+import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IBackupAgent;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
import android.net.Uri;
+import android.provider.Settings;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -35,71 +43,212 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import android.backup.IBackupManager;
+import android.backup.IRestoreObserver;
+import android.backup.IRestoreSession;
+import android.backup.RestoreSet;
+import com.android.internal.backup.LocalTransport;
+import com.android.internal.backup.IBackupTransport;
+
+import com.android.server.PackageManagerBackupAgent;
+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.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;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
private static final boolean DEBUG = true;
-
- private static final long COLLECTION_INTERVAL = 1000;
- //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
+ // How often we perform a backup pass. Privileged external callers can
+ // trigger an immediate pass.
+ private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
+
+ // The amount of time between the initial provisioning of the device and
+ // the first backup pass.
+ private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
+
+ private static final String RUN_BACKUP_ACTION = "_backup_run_";
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;
+
+ // Timeout interval for deciding that a bind or clear-data has taken too long
+ static final long TIMEOUT_INTERVAL = 10 * 1000;
+
private Context mContext;
private PackageManager mPackageManager;
+ private IActivityManager mActivityManager;
+ private PowerManager mPowerManager;
+ private AlarmManager mAlarmManager;
+
+ private boolean mEnabled; // access to this is synchronized on 'this'
+ private boolean mProvisioned;
+ private PowerManager.WakeLock mWakelock;
private final BackupHandler mBackupHandler = new BackupHandler();
+ private PendingIntent mRunBackupIntent;
+ private BroadcastReceiver mRunBackupReceiver;
+ private IntentFilter mRunBackupFilter;
// map UIDs to the set of backup client services within that UID's app set
- private SparseArray<HashSet<ServiceInfo>> mBackupParticipants
- = new SparseArray<HashSet<ServiceInfo>>();
+ private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
+ = new SparseArray<HashSet<ApplicationInfo>>();
// set of backup services that have pending changes
private class BackupRequest {
- public ServiceInfo service;
+ public ApplicationInfo appInfo;
public boolean fullBackup;
-
- BackupRequest(ServiceInfo svc, boolean isFull) {
- service = svc;
+
+ BackupRequest(ApplicationInfo app, boolean isFull) {
+ appInfo = app;
fullBackup = isFull;
}
+
+ public String toString() {
+ return "BackupRequest{app=" + appInfo + " full=" + fullBackup + "}";
+ }
}
// Backups that we haven't started yet.
- private HashMap<ComponentName,BackupRequest> mPendingBackups = new HashMap();
- // Backups that we have started. These are separate to prevent starvation
- // if an app keeps re-enqueuing itself.
- private ArrayList<BackupRequest> mBackupQueue;
+ private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
+ = new HashMap<ApplicationInfo,BackupRequest>();
+
+ // Pseudoname that we use for the Package Manager metadata "package"
+ private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+
+ // locking around the pending-backup management
private final Object mQueueLock = new Object();
- private File mStateDir;
+ // The thread performing the sequence of queued backups binds to each app's agent
+ // in succession. Bind notifications are asynchronously delivered through the
+ // Activity Manager; use this lock object to signal when a requested binding has
+ // completed.
+ private final Object mAgentConnectLock = new Object();
+ private IBackupAgent mConnectedAgent;
+ private volatile boolean mConnecting;
+
+ // A similar synchronicity mechanism around clearing apps' data for restore
+ private final Object mClearDataLock = new Object();
+ private volatile boolean mClearingData;
+
+ // Transport bookkeeping
+ private final HashMap<String,IBackupTransport> mTransports
+ = new HashMap<String,IBackupTransport>();
+ private String mCurrentTransport;
+ private IBackupTransport mLocalTransport, mGoogleTransport;
+ private RestoreSession mActiveRestoreSession;
+
+ private class RestoreParams {
+ public IBackupTransport transport;
+ public IRestoreObserver observer;
+ public long token;
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ }
+ }
+
+ private class ClearParams {
+ public IBackupTransport transport;
+ public PackageInfo packageInfo;
+
+ ClearParams(IBackupTransport _transport, PackageInfo _info) {
+ transport = _transport;
+ packageInfo = _info;
+ }
+ }
+
+ // Where we keep our journal files and other bookkeeping
+ private File mBaseStateDir;
private File mDataDir;
-
+ private File mJournalDir;
+ private File mJournal;
+ private RandomAccessFile mJournalStream;
+
public BackupManagerService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
+ mActivityManager = ActivityManagerNative.getDefault();
+
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
// Set up our bookkeeping
- mStateDir = new File(Environment.getDataDirectory(), "backup");
- mStateDir.mkdirs();
+ boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.BACKUP_ENABLED, 0) != 0;
+ // !!! TODO: mProvisioned needs to default to 0, not 1.
+ mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.BACKUP_PROVISIONED, 1) != 0;
+ mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mDataDir = Environment.getDownloadCacheDirectory();
-
- // Build our mapping of uid to backup client services
+
+ mRunBackupReceiver = new RunBackupReceiver();
+ mRunBackupFilter = new IntentFilter();
+ mRunBackupFilter.addAction(RUN_BACKUP_ACTION);
+ context.registerReceiver(mRunBackupReceiver, mRunBackupFilter);
+
+ Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
+ // !!! TODO: restrict delivery to our receiver; the naive setClass() doesn't seem to work
+ //backupIntent.setClass(context, mRunBackupReceiver.getClass());
+ backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
+
+ // Set up the backup-request journaling
+ mJournalDir = new File(mBaseStateDir, "pending");
+ mJournalDir.mkdirs(); // creates mBaseStateDir along the way
+ makeJournalLocked(); // okay because no other threads are running yet
+
+ // Build our mapping of uid to backup client services. This implicitly
+ // schedules a backup pass on the Package Manager metadata the first
+ // time anything needs to be backed up.
synchronized (mBackupParticipants) {
addPackageParticipantsLocked(null);
}
+ // Set up our transport options and initialize the default transport
+ // TODO: Have transports register themselves somehow?
+ // TODO: Don't create transports that we don't need to?
+ mLocalTransport = new LocalTransport(context); // This is actually pretty cheap
+ ComponentName localName = new ComponentName(context, LocalTransport.class);
+ registerTransport(localName.flattenToShortString(), mLocalTransport);
+
+ mGoogleTransport = null;
+ mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT);
+ if ("".equals(mCurrentTransport)) {
+ mCurrentTransport = null;
+ }
+ if (DEBUG) Log.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);
+
+ // Now that we know about valid backup participants, parse any
+ // leftover journal files into the pending backup set
+ parseLeftoverJournals();
+
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter filter = new IntentFilter();
@@ -107,6 +256,77 @@ class BackupManagerService extends IBackupManager.Stub {
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
+
+ // Power management
+ mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
+
+ // Start the backup passes going
+ setBackupEnabled(areEnabled);
+ }
+
+ private class RunBackupReceiver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
+ if (DEBUG) Log.v(TAG, "Running a backup pass");
+
+ synchronized (mQueueLock) {
+ // acquire a wakelock and pass it to the backup thread. it will
+ // be released once backup concludes.
+ mWakelock.acquire();
+
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
+ mBackupHandler.sendMessage(msg);
+ }
+ }
+ }
+ }
+
+ private void makeJournalLocked() {
+ try {
+ mJournal = File.createTempFile("journal", null, mJournalDir);
+ mJournalStream = new RandomAccessFile(mJournal, "rwd");
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write backup journals");
+ mJournal = null;
+ mJournalStream = null;
+ }
+ }
+
+ private void parseLeftoverJournals() {
+ if (mJournal != null) {
+ File[] allJournals = mJournalDir.listFiles();
+ for (File f : allJournals) {
+ if (f.compareTo(mJournal) != 0) {
+ // This isn't the current journal, so it must be a leftover. Read
+ // out the package names mentioned there and schedule them for
+ // backup.
+ try {
+ Log.i(TAG, "Found stale backup journal, scheduling:");
+ RandomAccessFile in = new RandomAccessFile(f, "r");
+ while (true) {
+ String packageName = in.readUTF();
+ Log.i(TAG, " + " + packageName);
+ dataChanged(packageName);
+ }
+ } catch (EOFException e) {
+ // no more data; we're done
+ } catch (Exception e) {
+ // can't read it or other error; just skip it
+ } finally {
+ // close/delete the file
+ f.delete();
+ }
+ }
+ }
+ }
+ }
+
+ // Add a transport to our set of available backends
+ private void registerTransport(String name, IBackupTransport transport) {
+ synchronized (mTransports) {
+ if (DEBUG) Log.v(TAG, "Registering transport " + name + " = " + transport);
+ mTransports.put(name, transport);
+ }
}
// ----- Track installation/removal of packages -----
@@ -149,282 +369,1201 @@ 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");
+ mGoogleTransport = IBackupTransport.Stub.asInterface(service);
+ registerTransport(name.flattenToShortString(), mGoogleTransport);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.v(TAG, "Disconnected from Google transport");
+ mGoogleTransport = null;
+ registerTransport(name.flattenToShortString(), null);
+ }
+ };
+
// ----- Run the actual backup process asynchronously -----
- private class BackupHandler extends Handler implements ServiceConnection {
+ private class BackupHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RUN_BACKUP:
+ {
+ IBackupTransport transport = getTransport(mCurrentTransport);
+ if (transport == null) {
+ Log.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) {
- mBackupQueue = new ArrayList();
- for (BackupRequest b: mPendingBackups.values()) {
- mBackupQueue.add(b);
+ // 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
+ if (mJournalStream != null) {
+ try {
+ mJournalStream.close();
+ } catch (IOException e) {
+ // don't need to do anything
+ }
+ makeJournalLocked();
+ }
+
+ // 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");
+ mWakelock.release();
}
- mPendingBackups = new HashMap<ComponentName,BackupRequest>();
- // !!! TODO: start a new backup-queue journal file too
- // WARNING: If we crash after this line, anything in mPendingBackups will
- // be lost. FIX THIS.
}
- startOneService();
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;
+ }
+ }
}
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d(TAG, "onServiceConnected name=" + name + " service=" + service);
- IBackupService bs = IBackupService.Stub.asInterface(service);
- processOneBackup(name, bs);
+ }
+
+ // 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);
+ List<PackageInfo> targetApps = allAgentPackages();
+ addPackageParticipantsLockedInner(packageName, targetApps);
+ }
+
+ private void addPackageParticipantsLockedInner(String packageName,
+ List<PackageInfo> targetPkgs) {
+ if (DEBUG) {
+ Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
+ for (PackageInfo p : targetPkgs) {
+ Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
+ + " uid=" + p.applicationInfo.uid);
+ }
}
- public void onServiceDisconnected(ComponentName name) {
- // TODO: handle backup being interrupted
+ for (PackageInfo pkg : targetPkgs) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
+ HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
+ if (set == null) {
+ set = new HashSet<ApplicationInfo>();
+ mBackupParticipants.put(uid, set);
+ }
+ set.add(pkg.applicationInfo);
+ }
}
}
- void startOneService() {
- // Loop until we find someone to start or the queue empties out.
- Intent intent = new Intent(BackupService.SERVICE_ACTION);
- while (true) {
- BackupRequest request;
- synchronized (mQueueLock) {
- int queueSize = mBackupQueue.size();
- if (queueSize == 0) {
- mBackupQueue = null;
- // TODO: Anything else to do here?
- return;
+ // 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);
+ List<PackageInfo> allApps = null;
+ if (packageName != null) {
+ allApps = new ArrayList<PackageInfo>();
+ try {
+ int flags = PackageManager.GET_SIGNATURES;
+ allApps.add(mPackageManager.getPackageInfo(packageName, flags));
+ } catch (Exception e) {
+ // just skip it (???)
+ }
+ } else {
+ // all apps with agents
+ allApps = allAgentPackages();
+ }
+ removePackageParticipantsLockedInner(packageName, allApps);
+ }
+
+ private void removePackageParticipantsLockedInner(String packageName,
+ List<PackageInfo> agents) {
+ if (DEBUG) {
+ Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
+ + ") removing " + agents.size() + " entries");
+ for (PackageInfo p : agents) {
+ Log.v(TAG, " - " + p);
+ }
+ }
+ for (PackageInfo pkg : agents) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
+ HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
+ if (set != null) {
+ // Find the existing entry with the same package name, and remove it.
+ // We can't just remove(app) because the instances are different.
+ for (ApplicationInfo entry: set) {
+ if (entry.packageName.equals(pkg.packageName)) {
+ set.remove(entry);
+ break;
+ }
+ }
+ if (set.size() == 0) {
+ mBackupParticipants.delete(uid);
+ }
}
- request = mBackupQueue.get(0);
- // Take it off the queue when we're done.
}
-
- intent.setClassName(request.service.packageName, request.service.name);
- Log.d(TAG, "binding to " + intent);
+ }
+ }
+
+ // Returns the set of all applications that define an android:backupAgent attribute
+ private List<PackageInfo> allAgentPackages() {
+ // !!! TODO: cache this and regenerate only when necessary
+ int flags = PackageManager.GET_SIGNATURES;
+ List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+ int N = packages.size();
+ for (int a = N-1; a >= 0; a--) {
+ ApplicationInfo app = packages.get(a).applicationInfo;
+ if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+ || app.backupAgentName == null) {
+ packages.remove(a);
+ }
+ }
+ return packages;
+ }
+
+ // Reset the given package's known backup participants. Unlike add/remove, the update
+ // action cannot be passed a null package name.
+ void updatePackageParticipantsLocked(String packageName) {
+ if (packageName == null) {
+ Log.e(TAG, "updatePackageParticipants called with null package name");
+ return;
+ }
+ if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
+
+ // brute force but small code size
+ List<PackageInfo> allApps = allAgentPackages();
+ removePackageParticipantsLockedInner(packageName, allApps);
+ addPackageParticipantsLockedInner(packageName, allApps);
+ }
+
+ // 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);
+ }
+ return transport;
+ }
+ }
+
+ // fire off a backup agent, blocking until it attaches or times out
+ IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
+ IBackupAgent agent = null;
+ synchronized(mAgentConnectLock) {
+ mConnecting = true;
+ mConnectedAgent = null;
try {
- if (mContext.bindService(intent, mBackupHandler, Context.BIND_AUTO_CREATE)) {
- Log.d(TAG, "awaiting service object for " + intent);
- // success
- return;
+ if (mActivityManager.bindBackupAgent(app, mode)) {
+ Log.d(TAG, "awaiting agent for " + app);
+
+ // success; wait for the agent to arrive
+ // only wait 10 seconds for the clear data to happen
+ long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
+ while (mConnecting && mConnectedAgent == null
+ && (System.currentTimeMillis() < timeoutMark)) {
+ try {
+ mAgentConnectLock.wait(5000);
+ } catch (InterruptedException e) {
+ // just bail
+ return null;
+ }
+ }
+
+ // if we timed out with no connect, abort and move on
+ if (mConnecting == true) {
+ Log.w(TAG, "Timeout waiting for agent " + app);
+ return null;
+ }
+ agent = mConnectedAgent;
}
- } catch (SecurityException ex) {
- // Try for the next one.
- Log.d(TAG, "error in bind", ex);
+ } catch (RemoteException e) {
+ // can't happen
}
}
+ return agent;
}
- void processOneBackup(ComponentName name, IBackupService bs) {
+ // clear an application's data, blocking until the operation completes or times out
+ void clearApplicationDataSynchronous(String packageName) {
+ // Don't wipe packages marked allowClearUserData=false
try {
- Log.d(TAG, "processOneBackup doBackup() on " + name);
+ 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 "
+ + packageName);
+ return;
+ }
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Tried to clear data for " + packageName + " but not found");
+ return;
+ }
- BackupRequest request;
- synchronized (mQueueLock) {
- if (mBackupQueue == null) {
- Log.d(TAG, "mBackupQueue is null. WHY?");
+ ClearDataObserver observer = new ClearDataObserver();
+
+ synchronized(mClearDataLock) {
+ mClearingData = true;
+ mPackageManager.clearApplicationUserData(packageName, observer);
+
+ // only wait 10 seconds for the clear data to happen
+ long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
+ while (mClearingData && (System.currentTimeMillis() < timeoutMark)) {
+ try {
+ mClearDataLock.wait(5000);
+ } catch (InterruptedException e) {
+ // won't happen, but still.
+ mClearingData = false;
}
- request = mBackupQueue.get(0);
}
+ }
+ }
- // !!! TODO right now these naming schemes limit applications to
- // one backup service per package
- File savedStateName = new File(mStateDir, request.service.packageName);
- File backupDataName = new File(mDataDir, request.service.packageName + ".data");
- File newStateName = new File(mStateDir, request.service.packageName + ".new");
-
- // In a full backup, we pass a null ParcelFileDescriptor as
- // the saved-state "file"
- ParcelFileDescriptor savedState = (request.fullBackup) ? null
- : ParcelFileDescriptor.open(savedStateName,
- ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE);
+ class ClearDataObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(String packageName, boolean succeeded)
+ throws android.os.RemoteException {
+ synchronized(mClearDataLock) {
+ mClearingData = false;
+ mClearDataLock.notifyAll();
+ }
+ }
+ }
- backupDataName.delete();
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ // ----- Back up a set of applications via a worker thread -----
- newStateName.delete();
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ class PerformBackupThread extends Thread {
+ private static final String TAG = "PerformBackupThread";
+ IBackupTransport mTransport;
+ ArrayList<BackupRequest> mQueue;
+ File mStateDir;
+ File mJournal;
+
+ public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
+ File journal) {
+ mTransport = transport;
+ mQueue = queue;
+ mJournal = journal;
- // Run the target's backup pass
try {
- // TODO: Make this oneway
- bs.doBackup(savedState, backupData, newState);
- } finally {
- if (savedState != null) {
- savedState.close();
+ mStateDir = new File(mBaseStateDir, transport.transportDirName());
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+ mStateDir.mkdirs();
+ }
+
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
+
+ // Backups run at background priority
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+ // The package manager doesn't have a proper <application> etc, but since
+ // it's running here in the system process we can just set up its agent
+ // directly and use a synthetic BackupRequest. We always run this pass
+ // because it's cheap and this way we guarantee that we don't get out of
+ // step even if we're selecting among various transports at run time.
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentPackages());
+ BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+ pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneBackup(pmRequest,
+ IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+ mTransport);
+
+ // Now run all the backups in our queue
+ doQueuedBackups(mTransport);
+
+ // Finally, tear down the transport
+ try {
+ if (!mTransport.finishBackup()) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in finishBackup()");
}
- backupData.close();
- newState.close();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in finishBackup()", e);
}
- // !!! TODO: Now propagate the newly-backed-up data to the transport
-
- // !!! TODO: After successful transport, delete the now-stale data
- // and juggle the files so that next time the new state is passed
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
-
- } catch (FileNotFoundException fnf) {
- Log.d(TAG, "File not found on backup: ");
- fnf.printStackTrace();
- } catch (RemoteException e) {
- Log.d(TAG, "Remote target " + name + " threw during backup:");
- e.printStackTrace();
- } catch (Exception e) {
- Log.w(TAG, "Final exception guard in backup: ");
- e.printStackTrace();
+ if (!mJournal.delete()) {
+ Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
+ }
+
+ // Only once we're entirely finished do we release the wakelock
+ mWakelock.release();
}
- synchronized (mQueueLock) {
- mBackupQueue.remove(0);
+
+ private void doQueuedBackups(IBackupTransport transport) {
+ for (BackupRequest request : mQueue) {
+ Log.d(TAG, "starting agent for backup of " + request);
+
+ IBackupAgent agent = null;
+ int mode = (request.fullBackup)
+ ? IApplicationThread.BACKUP_MODE_FULL
+ : IApplicationThread.BACKUP_MODE_INCREMENTAL;
+ try {
+ agent = bindToAgentSynchronous(request.appInfo, mode);
+ if (agent != null) {
+ processOneBackup(request, agent, transport);
+ }
+
+ // unbind even on timeout, just in case
+ mActivityManager.unbindBackupAgent(request.appInfo);
+ } catch (SecurityException ex) {
+ // Try for the next one.
+ Log.d(TAG, "error in bind/backup", ex);
+ } catch (RemoteException e) {
+ Log.v(TAG, "bind/backup threw");
+ e.printStackTrace();
+ }
+
+ }
}
- mContext.unbindService(mBackupHandler);
- }
- // Add the backup services in the given package to our set of known backup participants.
- // If 'packageName' is null, adds all backup services in the system.
- void addPackageParticipantsLocked(String packageName) {
- List<ResolveInfo> services = mPackageManager.queryIntentServices(
- new Intent(BackupService.SERVICE_ACTION), 0);
- addPackageParticipantsLockedInner(packageName, services);
- }
+ void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) {
+ final String packageName = request.appInfo.packageName;
+ Log.d(TAG, "processOneBackup doBackup() on " + packageName);
- private void addPackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
- for (ResolveInfo ri : services) {
- if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
- int uid = ri.serviceInfo.applicationInfo.uid;
- HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
- if (set == null) {
- set = new HashSet<ServiceInfo>();
- mBackupParticipants.put(uid, set);
+ 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
+ // be unraveled.
+ PackageInfo packInfo;
+ if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ // The metadata 'package' is synthetic
+ packInfo = new PackageInfo();
+ packInfo.packageName = packageName;
+ } else {
+ packInfo = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_SIGNATURES);
}
- if (DEBUG) {
- Log.v(TAG, "Adding " + services.size() + " backup participants:");
- for (ResolveInfo svc : services) {
- Log.v(TAG, " " + svc + " : " + svc.filter);
+
+ // !!! TODO: get the state file dir from the transport
+ File savedStateName = new File(mStateDir, packageName);
+ File backupDataName = new File(mDataDir, packageName + ".data");
+ File newStateName = new File(mStateDir, packageName + ".new");
+
+ // In a full backup, we pass a null ParcelFileDescriptor as
+ // the saved-state "file"
+ ParcelFileDescriptor savedState = (request.fullBackup) ? null
+ : ParcelFileDescriptor.open(savedStateName,
+ ParcelFileDescriptor.MODE_READ_ONLY |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ backupDataName.delete();
+ ParcelFileDescriptor backupData =
+ ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ newStateName.delete();
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ // Run the target's backup pass
+ boolean success = false;
+ try {
+ agent.doBackup(savedState, backupData, newState);
+ success = true;
+ } finally {
+ if (savedState != null) {
+ savedState.close();
}
+ backupData.close();
+ newState.close();
}
- set.add(ri.serviceInfo);
+ // Now propagate the newly-backed-up data to the transport
+ if (success) {
+ if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
+ backupData =
+ ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
+ if (!transport.performBackup(packInfo, backupData)) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in performBackup()");
+ }
+
+ // !!! TODO: After successful transport, delete the now-stale data
+ // and juggle the files so that next time the new state is passed
+ //backupDataName.delete();
+ newStateName.renameTo(savedStateName);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error backing up " + packageName, e);
}
}
}
- // Remove the given package's backup services from our known active set. If
- // 'packageName' is null, *all* backup services will be removed.
- void removePackageParticipantsLocked(String packageName) {
- List<ResolveInfo> services = mPackageManager.queryIntentServices(
- new Intent(BackupService.SERVICE_ACTION), 0);
- removePackageParticipantsLockedInner(packageName, services);
+
+ // ----- Restore handling -----
+
+ private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
+ // Allow unsigned apps, but not signed on one device and unsigned on the other
+ // !!! TODO: is this the right policy?
+ if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ + " device=" + deviceSigs);
+ if ((storedSigs == null || storedSigs.length == 0)
+ && (deviceSigs == null || deviceSigs.length == 0)) {
+ return true;
+ }
+ if (storedSigs == null || deviceSigs == null) {
+ return false;
+ }
+
+ // !!! TODO: this demands that every stored signature match one
+ // that is present on device, and does not demand the converse.
+ // Is this this right policy?
+ int nStored = storedSigs.length;
+ int nDevice = deviceSigs.length;
+
+ for (int i=0; i < nStored; i++) {
+ boolean match = false;
+ for (int j=0; j < nDevice; j++) {
+ if (storedSigs[i].equals(deviceSigs[j])) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
+ }
+ }
+ return true;
}
- private void removePackageParticipantsLockedInner(String packageName,
- List<ResolveInfo> services) {
- for (ResolveInfo ri : services) {
- if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
- int uid = ri.serviceInfo.applicationInfo.uid;
- HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
- if (set != null) {
- set.remove(ri.serviceInfo);
- if (set.size() == 0) {
- mBackupParticipants.put(uid, null);
+ class PerformRestoreThread extends Thread {
+ private IBackupTransport mTransport;
+ private IRestoreObserver mObserver;
+ private long mToken;
+ private RestoreSet mImage;
+ private File mStateDir;
+
+ class RestoreRequest {
+ public PackageInfo app;
+ public int storedAppVersion;
+
+ RestoreRequest(PackageInfo _app, int _version) {
+ app = _app;
+ storedAppVersion = _version;
+ }
+ }
+
+ PerformRestoreThread(IBackupTransport transport, IRestoreObserver observer,
+ long restoreSetToken) {
+ mTransport = transport;
+ Log.d(TAG, "PerformRestoreThread mObserver=" + mObserver);
+ mObserver = observer;
+ mToken = restoreSetToken;
+
+ try {
+ mStateDir = new File(mBaseStateDir, transport.transportDirName());
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+ mStateDir.mkdirs();
+ }
+
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
+ + " mObserver=" + mObserver + " mToken=" + mToken);
+ /**
+ * Restore sequence:
+ *
+ * 1. get the restore set description for our identity
+ * 2. for each app in the restore set:
+ * 3.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
+ */
+
+ int error = -1; // assume error
+
+ // build the set of apps to restore
+ try {
+ RestoreSet[] images = mTransport.getAvailableRestoreSets();
+ if (images == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting restore sets");
+ return;
+ }
+
+ if (images.length == 0) {
+ Log.i(TAG, "No restore sets available");
+ return;
+ }
+
+ mImage = images[0];
+
+ // Get the list of all packages which have backup enabled.
+ // (Include the Package Manager metadata pseudo-package first.)
+ ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
+ PackageInfo omPackage = new PackageInfo();
+ omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+ restorePackages.add(omPackage);
+
+ List<PackageInfo> agentPackages = allAgentPackages();
+ restorePackages.addAll(agentPackages);
+
+ // let the observer know that we're running
+ if (mObserver != null) {
+ try {
+ // !!! TODO: get an actual count from the transport after
+ // its startRestore() runs?
+ mObserver.restoreStarting(restorePackages.size());
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died at restoreStarting");
+ mObserver = null;
+ }
+ }
+
+ if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error starting restore operation");
+ return;
+ }
+
+ String packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting first restore package");
+ return;
+ } else if (packageName.equals("")) {
+ Log.i(TAG, "No restore data available");
+ return;
+ } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ + "\", found only \"" + packageName + "\"");
+ return;
+ }
+
+ // Pull the Package Manager metadata from the restore set first
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, agentPackages);
+ processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
+ // Verify that the backup set includes metadata. If not, we can't do
+ // signature/version verification etc, so we simply do not proceed with
+ // the restore operation.
+ if (!pmAgent.hasMetadata()) {
+ Log.i(TAG, "No restore metadata available, so not restoring settings");
+ return;
+ }
+
+ int count = 0;
+ for (;;) {
+ packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting next restore package");
+ return;
+ } else if (packageName.equals("")) {
+ break;
+ }
+
+ if (mObserver != null) {
+ ++count;
+ try {
+ mObserver.onUpdate(count);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died in onUpdate");
+ mObserver = null;
+ }
+ }
+
+ Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
+ if (metaInfo == null) {
+ Log.e(TAG, "Missing metadata for " + packageName);
+ continue;
+ }
+
+ int flags = PackageManager.GET_SIGNATURES;
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ if (metaInfo.versionCode > packageInfo.versionCode) {
+ Log.w(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is too new for installed version ["
+ + packageInfo.versionCode + "]");
+ continue;
+ }
+
+ if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
+ Log.w(TAG, "Signature mismatch restoring " + packageName);
+ continue;
+ }
+
+ if (DEBUG) Log.v(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is compatible with installed version ["
+ + packageInfo.versionCode + "]");
+
+ // Now perform the actual restore
+ clearApplicationDataSynchronous(packageName);
+ IBackupAgent agent = bindToAgentSynchronous(
+ packageInfo.applicationInfo,
+ IApplicationThread.BACKUP_MODE_RESTORE);
+ if (agent == null) {
+ Log.w(TAG, "Can't find backup agent for " + packageName);
+ continue;
+ }
+
+ try {
+ processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ } finally {
+ // unbind even on timeout or failure, just in case
+ mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
}
}
+
+ // if we get this far, report success to the observer
+ error = 0;
+ } catch (NameNotFoundException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Invalid paackage restoring data", e);
+ } catch (RemoteException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error restoring data", e);
+ } finally {
+ try {
+ mTransport.finishRestore();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error finishing restore", e);
+ }
+
+ Log.d(TAG, "finishing restore mObserver=" + mObserver);
+
+ if (mObserver != null) {
+ try {
+ mObserver.restoreFinished(error);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Restore observer died at restoreFinished");
+ }
+ }
+
+ // done; we can finally release the wakelock
+ mWakelock.release();
+ }
+ }
+
+ // Do the guts of a restore of one application, using mTransport.getRestoreData().
+ void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
+ // !!! TODO: actually run the restore through mTransport
+ final String packageName = app.packageName;
+
+ Log.d(TAG, "processOneRestore packageName=" + packageName);
+
+ // !!! TODO: get the dirs from the transport
+ File backupDataName = new File(mDataDir, packageName + ".restore");
+ backupDataName.delete();
+ try {
+ ParcelFileDescriptor backupData =
+ ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ // Run the transport's restore pass
+ // Run the target's backup pass
+ try {
+ if (!mTransport.getRestoreData(backupData)) {
+ // STOPSHIP TODO: Handle this error somehow?
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ return;
+ }
+ } finally {
+ backupData.close();
+ }
+
+ // Okay, we have the data. Now have the agent do the restore.
+ File newStateName = new File(mStateDir, packageName + ".new");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE);
+
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ try {
+ agent.doRestore(backupData, appVersionCode, newState);
+ } finally {
+ newState.close();
+ backupData.close();
+ }
+
+ // if everything went okay, remember the recorded state now
+ File savedStateName = new File(mStateDir, packageName);
+ newStateName.renameTo(savedStateName);
+ } catch (Exception e) {
+ Log.e(TAG, "Error restoring data for " + packageName, e);
}
}
}
- // Reset the given package's known backup participants. Unlike add/remove, the update
- // action cannot be passed a null package name.
- void updatePackageParticipantsLocked(String packageName) {
- if (packageName == null) {
- Log.e(TAG, "updatePackageParticipants called with null package name");
- return;
+ class PerformClearThread extends Thread {
+ IBackupTransport mTransport;
+ PackageInfo mPackage;
+
+ PerformClearThread(IBackupTransport transport, PackageInfo packageInfo) {
+ mTransport = transport;
+ mPackage = packageInfo;
}
- // brute force but small code size
- List<ResolveInfo> services = mPackageManager.queryIntentServices(
- new Intent(BackupService.SERVICE_ACTION), 0);
- removePackageParticipantsLockedInner(packageName, services);
- addPackageParticipantsLockedInner(packageName, services);
+ @Override
+ public void run() {
+ try {
+ // Clear the on-device backup state to ensure a full backup next time
+ File stateDir = new File(mBaseStateDir, mTransport.transportDirName());
+ File stateFile = new File(stateDir, mPackage.packageName);
+ stateFile.delete();
+
+ // Tell the transport to remove all the persistent storage for the app
+ mTransport.clearBackupData(mPackage);
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ } finally {
+ try {
+ mTransport.finishBackup();
+ } catch (RemoteException e) {
+ // can't happen; the transport is local
+ }
+
+ // Last but not least, release the cpu
+ mWakelock.release();
+ }
+ }
}
+
// ----- IBackupManager binder interface -----
-
+
public void dataChanged(String packageName) throws RemoteException {
// 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.
- Log.d(TAG, "dataChanged packageName=" + packageName);
-
- HashSet<ServiceInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
- Log.d(TAG, "targets=" + targets);
+ // If the caller does not hold the BACKUP permission, it can only request a
+ // backup of its own data.
+ HashSet<ApplicationInfo> targets;
+ if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
+ Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ targets = mBackupParticipants.get(Binder.getCallingUid());
+ } else {
+ // a caller with full permission can ask to back up any participating app
+ // !!! TODO: allow backup of ANY app?
+ targets = new HashSet<ApplicationInfo>();
+ int N = mBackupParticipants.size();
+ for (int i = 0; i < N; i++) {
+ HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+ if (s != null) {
+ targets.addAll(s);
+ }
+ }
+ }
if (targets != null) {
synchronized (mQueueLock) {
// Note that this client has made data changes that need to be backed up
- for (ServiceInfo service : targets) {
+ for (ApplicationInfo app : targets) {
// validate the caller-supplied package name against the known set of
// packages associated with this uid
- if (service.packageName.equals(packageName)) {
+ if (app.packageName.equals(packageName)) {
// Add the caller to the set of pending backups. If there is
// one already there, then overwrite it, but no harm done.
- mPendingBackups.put(new ComponentName(service.packageName, service.name),
- new BackupRequest(service, true));
- // !!! TODO: write to the pending-backup journal file in case of crash
+ BackupRequest req = new BackupRequest(app, false);
+ if (mPendingBackups.put(app, req) == null) {
+ // Journal this request in case of crash. The put()
+ // operation returned null when this package was not already
+ // in the set; we want to avoid touching the disk redundantly.
+ writeToJournalLocked(packageName);
+
+ if (DEBUG) {
+ int numKeys = mPendingBackups.size();
+ Log.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
+ for (BackupRequest b : mPendingBackups.values()) {
+ Log.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
+ }
+ }
+ }
}
}
+ }
+ } else {
+ Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'");
+ }
+ }
+
+ private void writeToJournalLocked(String str) {
+ if (mJournalStream != null) {
+ try {
+ mJournalStream.writeUTF(str);
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing to backup journal");
+ mJournalStream = null;
+ mJournal = null;
+ }
+ }
+ }
+
+ // Clear the given package's backup data from the current transport
+ public void clearBackupData(String packageName) {
+ if (DEBUG) Log.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");
+ return;
+ }
+
+ // If the caller does not hold the BACKUP permission, it can only request a
+ // wipe of its own backed-up data.
+ HashSet<ApplicationInfo> apps;
+ if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
+ Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ apps = mBackupParticipants.get(Binder.getCallingUid());
+ } 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");
+ apps = new HashSet<ApplicationInfo>();
+ int N = mBackupParticipants.size();
+ for (int i = 0; i < N; i++) {
+ HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+ if (s != null) {
+ apps.addAll(s);
+ }
+ }
+ }
+
+ // 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");
+ // found it; fire off the clear request
+ synchronized (mQueueLock) {
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
+ new ClearParams(getTransport(mCurrentTransport), info));
+ mBackupHandler.sendMessage(msg);
+ }
+ break;
+ }
+ }
+ }
- Log.d(TAG, "Scheduling backup for " + mPendingBackups.size() + " participants");
- // Schedule a backup pass in a few minutes. As backup-eligible data
- // keeps changing, continue to defer the backup pass until things
- // settle down, to avoid extra overhead.
- mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
+ // Run a backup pass immediately for any applications that have declared
+ // that they have pending updates.
+ public void backupNow() throws RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "backupNow");
+
+ if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
+ synchronized (mQueueLock) {
+ try {
+ if (DEBUG) Log.v(TAG, "sending immediate backup broadcast");
+ mRunBackupIntent.send();
+ } catch (PendingIntent.CanceledException e) {
+ // should never happen
+ Log.e(TAG, "run-backup intent cancelled!");
}
}
}
- // Schedule a backup pass for a given package, even if the caller is not part of
- // that uid or package itself.
- public void scheduleFullBackup(String packageName) throws RemoteException {
- // !!! TODO: protect with a signature-or-system permission?
- HashSet<ServiceInfo> targets = new HashSet<ServiceInfo>();
+ // Enable/disable the backup service
+ public void setBackupEnabled(boolean enable) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "setBackupEnabled");
+
+ boolean wasEnabled = mEnabled;
+ synchronized (this) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_ENABLED, enable ? 1 : 0);
+ mEnabled = enable;
+ }
+
synchronized (mQueueLock) {
- int numKeys = mBackupParticipants.size();
- for (int index = 0; index < numKeys; index++) {
- int uid = mBackupParticipants.keyAt(index);
- HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
- for (ServiceInfo service: servicesAtUid) {
- if (service.packageName.equals(packageName)) {
- mPendingBackups.put(new ComponentName(service.packageName, service.name),
- new BackupRequest(service, true));
+ if (enable && !wasEnabled && mProvisioned) {
+ // if we've just been enabled, start scheduling backup passes
+ startBackupAlarmsLocked(BACKUP_INTERVAL);
+ } else if (!enable) {
+ // No longer enabled, so stop running backups
+ mAlarmManager.cancel(mRunBackupIntent);
+ }
+ }
+ }
+
+ // Mark the backup service as having been provisioned
+ public void setBackupProvisioned(boolean available) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "setBackupProvisioned");
+
+ boolean wasProvisioned = mProvisioned;
+ synchronized (this) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
+ mProvisioned = available;
+ }
+
+ synchronized (mQueueLock) {
+ if (available && !wasProvisioned && mEnabled) {
+ // we're now good to go, so start the backup alarms
+ startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+ } else if (!available) {
+ // No longer enabled, so stop running backups
+ Log.w(TAG, "Backup service no longer provisioned");
+ mAlarmManager.cancel(mRunBackupIntent);
+ }
+ }
+ }
+
+ private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
+ long when = System.currentTimeMillis() + delayBeforeFirstBackup;
+ mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
+ BACKUP_INTERVAL, mRunBackupIntent);
+ }
+
+ // Report whether the backup mechanism is currently enabled
+ public boolean isBackupEnabled() {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
+ return mEnabled; // no need to synchronize just to read it
+ }
+
+ // Report the name of the currently active transport
+ public String getCurrentTransport() {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ "getCurrentTransport");
+ Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
+ return mCurrentTransport;
+ }
+
+ // Report all known, available backup transports
+ public String[] listAllTransports() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
+
+ String[] list = null;
+ ArrayList<String> known = new ArrayList<String>();
+ for (Map.Entry<String, IBackupTransport> entry : mTransports.entrySet()) {
+ if (entry.getValue() != null) {
+ known.add(entry.getKey());
+ }
+ }
+
+ if (known.size() > 0) {
+ list = new String[known.size()];
+ known.toArray(list);
+ }
+ return list;
+ }
+
+ // Select which transport to use for the next backup operation. If the given
+ // name is not one of the available transports, no action is taken and the method
+ // returns null.
+ public String selectBackupTransport(String transport) {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
+
+ synchronized (mTransports) {
+ String prevTransport = null;
+ if (mTransports.get(transport) != null) {
+ prevTransport = mCurrentTransport;
+ mCurrentTransport = transport;
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT, transport);
+ Log.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ + " returning " + prevTransport);
+ } else {
+ Log.w(TAG, "Attempt to select unavailable transport " + transport);
+ }
+ return prevTransport;
+ }
+ }
+
+ // Callback: a requested backup agent has been instantiated. This should only
+ // be called from the Activity Manager.
+ public void agentConnected(String packageName, IBinder agentBinder) {
+ synchronized(mAgentConnectLock) {
+ if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ Log.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()
+ + " claiming agent connected");
+ }
+ mAgentConnectLock.notifyAll();
+ }
+ }
+
+ // Callback: a backup agent has failed to come up, or has unexpectedly quit.
+ // If the agent failed to come up in the first place, the agentBinder argument
+ // will be null. This should only be called from the Activity Manager.
+ public void agentDisconnected(String packageName) {
+ // TODO: handle backup being interrupted
+ synchronized(mAgentConnectLock) {
+ if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ mConnectedAgent = null;
+ mConnecting = false;
+ } else {
+ Log.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+ + " claiming agent disconnected");
+ }
+ mAgentConnectLock.notifyAll();
+ }
+ }
+
+ // Hand off a restore session
+ public IRestoreSession beginRestoreSession(String transport) {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
+
+ synchronized(this) {
+ if (mActiveRestoreSession != null) {
+ Log.d(TAG, "Restore session requested but one already active");
+ return null;
+ }
+ mActiveRestoreSession = new RestoreSession(transport);
+ }
+ return mActiveRestoreSession;
+ }
+
+ // ----- Restore session -----
+
+ class RestoreSession extends IRestoreSession.Stub {
+ private static final String TAG = "RestoreSession";
+
+ private IBackupTransport mRestoreTransport = null;
+ RestoreSet[] mRestoreSets = null;
+
+ RestoreSession(String transport) {
+ mRestoreTransport = getTransport(transport);
+ }
+
+ // --- Binder interface ---
+ public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ "getAvailableRestoreSets");
+
+ try {
+ synchronized(this) {
+ if (mRestoreSets == null) {
+ mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
+ }
+ return mRestoreSets;
+ }
+ } catch (RuntimeException e) {
+ Log.d(TAG, "getAvailableRestoreSets exception");
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ public int performRestore(long token, IRestoreObserver observer)
+ throws android.os.RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "performRestore");
+
+ Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
+
+ if (mRestoreSets != null) {
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token);
+ mBackupHandler.sendMessage(msg);
+ return 0;
}
}
+ } else {
+ if (DEBUG) Log.v(TAG, "No current restore set, not doing restore");
+ }
+ return -1;
+ }
+
+ public void endRestoreSession() throws android.os.RemoteException {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ "endRestoreSession");
+
+ Log.d(TAG, "endRestoreSession");
+
+ mRestoreTransport.finishRestore();
+ mRestoreTransport = null;
+ synchronized(BackupManagerService.this) {
+ if (BackupManagerService.this.mActiveRestoreSession == this) {
+ BackupManagerService.this.mActiveRestoreSession = null;
+ } else {
+ Log.e(TAG, "ending non-current restore session");
+ }
}
}
}
-
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
+ long oldId = Binder.clearCallingIdentity();
+
+ pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ + " / " + (!mProvisioned ? "not " : "") + "provisioned");
+ pw.println("Available transports:");
+ for (String t : listAllTransports()) {
+ String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
+ pw.println(pad + t);
+ }
int N = mBackupParticipants.size();
- pw.println("Participants:");
+ pw.println("Participants: " + N);
for (int i=0; i<N; i++) {
int uid = mBackupParticipants.keyAt(i);
pw.print(" uid: ");
pw.println(uid);
- HashSet<ServiceInfo> services = mBackupParticipants.valueAt(i);
- for (ServiceInfo s: services) {
- pw.print(" ");
- pw.println(s.toString());
+ HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
+ for (ApplicationInfo app: participants) {
+ pw.println(" " + app.toString());
}
}
+ pw.println("Pending: " + mPendingBackups.size());
+ for (BackupRequest req : mPendingBackups.values()) {
+ pw.println(" " + req);
+ }
+
+ Binder.restoreCallingIdentity(oldId);
}
}
}
diff --git a/services/java/com/android/server/EntropyService.java b/services/java/com/android/server/EntropyService.java
new file mode 100644
index 0000000..28f09f5
--- /dev/null
+++ b/services/java/com/android/server/EntropyService.java
@@ -0,0 +1,148 @@
+/*
+ * 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.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import android.os.Binder;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * A service designed to load and periodically save &quot;randomness&quot;
+ * for the Linux kernel.
+ *
+ * <p>When a Linux system starts up, the entropy pool associated with
+ * {@code /dev/random} may be in a fairly predictable state. Applications which
+ * depend strongly on randomness may find {@code /dev/random} or
+ * {@code /dev/urandom} returning predictable data. In order to counteract
+ * this effect, it's helpful to carry the entropy pool information across
+ * shutdowns and startups.
+ *
+ * <p>This class was modeled after the script in
+ * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man
+ * 4 random</a>.
+ *
+ * <p>TODO: Investigate attempting to write entropy data at shutdown time
+ * 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();
+
+ /**
+ * Handler that periodically updates the entropy on disk.
+ */
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what != ENTROPY_WHAT) {
+ Log.e(TAG, "Will not process invalid message");
+ return;
+ }
+ writeEntropy();
+ scheduleEntropyWriter();
+ }
+ };
+
+ public EntropyService() {
+ loadInitialEntropy();
+ addDeviceSpecificEntropy();
+ writeEntropy();
+ scheduleEntropyWriter();
+ }
+
+ private void scheduleEntropyWriter() {
+ mHandler.removeMessages(ENTROPY_WHAT);
+ mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
+ }
+
+ private void loadInitialEntropy() {
+ try {
+ RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
+ } catch (IOException e) {
+ Log.w(TAG, "unable to load initial entropy (first boot?)", e);
+ }
+ }
+
+ private void writeEntropy() {
+ try {
+ RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
+ } catch (IOException e) {
+ Log.w(TAG, "unable to write entropy", e);
+ }
+ }
+
+ /**
+ * Add additional information to the kernel entropy pool. The
+ * information isn't necessarily "random", but that's ok. Even
+ * sending non-random information to {@code /dev/urandom} is useful
+ * because, while it doesn't increase the "quality" of the entropy pool,
+ * it mixes more bits into the pool, which gives us a higher degree
+ * of uncertainty in the generated randomness. Like nature, writes to
+ * the random device can only cause the quality of the entropy in the
+ * kernel to stay the same or increase.
+ *
+ * <p>For maximum effect, we try to target information which varies
+ * on a per-device basis, and is not easily observable to an
+ * attacker.
+ */
+ private void addDeviceSpecificEntropy() {
+ PrintWriter out = null;
+ try {
+ out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
+ out.println("Copyright (C) 2009 The Android Open Source Project");
+ out.println("All Your Randomness Are Belong To Us");
+ out.println(START_TIME);
+ out.println(START_NANOTIME);
+ out.println(SystemProperties.get("ro.serialno"));
+ out.println(SystemProperties.get("ro.bootmode"));
+ out.println(SystemProperties.get("ro.baseband"));
+ out.println(SystemProperties.get("ro.carrier"));
+ out.println(SystemProperties.get("ro.bootloader"));
+ out.println(SystemProperties.get("ro.hardware"));
+ out.println(SystemProperties.get("ro.revision"));
+ 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);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+ private static String getSystemDir() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ systemDir.mkdirs();
+ return systemDir.toString();
+ }
+}
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 3fc1e0e..9b0a2d4 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -35,6 +35,7 @@ import java.io.FileNotFoundException;
*/
class HeadsetObserver extends UEventObserver {
private static final String TAG = HeadsetObserver.class.getSimpleName();
+ private static final boolean LOG = false;
private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w";
private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
@@ -61,7 +62,7 @@ class HeadsetObserver extends UEventObserver {
@Override
public void onUEvent(UEventObserver.UEvent event) {
- Log.v(TAG, "Headset UEVENT: " + event.toString());
+ if (LOG) Log.v(TAG, "Headset UEVENT: " + event.toString());
try {
update(event.get("SWITCH_NAME"), Integer.parseInt(event.get("SWITCH_STATE")));
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 72efca5..d8c8c90 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -163,8 +163,24 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
return Collections.unmodifiableSet(mFilters);
}
- public List<R> queryIntent(ContentResolver resolver, Intent intent,
- String resolvedType, boolean defaultOnly) {
+ public List<R> queryIntentFromList(Intent intent, String resolvedType,
+ boolean defaultOnly, ArrayList<ArrayList<F>> listCut) {
+ ArrayList<R> resultList = new ArrayList<R>();
+
+ final boolean debug = localLOGV ||
+ ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
+
+ final String scheme = intent.getScheme();
+ int N = listCut.size();
+ for (int i = 0; i < N; ++i) {
+ buildResolveList(intent, debug, defaultOnly,
+ resolvedType, scheme, listCut.get(i), resultList);
+ }
+ sortResults(resultList);
+ return resultList;
+ }
+
+ public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
String scheme = intent.getScheme();
ArrayList<R> finalList = new ArrayList<R>();
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 05888e0..fab97b1 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -46,7 +46,6 @@ import android.location.Address;
import android.location.IGeocodeProvider;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
-import android.location.ILocationCollector;
import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.ILocationProvider;
@@ -66,15 +65,12 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
-import android.util.Config;
import android.util.Log;
import android.util.PrintWriterPrinter;
-import android.util.SparseIntArray;
import com.android.internal.location.GpsLocationProvider;
import com.android.internal.location.LocationProviderProxy;
import com.android.internal.location.MockProvider;
-import com.android.server.am.BatteryStatsService;
/**
* The service class that manages LocationProviders and issues location
@@ -107,8 +103,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
private static final String INSTALL_LOCATION_PROVIDER =
android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
- private static final String INSTALL_LOCATION_COLLECTOR =
- android.Manifest.permission.INSTALL_LOCATION_COLLECTOR;
// Set of providers that are explicitly enabled
private final Set<String> mEnabledProviders = new HashSet<String>();
@@ -171,9 +165,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private HashMap<String,Location> mLastKnownLocation =
new HashMap<String,Location>();
- // Location collector
- private ILocationCollector mCollector;
-
private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
// for Settings change notification
@@ -516,6 +507,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private void removeProvider(LocationProviderProxy provider) {
mProviders.remove(provider);
+ provider.unlinkProvider();
mProvidersByName.remove(provider.getName());
}
@@ -630,16 +622,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- public void installLocationCollector(ILocationCollector collector) {
- if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_COLLECTOR)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires INSTALL_LOCATION_COLLECTOR permission");
- }
-
- // FIXME - only support one collector
- mCollector = collector;
- }
-
public void installGeocodeProvider(IGeocodeProvider provider) {
if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
!= PackageManager.PERMISSION_GRANTED) {
@@ -666,14 +648,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private void checkPermissionsSafe(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider)
- && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
}
if (LocationManager.NETWORK_PROVIDER.equals(provider)
- && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
- && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException(
"Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
@@ -682,14 +664,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private boolean isAllowedProviderSafe(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider)
- && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
return false;
}
if (LocationManager.NETWORK_PROVIDER.equals(provider)
- && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
- && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
+ && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
return false;
}
@@ -788,8 +770,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
if (deadReceivers == null) {
deadReceivers = new ArrayList<Receiver>();
- deadReceivers.add(record.mReceiver);
}
+ deadReceivers.add(record.mReceiver);
}
listeners++;
}
@@ -1093,7 +1075,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (mGpsStatusProvider == null) {
return false;
}
- if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
+ if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
}
@@ -1121,7 +1103,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// first check for permission to the provider
checkPermissionsSafe(provider);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
- if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
+ if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
}
@@ -1619,23 +1601,19 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (mLock) {
Location location = (Location) msg.obj;
+ String provider = location.getProvider();
- if (mCollector != null &&
- LocationManager.GPS_PROVIDER.equals(location.getProvider())) {
- try {
- mCollector.updateLocation(location);
- } catch (RemoteException e) {
- Log.w(TAG, "mCollector.updateLocation failed");
- mCollector = null;
+ // 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);
}
}
- String provider = location.getProvider();
- if (!isAllowedBySettingsLocked(provider)) {
- return;
+ if (isAllowedBySettingsLocked(provider)) {
+ handleLocationChangedLocked(location);
}
-
- handleLocationChangedLocked(location);
}
}
} catch (Exception e) {
@@ -1935,7 +1913,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (mLock) {
pw.println("Current Location Manager state:");
pw.println(" sProvidersLoaded=" + sProvidersLoaded);
- pw.println(" mCollector=" + mCollector);
pw.println(" Listeners:");
int N = mReceivers.size();
for (int i=0; i<N; i++) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 6ed8b4c..854138c 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -16,47 +16,52 @@
package com.android.server;
+import com.android.server.status.IconData;
+import com.android.server.status.NotificationData;
+import com.android.server.status.StatusBarService;
+
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
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.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.media.AudioManager;
+import android.database.ContentObserver;
import android.media.AsyncPlayer;
-import android.media.RingtoneManager;
+import android.media.AudioManager;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Binder;
-import android.os.RemoteException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Power;
+import android.os.RemoteException;
import android.os.Vibrator;
import android.provider.Settings;
-import android.util.Config;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-import com.android.server.status.IconData;
-import com.android.server.status.NotificationData;
-import com.android.server.status.StatusBarService;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.io.IOException;
class NotificationManagerService extends INotificationManager.Stub
{
@@ -88,6 +93,12 @@ class NotificationManagerService extends INotificationManager.Stub
private NotificationRecord mVibrateNotification;
private Vibrator mVibrator = new Vibrator();
+ // adb
+ private int mBatteryPlugged;
+ private boolean mAdbEnabled = false;
+ private boolean mAdbNotificationShown = false;
+ private Notification mAdbNotification;
+
private ArrayList<NotificationRecord> mNotificationList;
private ArrayList<ToastRecord> mToastQueue;
@@ -98,7 +109,7 @@ class NotificationManagerService extends INotificationManager.Stub
private boolean mBatteryLow;
private boolean mBatteryFull;
private NotificationRecord mLedNotification;
-
+
private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on
private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00; // Charging - orange solid on
private static final int BATTERY_FULL_ARGB = 0xFF00FF00; // Charging Full - green solid on
@@ -297,6 +308,9 @@ class NotificationManagerService extends INotificationManager.Stub
mBatteryFull = batteryFull;
updateLights();
}
+
+ mBatteryPlugged = intent.getIntExtra("plugged", 0);
+ updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Uri uri = intent.getData();
@@ -312,6 +326,31 @@ class NotificationManagerService extends INotificationManager.Stub
}
};
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ADB_ENABLED), false, this);
+ update();
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ update();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mAdbEnabled = Settings.Secure.getInt(resolver,
+ Settings.Secure.ADB_ENABLED, 0) != 0;
+ updateAdbNotification();
+ }
+ }
+ private final SettingsObserver mSettingsObserver;
+
NotificationManagerService(Context context, StatusBarService statusBar,
HardwareService hardware)
{
@@ -333,6 +372,9 @@ class NotificationManagerService extends INotificationManager.Stub
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(mIntentReceiver, filter);
+
+ mSettingsObserver = new SettingsObserver(mHandler);
+ mSettingsObserver.observe();
}
// Toasts
@@ -594,6 +636,9 @@ class NotificationManagerService extends INotificationManager.Stub
Binder.restoreCallingIdentity(identity);
}
}
+
+ sendAccessibilityEventTypeNotificationChangedDoCheck(notification, pkg);
+
} else {
if (old != null && old.statusBarKey != null) {
long identity = Binder.clearCallingIdentity();
@@ -676,6 +721,26 @@ class NotificationManagerService extends INotificationManager.Stub
idOut[0] = id;
}
+ private void sendAccessibilityEventTypeNotificationChangedDoCheck(Notification notification,
+ CharSequence packageName) {
+ AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+ if (!manager.isEnabled()) {
+ return;
+ }
+
+ AccessibilityEvent event =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+ event.setPackageName(packageName);
+ event.setClassName(Notification.class.getName());
+ event.setParcelableData(notification);
+ CharSequence tickerText = notification.tickerText;
+ if (!TextUtils.isEmpty(tickerText)) {
+ event.getText().add(tickerText);
+ }
+
+ manager.sendAccessibilityEvent(event);
+ }
+
private void cancelNotificationLocked(NotificationRecord r) {
// status bar
if (r.notification.icon != 0) {
@@ -869,6 +934,62 @@ class NotificationManagerService extends INotificationManager.Stub
return -1;
}
+ // This is here instead of StatusBarPolicy because it is an important
+ // security feature that we don't want people customizing the platform
+ // to accidentally lose.
+ private void updateAdbNotification() {
+ if (mAdbEnabled && mBatteryPlugged == BatteryManager.BATTERY_PLUGGED_USB) {
+ if (!mAdbNotificationShown) {
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.adb_active_notification_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.adb_active_notification_message);
+
+ if (mAdbNotification == null) {
+ mAdbNotification = new Notification();
+ mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
+ mAdbNotification.when = 0;
+ mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ mAdbNotification.tickerText = title;
+ mAdbNotification.defaults |= Notification.DEFAULT_SOUND;
+ }
+
+ Intent intent = new Intent(
+ Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ // Note: we are hard-coding the component because this is
+ // an important security UI that we don't want anyone
+ // intercepting.
+ intent.setComponent(new ComponentName("com.android.settings",
+ "com.android.settings.DevelopmentSettings"));
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+ 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);
+ if (notificationManager != null) {
+ mAdbNotificationShown = false;
+ notificationManager.cancel(
+ com.android.internal.R.string.adb_active_notification_title);
+ }
+ }
+ }
+
// ======================================================================
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
new file mode 100644
index 0000000..786f423
--- /dev/null
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -0,0 +1,413 @@
+/*
+ * 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.app.BackupAgent;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataOutput;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * We back up the signatures of each package so that during a system restore,
+ * we can verify that the app whose data we think we have matches the app
+ * actually resident on the device.
+ *
+ * Since the Package Manager isn't a proper "application" we just provide a
+ * direct IBackupAgent implementation and hand-construct it at need.
+ */
+public class PackageManagerBackupAgent extends BackupAgent {
+ private static final String TAG = "PMBA";
+ private static final boolean DEBUG = true;
+
+ // key under which we store global metadata (individual app metadata
+ // is stored using the package name as a key)
+ private static final String GLOBAL_METADATA_KEY = "@meta@";
+
+ private List<PackageInfo> mAllPackages;
+ private PackageManager mPackageManager;
+ // version & signature info of each app in a restore set
+ private HashMap<String, Metadata> mRestoredSignatures;
+ // The version info of each backed-up app as read from the state file
+ private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>();
+
+ private final HashSet<String> mExisting = new HashSet<String>();
+ private int mStoredSdkVersion;
+ private String mStoredIncrementalVersion;
+ private boolean mHasMetadata;
+
+ public class Metadata {
+ public int versionCode;
+ public Signature[] signatures;
+
+ Metadata(int version, Signature[] sigs) {
+ versionCode = version;
+ signatures = sigs;
+ }
+ }
+
+ // We're constructed with the set of applications that are participating
+ // in backup. This set changes as apps are installed & removed.
+ PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
+ mPackageManager = packageMgr;
+ mAllPackages = packages;
+ mRestoredSignatures = null;
+ mHasMetadata = false;
+ }
+
+ public boolean hasMetadata() {
+ return mHasMetadata;
+ }
+
+ public Metadata getRestoredMetadata(String packageName) {
+ if (mRestoredSignatures == null) {
+ Log.w(TAG, "getRestoredMetadata() before metadata read!");
+ return null;
+ }
+
+ return mRestoredSignatures.get(packageName);
+ }
+
+ // 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()");
+
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
+ DataOutputStream outWriter = new DataOutputStream(bufStream);
+ parseStateFile(oldState);
+
+ // If the stored version string differs, we need to re-backup all
+ // of the metadata. We force this by removing everything from the
+ // "already backed up" map built by parseStateFile().
+ if (mStoredIncrementalVersion == null
+ || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) {
+ Log.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
+ + Build.VERSION.INCREMENTAL + " - rewriting");
+ mExisting.clear();
+ }
+
+ try {
+ /*
+ * Global metadata:
+ *
+ * int SDKversion -- the SDK version of the OS itself on the device
+ * that produced this backup set. Used to reject
+ * backups from later OSes onto earlier ones.
+ * String incremental -- the incremental release name of the OS stored in
+ * 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);
+ } else {
+ if (DEBUG) Log.v(TAG, "Global metadata key already stored");
+ // don't consider it to have been skipped/deleted
+ mExisting.remove(GLOBAL_METADATA_KEY);
+ }
+
+ // For each app we have on device, see if we've backed it up yet. If not,
+ // write its signature block to the output, keyed on the package name.
+ for (PackageInfo pkg : mAllPackages) {
+ String packName = pkg.packageName;
+ if (packName.equals(GLOBAL_METADATA_KEY)) {
+ // We've already handled the metadata key; skip it here
+ continue;
+ } else {
+ PackageInfo info = null;
+ try {
+ info = mPackageManager.getPackageInfo(packName,
+ PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ // Weird; we just found it, and now are told it doesn't exist.
+ // Treat it as having been removed from the device.
+ mExisting.add(packName);
+ 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
+ // 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 (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);
+
+ // !!! TODO: take out this debugging
+ 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);
+ }
+ }
+ }
+
+ // At this point, the only entries in 'existing' are apps that were
+ // 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) {
+ // !!! TODO: take out this msg
+ if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
+ try {
+ data.writeEntityHeader(app, -1);
+ } catch (IOException e) {
+ Log.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!");
+ return;
+ }
+
+ // Finally, write the new state blob -- just the list of all apps we handled
+ writeStateFile(mAllPackages, newState);
+ }
+
+ // "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
+ // image. We'll use those later to determine what we can legitimately restore.
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
+ HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
+ if (DEBUG) Log.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);
+
+ // 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);
+
+ if (key.equals(GLOBAL_METADATA_KEY)) {
+ int storedSdkVersion = in.readInt();
+ if (DEBUG) Log.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");
+ return;
+ }
+ mStoredSdkVersion = storedSdkVersion;
+ mStoredIncrementalVersion = in.readUTF();
+ mHasMetadata = true;
+ // !!! TODO: remove this debugging output
+ if (DEBUG) {
+ Log.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);
+// !!! TODO: take out this debugging
+ if (DEBUG) {
+ Log.i(TAG, " restored metadata for " + key
+ + " dataSize=" + dataSize
+ + " versionCode=" + versionCode + " sigs=" + sigs);
+ }
+
+ ApplicationInfo app = new ApplicationInfo();
+ app.packageName = key;
+ restoredApps.add(app);
+ sigMap.put(key, new Metadata(versionCode, sigs));
+ }
+ }
+
+ // On successful completion, cache the signature map for the Backup Manager to use
+ 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;
+ }
+
+ return outBuf.toByteArray();
+ }
+
+ private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
+ Signature[] sigs = null;
+
+ try {
+ int num = in.readInt();
+ Log.v(TAG, " ... unflatten read " + num);
+ 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");
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to unflatten sigs");
+ return null;
+ }
+
+ return sigs;
+ }
+
+ // Util: parse out an existing state file into a usable structure
+ private void parseStateFile(ParcelFileDescriptor stateFile) {
+ mExisting.clear();
+ mStateVersions.clear();
+ mStoredSdkVersion = 0;
+ mStoredIncrementalVersion = null;
+
+ // The state file is just the list of app names we have stored signatures for
+ // with the exception of the metadata block, to which is also appended the
+ // version numbers corresponding with the last time we wrote this PM block.
+ // If they mismatch the current system, we'll re-store the metadata key.
+ FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
+ DataInputStream in = new DataInputStream(instream);
+
+ int bufSize = 256;
+ byte[] buf = new byte[bufSize];
+ try {
+ String pkg = in.readUTF();
+ if (pkg.equals(GLOBAL_METADATA_KEY)) {
+ mStoredSdkVersion = in.readInt();
+ mStoredIncrementalVersion = in.readUTF();
+ mExisting.add(GLOBAL_METADATA_KEY);
+ } else {
+ Log.e(TAG, "No global metadata in state file!");
+ return;
+ }
+
+ // The global metadata was first; now read all the apps
+ while (true) {
+ pkg = in.readUTF();
+ int versionCode = in.readInt();
+ mExisting.add(pkg);
+ mStateVersions.put(pkg, new Metadata(versionCode, null));
+ }
+ } catch (EOFException eof) {
+ // safe; we're done
+ } catch (IOException e) {
+ // whoops, bad state file. abort.
+ Log.e(TAG, "Unable to read Package Manager state file: " + e);
+ }
+ }
+
+ // Util: write out our new backup state file
+ private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
+ FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+
+ try {
+ // by the time we get here we know we've stored the global metadata record
+ out.writeUTF(GLOBAL_METADATA_KEY);
+ out.writeInt(Build.VERSION.SDK_INT);
+ out.writeUTF(Build.VERSION.INCREMENTAL);
+
+ // now write all the app names too
+ for (PackageInfo pkg : pkgs) {
+ out.writeUTF(pkg.packageName);
+ out.writeInt(pkg.versionCode);
+ }
+ } catch (IOException e) {
+ Log.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 079f363..06435c8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -26,13 +26,12 @@ import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
@@ -57,6 +56,8 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -147,6 +148,7 @@ class PackageManagerService extends IPackageManager.Stub {
final Context mContext;
final boolean mFactoryTest;
+ final boolean mNoDexOpt;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
@@ -258,6 +260,7 @@ class PackageManagerService extends IPackageManager.Stub {
final ResolveInfo mResolveInfo = new ResolveInfo();
ComponentName mResolveComponentName;
PackageParser.Package mPlatformPackage;
+ private boolean mCompatibilityModeEnabled = true;
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
@@ -297,6 +300,7 @@ class PackageManagerService extends IPackageManager.Stub {
mContext = context;
mFactoryTest = factoryTest;
+ mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings();
mSettings.addSharedUserLP("android.uid.system",
@@ -366,6 +370,10 @@ class PackageManagerService extends IPackageManager.Stub {
startTime);
int scanMode = SCAN_MONITOR;
+ if (mNoDexOpt) {
+ Log.w(TAG, "Running ENG build: no pre-dexopt!");
+ scanMode |= SCAN_NO_DEX;
+ }
final HashSet<String> libFiles = new HashSet<String>();
@@ -508,7 +516,7 @@ class PackageManagerService extends IPackageManager.Stub {
} // synchronized (mPackages)
} // synchronized (mInstallLock)
}
-
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -884,7 +892,11 @@ class PackageManagerService extends IPackageManager.Stub {
+ ": " + p);
if (p != null) {
// Note: isEnabledLP() does not apply here - always return info
- return PackageParser.generateApplicationInfo(p, flags);
+ ApplicationInfo appInfo = PackageParser.generateApplicationInfo(p, flags);
+ if (!mCompatibilityModeEnabled) {
+ appInfo.disableCompatibilityMode();
+ }
+ return appInfo;
}
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
@@ -922,7 +934,7 @@ class PackageManagerService extends IPackageManager.Stub {
});
}
- public void freeStorage(final long freeStorageSize, final PendingIntent opFinishedIntent) {
+ public void freeStorage(final long freeStorageSize, final IntentSender pi) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
// Queue up an async operation since clearing cache may take a little while.
@@ -936,11 +948,13 @@ class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Couldn't clear application caches");
}
}
- if(opFinishedIntent != null) {
+ if(pi != null) {
try {
// Callback via pending intent
- opFinishedIntent.send((retCode >= 0) ? 1 : 0);
- } catch (CanceledException e1) {
+ int code = (retCode >= 0) ? 1 : 0;
+ pi.sendIntent(null, code, null,
+ null, null);
+ } catch (SendIntentException e1) {
Log.i(TAG, "Failed to send pending intent");
}
}
@@ -951,8 +965,8 @@ class PackageManagerService extends IPackageManager.Stub {
public ActivityInfo getActivityInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
- if (Config.LOGV) Log.v(
- TAG, "getActivityInfo " + component + ": " + a);
+
+ if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledLP(a.info, flags)) {
return PackageParser.generateActivityInfo(a, flags);
}
@@ -1203,6 +1217,11 @@ class PackageManagerService extends IPackageManager.Stub {
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags) {
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
+ return chooseBestActivity(intent, resolvedType, flags, query);
+ }
+
+ private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
+ int flags, List<ResolveInfo> query) {
if (query != null) {
final int N = query.size();
if (N == 1) {
@@ -1243,8 +1262,7 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
List<PreferredActivity> prefs =
- mSettings.mPreferredActivities.queryIntent(null,
- intent, resolvedType,
+ mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
if (prefs != null && prefs.size() > 0) {
// First figure out how good the original match set is.
@@ -1320,8 +1338,17 @@ class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
- return (List<ResolveInfo>)mActivities.
- queryIntent(null, intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mActivities.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.activities);
+ }
+ return null;
}
}
@@ -1488,9 +1515,30 @@ class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags) {
+ ComponentName comp = intent.getComponent();
+ if (comp != null) {
+ List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ ActivityInfo ai = getReceiverInfo(comp, flags);
+ if (ai != null) {
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ list.add(ri);
+ }
+ return list;
+ }
+
synchronized (mPackages) {
- return (List<ResolveInfo>)mReceivers.
- queryIntent(null, intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mReceivers.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.receivers);
+ }
+ return null;
}
}
@@ -1523,8 +1571,17 @@ class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
- return (List<ResolveInfo>)mServices.
- queryIntent(null, intent, resolvedType, flags);
+ String pkgName = intent.getPackage();
+ if (pkgName == null) {
+ return (List<ResolveInfo>)mServices.queryIntent(intent,
+ resolvedType, flags);
+ }
+ PackageParser.Package pkg = mPackages.get(pkgName);
+ if (pkg != null) {
+ return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
+ resolvedType, flags, pkg.services);
+ }
+ return null;
}
}
@@ -1837,7 +1894,56 @@ class PackageManagerService extends IPackageManager.Stub {
}
return true;
}
+
+ public boolean performDexOpt(String packageName) {
+ if (!mNoDexOpt) {
+ return false;
+ }
+ PackageParser.Package p;
+ synchronized (mPackages) {
+ p = mPackages.get(packageName);
+ if (p == null || p.mDidDexOpt) {
+ return false;
+ }
+ }
+ synchronized (mInstallLock) {
+ 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) {
+ String path = pkg.mScanPath;
+ int ret = 0;
+ try {
+ if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
+ ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
+ !pkg.mForwardLocked);
+ pkg.mDidDexOpt = true;
+ performed = true;
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Apk not found for dexopt: " + path);
+ ret = -1;
+ } catch (IOException e) {
+ Log.w(TAG, "Exception reading apk: " + path, e);
+ ret = -1;
+ }
+ if (ret < 0) {
+ //error from installer
+ 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) {
@@ -2126,37 +2232,18 @@ class PackageManagerService extends IPackageManager.Stub {
String path = scanFile.getPath();
if (scanFileNewer) {
Log.i(TAG, path + " changed; unpacking");
- try {
- cachePackageSharedLibsLI(pkg, dataPath, scanFile);
- } catch (IOException e) {
- Log.e(TAG, "Failure extracting shared libs", e);
- if(mInstaller != null) {
- mInstaller.remove(pkgName);
- } else {
- dataPath.delete();
- }
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ int err = cachePackageSharedLibsLI(pkg, dataPath, scanFile);
+ if (err != PackageManager.INSTALL_SUCCEEDED) {
+ mLastScanError = err;
return null;
}
}
- if ((scanMode&SCAN_NO_DEX) == 0
- && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- int ret = 0;
- try {
- if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
- ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
- (scanMode&SCAN_FORWARD_LOCKED) == 0);
- }
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Apk not found for dexopt: " + path);
- ret = -1;
- } catch (IOException e) {
- Log.w(TAG, "Exception reading apk: " + path, e);
- ret = -1;
- }
- if (ret < 0) {
- //error from installer
+ 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;
return null;
}
@@ -2419,14 +2506,15 @@ class PackageManagerService extends IPackageManager.Stub {
return pkg;
}
- private void cachePackageSharedLibsLI(PackageParser.Package pkg,
- File dataPath, File scanFile) throws IOException {
+ private int cachePackageSharedLibsLI(PackageParser.Package pkg,
+ File dataPath, File scanFile) {
File sharedLibraryDir = new File(dataPath.getPath() + "/lib");
- final String sharedLibraryABI = "armeabi";
+ final String sharedLibraryABI = Build.CPU_ABI;
final String apkLibraryDirectory = "lib/" + sharedLibraryABI + "/";
final String apkSharedLibraryPrefix = apkLibraryDirectory + "lib";
final String sharedLibrarySuffix = ".so";
- boolean createdSharedLib = false;
+ boolean hasNativeCode = false;
+ boolean installedNativeCode = false;
try {
ZipFile zipFile = new ZipFile(scanFile);
Enumeration<ZipEntry> entries =
@@ -2435,9 +2523,15 @@ class PackageManagerService extends IPackageManager.Stub {
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.isDirectory()) {
+ if (!hasNativeCode && entry.getName().startsWith("lib")) {
+ hasNativeCode = true;
+ }
continue;
}
String entryName = entry.getName();
+ if (entryName.startsWith("lib/")) {
+ hasNativeCode = true;
+ }
if (! (entryName.startsWith(apkSharedLibraryPrefix)
&& entryName.endsWith(sharedLibrarySuffix))) {
continue;
@@ -2448,6 +2542,9 @@ class PackageManagerService extends IPackageManager.Stub {
|| (!FileUtils.isFilenameSafe(new File(libFileName)))) {
continue;
}
+
+ installedNativeCode = true;
+
String sharedLibraryFilePath = sharedLibraryDir.getPath() +
File.separator + libFileName;
File sharedLibraryFile = new File(sharedLibraryFilePath);
@@ -2459,19 +2556,23 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (mInstaller == null) {
sharedLibraryDir.mkdir();
- createdSharedLib = true;
}
cacheSharedLibLI(pkg, zipFile, entry, sharedLibraryDir,
sharedLibraryFile);
}
}
} catch (IOException e) {
- Log.e(TAG, "Failed to cache package shared libs", e);
- if(createdSharedLib) {
- sharedLibraryDir.delete();
- }
- throw e;
+ Log.w(TAG, "Failed to cache package shared libs", e);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
+
+ if (hasNativeCode && !installedNativeCode) {
+ Log.w(TAG, "Install failed: .apk has native code but none for arch "
+ + Build.CPU_ABI);
+ return PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
+ }
+
+ return PackageManager.INSTALL_SUCCEEDED;
}
private void cacheSharedLibLI(PackageParser.Package pkg,
@@ -2801,6 +2902,21 @@ class PackageManagerService extends IPackageManager.Stub {
// we can't add any new permissions to it.
if (!gp.loadedPermissions.contains(perm)) {
allowed = false;
+ // Except... if this is a permission that was added
+ // to the platform (note: need to only do this when
+ // updating the platform).
+ final int NP = PackageParser.NEW_PERMISSIONS.length;
+ for (int ip=0; ip<NP; ip++) {
+ final PackageParser.NewPermissionInfo npi
+ = PackageParser.NEW_PERMISSIONS[ip];
+ if (npi.name.equals(perm)
+ && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+ allowed = true;
+ Log.i(TAG, "Auto-granting WRITE_EXTERNAL_STORAGE to old pkg "
+ + pkg.packageName);
+ break;
+ }
+ }
}
}
if (allowed) {
@@ -2839,20 +2955,38 @@ class PackageManagerService extends IPackageManager.Stub {
private final class ActivityIntentResolver
extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
- public List queryIntent(ContentResolver resolver, Intent intent,
- String resolvedType, boolean defaultOnly) {
+ public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(resolver, intent, resolvedType, defaultOnly);
+ return super.queryIntent(intent, resolvedType, defaultOnly);
}
- public List queryIntent(ContentResolver resolver, Intent intent,
- String resolvedType, int flags) {
+ public List queryIntent(Intent intent, String resolvedType, int flags) {
mFlags = flags;
- return super.queryIntent(
- resolver, intent, resolvedType,
+ return super.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
}
+ public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
+ ArrayList<PackageParser.Activity> packageActivities) {
+ if (packageActivities == null) {
+ return null;
+ }
+ mFlags = flags;
+ final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
+ int N = packageActivities.size();
+ ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
+ new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
+
+ ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
+ for (int i = 0; i < N; ++i) {
+ intentFilters = packageActivities.get(i).intents;
+ if (intentFilters != null && intentFilters.size() > 0) {
+ listCut.add(intentFilters);
+ }
+ }
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+ }
+
public final void addActivity(PackageParser.Activity a, String type) {
mActivities.put(a.component, a);
if (SHOW_INFO || Config.LOGV) Log.v(
@@ -2860,8 +2994,7 @@ class PackageManagerService extends IPackageManager.Stub {
(a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
int NI = a.intents.size();
- int j;
- for (j=0; j<NI; j++) {
+ for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
if (SHOW_INFO || Config.LOGV) {
Log.v(TAG, " IntentFilter:");
@@ -2881,8 +3014,7 @@ class PackageManagerService extends IPackageManager.Stub {
(a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
int NI = a.intents.size();
- int j;
- for (j=0; j<NI; j++) {
+ for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
if (SHOW_INFO || Config.LOGV) {
Log.v(TAG, " IntentFilter:");
@@ -2969,20 +3101,38 @@ class PackageManagerService extends IPackageManager.Stub {
private final class ServiceIntentResolver
extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
- public List queryIntent(ContentResolver resolver, Intent intent,
- String resolvedType, boolean defaultOnly) {
+ public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
- return super.queryIntent(resolver, intent, resolvedType, defaultOnly);
+ return super.queryIntent(intent, resolvedType, defaultOnly);
}
- public List queryIntent(ContentResolver resolver, Intent intent,
- String resolvedType, int flags) {
+ public List queryIntent(Intent intent, String resolvedType, int flags) {
mFlags = flags;
- return super.queryIntent(
- resolver, intent, resolvedType,
+ return super.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
}
+ public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
+ ArrayList<PackageParser.Service> packageServices) {
+ if (packageServices == null) {
+ return null;
+ }
+ mFlags = flags;
+ final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
+ int N = packageServices.size();
+ ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
+ new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
+
+ ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
+ for (int i = 0; i < N; ++i) {
+ intentFilters = packageServices.get(i).intents;
+ if (intentFilters != null && intentFilters.size() > 0) {
+ listCut.add(intentFilters);
+ }
+ }
+ return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+ }
+
public final void addService(PackageParser.Service s) {
mServices.put(s.component, s);
if (SHOW_INFO || Config.LOGV) Log.v(
@@ -3142,6 +3292,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (extras != null) {
intent.putExtras(extras);
}
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
am.broadcastIntent(
null, intent,
null, null, 0, null, null, null, false, false);
@@ -3545,7 +3696,9 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
// Re installation failed. Restore old information
// Remove new pkg information
- removePackageLI(newPackage, true);
+ if (newPackage != null) {
+ removePackageLI(newPackage, true);
+ }
// Add back the old system package
scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
oldPkgSetting.resourcePath,
@@ -4084,6 +4237,7 @@ class PackageManagerService extends IPackageManager.Stub {
return false;
}
synchronized (mPackages) {
+ grantPermissionsLP(newPkg, true);
mSettings.writeLP();
}
return true;
@@ -4445,6 +4599,42 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ 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.");
+ }
+ if (filter.countCategories() != 1) {
+ throw new IllegalArgumentException(
+ "replacePreferredActivity expects filter to have only 1 category.");
+ }
+ if (filter.countDataAuthorities() != 0
+ || filter.countDataPaths() != 0
+ || filter.countDataSchemes() != 0
+ || filter.countDataTypes() != 0) {
+ throw new IllegalArgumentException(
+ "replacePreferredActivity expects filter to have no data authorities, " +
+ "paths, schemes or types.");
+ }
+ synchronized (mPackages) {
+ Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
+ String action = filter.getAction(0);
+ String category = filter.getCategory(0);
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
+ it.remove();
+ Log.i(TAG, "Removed preferred activity " + pa.mActivity + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
+ }
+ addPreferredActivity(filter, match, set, activity);
+ }
+ }
+
public void clearPackagePreferredActivities(String packageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -4609,6 +4799,14 @@ class PackageManagerService extends IPackageManager.Stub {
public void systemReady() {
mSystemReady = true;
+
+ // Read the compatibilty setting when the system is ready.
+ mCompatibilityModeEnabled = android.provider.Settings.System.getInt(
+ mContext.getContentResolver(),
+ android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
+ if (DEBUG_SETTINGS) {
+ Log.d(TAG, "compatibility mode:" + mCompatibilityModeEnabled);
+ }
}
public boolean isSafeMode() {
@@ -5607,24 +5805,15 @@ class PackageManagerService extends IPackageManager.Stub {
// Check to see if its a disabled system app
PackageSetting ps = mDisabledSysPackages.get(name);
if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
- // Could be a replaced system package
- // Note that if the user replaced a system app, the user has to physically
- // delete the new one in order to revert to the system app. So even
- // if the user updated the system app via an update, the user still
- // has to delete the one installed in the data partition in order to pick up the
- // new system package.
+ // This is an updated system app with versions in both system
+ // and data partition. Just let the most recent version
+ // take precedence.
return p;
- } else if ((p.pkg != null) && (p.pkg.applicationInfo != null) &&
- ((p.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
- // Check for non-system apps
+ } else if ((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ // Let the app continue with previous uid if code path changes.
reportSettingsProblem(Log.WARN,
"Package " + name + " codePath changed from " + p.codePath
+ " to " + codePath + "; Retaining data and using new code");
- } else {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " codePath changed from " + p.codePath
- + " to " + codePath + "; replacing with new");
- p = null;
}
} else if (p.sharedUser != sharedUser) {
reportSettingsProblem(Log.WARN,
@@ -5709,7 +5898,7 @@ class PackageManagerService extends IPackageManager.Stub {
continue;
}
for (PackageSetting pkg:sus.packages) {
- if (pkg.grantedPermissions.contains (eachPerm)) {
+ if (pkg.pkg.requestedPermissions.contains(eachPerm)) {
used = true;
break;
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index c5ea5fa..79d78ad 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -709,7 +709,10 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
p.awakeOnSet = true;
}
} else {
- mPokeLocks.remove(token);
+ PokeLock rLock = mPokeLocks.remove(token);
+ if (rLock != null) {
+ token.unlinkToDeath(rLock, 0);
+ }
}
int oldPokey = mPokey;
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index 55adabb..58f8980 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -54,7 +54,10 @@ public class ProcessStats {
PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
};
+ /** Stores user time and system time in 100ths of a second. */
private final long[] mProcessStatsData = new long[2];
+ /** Stores user time and system time in 100ths of a second. */
+ private final long[] mSinglePidStatsData = new long[2];
private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
PROC_SPACE_TERM,
@@ -418,7 +421,18 @@ public class ProcessStats {
return pids;
}
-
+
+ public long getCpuTimeForPid(int pid) {
+ final String statFile = "/proc/" + pid + "/stat";
+ final long[] statsData = mSinglePidStatsData;
+ if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
+ null, statsData, null)) {
+ long time = statsData[0] + statsData[1];
+ return time;
+ }
+ return 0;
+ }
+
final public int getLastUserTime() {
return mRelUserTime;
}
diff --git a/services/java/com/android/server/RandomBlock.java b/services/java/com/android/server/RandomBlock.java
new file mode 100644
index 0000000..4ac1c6e
--- /dev/null
+++ b/services/java/com/android/server/RandomBlock.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util.Log;
+
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+
+/**
+ * A 4k block of random {@code byte}s.
+ */
+class RandomBlock {
+
+ private static final String TAG = "RandomBlock";
+ private static final int BLOCK_SIZE = 4096;
+ private byte[] block = new byte[BLOCK_SIZE];
+
+ private RandomBlock() { }
+
+ static RandomBlock fromFile(String filename) throws IOException {
+ Log.v(TAG, "reading from file " + filename);
+ InputStream stream = null;
+ try {
+ stream = new FileInputStream(filename);
+ return fromStream(stream);
+ } finally {
+ close(stream);
+ }
+ }
+
+ private static RandomBlock fromStream(InputStream in) throws IOException {
+ RandomBlock retval = new RandomBlock();
+ int total = 0;
+ while(total < BLOCK_SIZE) {
+ int result = in.read(retval.block, total, BLOCK_SIZE - total);
+ if (result == -1) {
+ throw new EOFException();
+ }
+ total += result;
+ }
+ return retval;
+ }
+
+ void toFile(String filename) throws IOException {
+ Log.v(TAG, "writing to file " + filename);
+ RandomAccessFile out = null;
+ try {
+ out = new RandomAccessFile(filename, "rws");
+ toDataOut(out);
+ truncateIfPossible(out);
+ } finally {
+ close(out);
+ }
+ }
+
+ private static void truncateIfPossible(RandomAccessFile f) {
+ try {
+ f.setLength(BLOCK_SIZE);
+ } catch (IOException e) {
+ // ignore this exception. Sometimes, the file we're trying to
+ // write is a character device, such as /dev/urandom, and
+ // these character devices do not support setting the length.
+ }
+ }
+
+ private void toDataOut(DataOutput out) throws IOException {
+ out.write(block);
+ }
+
+ private static void close(Closeable c) {
+ try {
+ if (c == null) {
+ return;
+ }
+ c.close();
+ } catch (IOException e) {
+ Log.w(TAG, "IOException thrown while closing Closeable", e);
+ }
+ }
+}
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index b253038..ceef39f 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -19,7 +19,7 @@ package com.android.server;
import android.content.Context;
import android.hardware.ISensorService;
import android.os.Binder;
-import android.os.ParcelFileDescriptor;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.util.Config;
@@ -101,7 +101,7 @@ class SensorService extends ISensorService.Stub {
_sensors_control_init();
}
- public ParcelFileDescriptor getDataChanel() throws RemoteException {
+ public Bundle getDataChannel() throws RemoteException {
return _sensors_control_open();
}
@@ -190,7 +190,7 @@ class SensorService extends ISensorService.Stub {
ArrayList<Listener> mListeners = new ArrayList<Listener>();
private static native int _sensors_control_init();
- private static native ParcelFileDescriptor _sensors_control_open();
+ private static native Bundle _sensors_control_open();
private static native boolean _sensors_control_activate(int sensor, boolean activate);
private static native int _sensors_control_set_delay(int ms);
private static native int _sensors_control_wake();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8b7260b..3e4d5f9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,6 +97,9 @@ class ServerThread extends Thread {
// Critical services...
try {
+ Log.i(TAG, "Starting Entropy Service.");
+ ServiceManager.addService("entropy", new EntropyService());
+
Log.i(TAG, "Starting Power Manager.");
power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);
@@ -228,6 +231,14 @@ class ServerThread extends Thread {
}
try {
+ Log.i(TAG, "Starting Accessibility Manager.");
+ ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
+ new AccessibilityManagerService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Accessibility Manager", e);
+ }
+
+ try {
Log.i(TAG, "Starting Notification Manager.");
ServiceManager.addService(Context.NOTIFICATION_SERVICE,
new NotificationManagerService(context, statusBar, hardware));
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index fa54421..9f2856c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -26,6 +26,7 @@ import android.os.RemoteException;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -39,48 +40,71 @@ import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.DefaultPhoneNotifier;
import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyIntents;
import com.android.server.am.BatteryStatsService;
-
/**
- * Since phone process can be restarted, this class provides a centralized
- * place that applications can register and be called back from.
+ * Since phone process can be restarted, this class provides a centralized place
+ * that applications can register and be called back from.
*/
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
private static class Record {
String pkgForDebug;
+
IBinder binder;
+
IPhoneStateListener callback;
+
int events;
}
private final Context mContext;
+
private final ArrayList<Record> mRecords = new ArrayList();
+
private final IBatteryStats mBatteryStats;
private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+
private String mCallIncomingNumber = "";
+
private ServiceState mServiceState = new ServiceState();
- private int mSignalStrength = -1;
+
+ private SignalStrength mSignalStrength = new SignalStrength();
+
private boolean mMessageWaiting = false;
+
private boolean mCallForwarding = false;
+
private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+
private int mDataConnectionState = TelephonyManager.DATA_CONNECTED;
+
private boolean mDataConnectionPossible = false;
+
private String mDataConnectionReason = "";
+
private String mDataConnectionApn = "";
+
private String mDataConnectionInterfaceName = "";
+
private Bundle mCellLocation = new Bundle();
- // we keep a copy of all of the sate so we can send it out when folks register for it
+ static final int PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
+ PhoneStateListener.LISTEN_CALL_STATE |
+ PhoneStateListener.LISTEN_DATA_ACTIVITY |
+ PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
+ PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+
+ // we keep a copy of all of the state so we can send it out when folks
+ // register for it
//
- // In these calls we call with the lock held. This is safe becasuse remote
- // calls go through a oneway interface and local calls going through a handler before
- // they get to app code.
+ // In these calls we call with the lock held. This is safe becasuse remote
+ // calls go through a oneway interface and local calls going through a
+ // handler before they get to app code.
TelephonyRegistry(Context context) {
CellLocation.getEmpty().fillInNotifierBundle(mCellLocation);
@@ -90,14 +114,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
- //Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events));
+ // Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
+ // Integer.toHexString(events));
if (events != 0) {
- // check permissions
- if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
-
- }
+ /* Checks permission and throws Security exception */
+ checkListenerPermission(events);
synchronized (mRecords) {
// register
@@ -105,7 +126,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
find_and_add: {
IBinder b = callback.asBinder();
final int N = mRecords.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
r = mRecords.get(i);
if (b == r.binder) {
break find_and_add;
@@ -125,7 +146,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- r.callback.onSignalStrengthChanged(mSignalStrength);
+ int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -168,6 +191,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ try {
+ r.callback.onSignalStrengthsChanged(mSignalStrength);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -177,8 +207,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private void remove(IBinder binder) {
synchronized (mRecords) {
- final int N = mRecords.size();
- for (int i=0; i<N; i++) {
+ final int recordCount = mRecords.size();
+ for (int i = 0; i < recordCount; i++) {
if (mRecords.get(i).binder == binder) {
mRecords.remove(i);
return;
@@ -188,14 +218,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCallState(int state, String incomingNumber) {
- if (!checkPhoneStatePermission("notifyCallState()")) {
+ if (!checkNotifyPermission("notifyCallState()")) {
return;
}
synchronized (mRecords) {
mCallState = state;
mCallIncomingNumber = incomingNumber;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
try {
@@ -210,13 +239,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyServiceState(ServiceState state) {
- if (!checkPhoneStatePermission("notifyServiceState()")) {
+ if (!checkNotifyPermission("notifyServiceState()")){
return;
- }
+ }
synchronized (mRecords) {
mServiceState = state;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
sendServiceState(r, state);
@@ -226,35 +254,38 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
broadcastServiceStateChanged(state);
}
- public void notifySignalStrength(int signalStrengthASU) {
- if (!checkPhoneStatePermission("notifySignalStrength()")) {
+ public void notifySignalStrength(SignalStrength signalStrength) {
+ if (!checkNotifyPermission("notifySignalStrength()")) {
return;
- }
+ }
synchronized (mRecords) {
- mSignalStrength = signalStrengthASU;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ mSignalStrength = signalStrength;
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
+ if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ sendSignalStrength(r, signalStrength);
+ }
if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- r.callback.onSignalStrengthChanged(signalStrengthASU);
+ int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
} catch (RemoteException ex) {
remove(r.binder);
}
}
}
}
- broadcastSignalStrengthChanged(signalStrengthASU);
+ broadcastSignalStrengthChanged(signalStrength);
}
public void notifyMessageWaitingChanged(boolean mwi) {
- if (!checkPhoneStatePermission("notifyMessageWaitingChanged()")) {
+ if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
return;
- }
+ }
synchronized (mRecords) {
mMessageWaiting = mwi;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
try {
@@ -268,13 +299,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCallForwardingChanged(boolean cfi) {
- if (!checkPhoneStatePermission("notifyCallForwardingChanged()")) {
+ if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
return;
- }
+ }
synchronized (mRecords) {
mCallForwarding = cfi;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
try {
@@ -288,13 +318,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyDataActivity(int state) {
- if (!checkPhoneStatePermission("notifyDataActivity()")) {
+ if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
- }
+ }
synchronized (mRecords) {
mDataActivity = state;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
@@ -307,19 +336,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyDataConnection(int state, boolean isDataConnectivityPissible,
+ public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String interfaceName) {
- if (!checkPhoneStatePermission("notifyDataConnection()")) {
+ if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
- }
+ }
synchronized (mRecords) {
mDataConnectionState = state;
- mDataConnectionPossible = isDataConnectivityPissible;
+ mDataConnectionPossible = isDataConnectivityPossible;
mDataConnectionReason = reason;
mDataConnectionApn = apn;
mDataConnectionInterfaceName = interfaceName;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try {
@@ -330,17 +358,17 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
}
- broadcastDataConnectionStateChanged(state, isDataConnectivityPissible,
- reason, apn, interfaceName);
+ broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
+ interfaceName);
}
public void notifyDataConnectionFailed(String reason) {
- if (!checkPhoneStatePermission("notifyDataConnectionFailed()")) {
+ if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
- }
+ }
/*
* This is commented out because there is on onDataConnectionFailed callback
- * on PhoneStateListener. There should be.
+ * on PhoneStateListener. There should be
synchronized (mRecords) {
mDataConnectionFailedReason = reason;
final int N = mRecords.size();
@@ -356,13 +384,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCellLocation(Bundle cellLocation) {
- if (!checkPhoneStatePermission("notifyCellLocation()")) {
+ if (!checkNotifyPermission("notifyCellLocation()")) {
return;
- }
+ }
synchronized (mRecords) {
mCellLocation = cellLocation;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
sendCellLocation(r, cellLocation);
@@ -371,11 +398,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- //
- // the new callback broadcasting
- //
- // copy the service state object so they can't mess it up in the local calls
- //
+ /**
+ * Copy the service state object so they can't mess it up in the local calls
+ */
public void sendServiceState(Record r, ServiceState state) {
try {
r.callback.onServiceStateChanged(new ServiceState(state));
@@ -384,7 +409,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void sendCellLocation(Record r, Bundle cellLocation) {
+ private void sendCellLocation(Record r, Bundle cellLocation) {
try {
r.callback.onCellLocationChanged(new Bundle(cellLocation));
} catch (RemoteException ex) {
@@ -392,18 +417,24 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ private void sendSignalStrength(Record r, SignalStrength signalStrength) {
+ try {
+ r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump telephony.registry from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
return;
}
synchronized (mRecords) {
- final int N = mRecords.size();
+ final int recordCount = mRecords.size();
pw.println("last known state:");
pw.println(" mCallState=" + mCallState);
pw.println(" mCallIncomingNumber=" + mCallIncomingNumber);
@@ -418,20 +449,28 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println(" mDataConnectionApn=" + mDataConnectionApn);
pw.println(" mDataConnectionInterfaceName=" + mDataConnectionInterfaceName);
pw.println(" mCellLocation=" + mCellLocation);
- pw.println("registrations: count=" + N);
- for (int i=0; i<N; i++) {
+ pw.println("registrations: count=" + recordCount);
+ for (int i = 0; i < recordCount; i++) {
Record r = mRecords.get(i);
pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
}
}
}
-
//
// the legacy intent broadcasting
//
private void broadcastServiceStateChanged(ServiceState state) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteAirplaneMode(state.getState() == ServiceState.STATE_POWER_OFF);
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
@@ -439,17 +478,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendStickyBroadcast(intent);
}
- private void broadcastSignalStrengthChanged(int asu) {
+ private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
long ident = Binder.clearCallingIdentity();
try {
- mBatteryStats.notePhoneSignalStrength(asu);
+ mBatteryStats.notePhoneSignalStrength(signalStrength);
} catch (RemoteException e) {
+ /* The remote entity disappeared, we can safely ignore the exception. */
} finally {
Binder.restoreCallingIdentity(ident);
}
-
+
Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
- intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu);
+ Bundle data = new Bundle();
+ signalStrength.fillInNotifierBundle(data);
+ intent.putExtras(data);
mContext.sendStickyBroadcast(intent);
}
@@ -462,13 +504,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mBatteryStats.notePhoneOn();
}
} catch (RemoteException e) {
+ /* The remote entity disappeared, we can safely ignore the exception. */
} finally {
Binder.restoreCallingIdentity(ident);
}
-
+
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- intent.putExtra(Phone.STATE_KEY,
- DefaultPhoneNotifier.convertCallState(state).toString());
+ intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString());
if (!TextUtils.isEmpty(incomingNumber)) {
intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
}
@@ -498,16 +540,28 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
mContext.sendStickyBroadcast(intent);
}
-
- private boolean checkPhoneStatePermission(String method) {
+
+ private boolean checkNotifyPermission(String method) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
String msg = "Modify Phone State Permission Denial: " + method + " from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid();
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
Log.w(TAG, msg);
return false;
}
+
+ private void checkListenerPermission(int events) {
+ if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
+
+ }
+
+ if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PHONE_STATE, null);
+ }
+ }
}
diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java
index 5532894..d921baf 100644
--- a/services/java/com/android/server/WallpaperService.java
+++ b/services/java/com/android/server/WallpaperService.java
@@ -18,8 +18,10 @@ package com.android.server;
import static android.os.FileObserver.*;
import static android.os.ParcelFileDescriptor.*;
+
import android.app.IWallpaperService;
import android.app.IWallpaperServiceCallback;
+import android.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -154,7 +156,16 @@ class WallpaperService extends IWallpaperService.Stub {
public ParcelFileDescriptor setWallpaper() {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
try {
- return ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE);
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ MODE_CREATE|MODE_READ_WRITE);
+
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ return fd;
} catch (FileNotFoundException e) {
if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index fef3598..68bf4fb 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -504,6 +504,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");
Process.killProcess(mPhonePid);
}
} else {
@@ -848,6 +849,7 @@ public class Watchdog extends Thread {
// Only kill the process if the debugger is not attached.
if (!Debug.isDebuggerConnected()) {
+ Log.i(TAG, "Watchdog is killing the system process");
Process.killProcess(Process.myPid());
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 348f0a1..a940af3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -38,6 +38,7 @@ import android.net.wifi.WifiNative;
import android.net.wifi.WifiStateTracker;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.SupplicantState;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
import android.os.Binder;
@@ -49,6 +50,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
import android.text.TextUtils;
@@ -64,6 +66,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import com.android.internal.app.IBatteryStats;
+import android.backup.IBackupManager;
import com.android.server.am.BatteryStatsService;
/**
@@ -96,8 +99,8 @@ public class WifiService extends IWifiManager.Stub {
private int mScanLocksAcquired;
private int mScanLocksReleased;
- private final List<WifiMulticaster> mMulticasters =
- new ArrayList<WifiMulticaster>();
+ private final List<Multicaster> mMulticasters =
+ new ArrayList<Multicaster>();
private int mMulticastEnabled;
private int mMulticastDisabled;
@@ -588,6 +591,12 @@ public class WifiService extends IWifiManager.Stub {
}
+ private void enforceMulticastChangePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
+ "WifiService");
+ }
+
/**
* see {@link WifiManager#getWifiState()}
* @return One of {@link WifiManager#WIFI_STATE_DISABLED},
@@ -1054,6 +1063,94 @@ public class WifiService extends IWifiManager.Stub {
break setVariables;
}
+ if ((config.eap != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.eapVarName,
+ config.eap)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set eap: "+
+ config.eap);
+ }
+ break setVariables;
+ }
+
+ if ((config.identity != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.identityVarName,
+ config.identity)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set identity: "+
+ config.identity);
+ }
+ break setVariables;
+ }
+
+ if ((config.anonymousIdentity != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.anonymousIdentityVarName,
+ config.anonymousIdentity)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set anonymousIdentity: "+
+ config.anonymousIdentity);
+ }
+ break setVariables;
+ }
+
+ if ((config.password != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.passwordVarName,
+ config.password)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set password: "+
+ config.password);
+ }
+ break setVariables;
+ }
+
+ if ((config.clientCert != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.clientCertVarName,
+ config.clientCert)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set clientCert: "+
+ config.clientCert);
+ }
+ break setVariables;
+ }
+
+ if ((config.caCert != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.caCertVarName,
+ config.caCert)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set caCert: "+
+ config.caCert);
+ }
+ break setVariables;
+ }
+
+ if ((config.privateKey != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.privateKeyVarName,
+ config.privateKey)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set privateKey: "+
+ config.privateKey);
+ }
+ break setVariables;
+ }
+
+ if ((config.privateKeyPasswd != null) && !WifiNative.setNetworkVariableCommand(
+ netId,
+ WifiConfiguration.privateKeyPasswdVarName,
+ config.privateKeyPasswd)) {
+ if (DBG) {
+ Log.d(TAG, config.SSID + ": failed to set privateKeyPasswd: "+
+ config.privateKeyPasswd);
+ }
+ break setVariables;
+ }
+
return netId;
}
@@ -1353,6 +1450,16 @@ public class WifiService extends IWifiManager.Stub {
}
}
}
+ // Inform the backup manager about a data change
+ IBackupManager ibm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ if (ibm != null) {
+ try {
+ ibm.dataChanged("com.android.providers.settings");
+ } catch (Exception e) {
+ // Try again later
+ }
+ }
return result;
}
@@ -1449,10 +1556,12 @@ public class WifiService extends IWifiManager.Stub {
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");
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+ Log.d(TAG, "ACTION_SCREEN_OFF");
mScreenOff = true;
/*
* Set a timer to put Wi-Fi to sleep, but only if the screen is off
@@ -1461,12 +1570,21 @@ public class WifiService extends IWifiManager.Stub {
* or plugged in to AC).
*/
if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
- long triggerTime = System.currentTimeMillis() + idleMillis;
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+ WifiInfo info = mWifiStateTracker.requestConnectionInfo();
+ if (info.getSupplicantState() != SupplicantState.COMPLETED) {
+ // 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");
+ 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");
mDeviceIdle = true;
} else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
/*
@@ -1477,9 +1595,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);
if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
!shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
long triggerTime = System.currentTimeMillis() + idleMillis;
+ Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
mPluggedType = pluggedType;
return;
@@ -1732,7 +1852,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- private class WifiLock extends WifiDeathRecipient {
+ private class WifiLock extends DeathRecipient {
WifiLock(int lockMode, String tag, IBinder binder) {
super(lockMode, tag, binder);
}
@@ -1780,7 +1900,9 @@ public class WifiService extends IWifiManager.Stub {
private WifiLock removeLock(IBinder binder) {
int index = findLockByBinder(binder);
if (index >= 0) {
- return mList.remove(index);
+ WifiLock ret = mList.remove(index);
+ ret.unlinkDeathRecipient();
+ return ret;
} else {
return null;
}
@@ -1875,13 +1997,13 @@ public class WifiService extends IWifiManager.Stub {
return hadLock;
}
- private abstract class WifiDeathRecipient
+ private abstract class DeathRecipient
implements IBinder.DeathRecipient {
String mTag;
int mMode;
IBinder mBinder;
- WifiDeathRecipient(int mode, String tag, IBinder binder) {
+ DeathRecipient(int mode, String tag, IBinder binder) {
super();
mTag = tag;
mMode = mode;
@@ -1892,15 +2014,19 @@ public class WifiService extends IWifiManager.Stub {
binderDied();
}
}
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
}
- private class WifiMulticaster extends WifiDeathRecipient {
- WifiMulticaster(String tag, IBinder binder) {
+ private class Multicaster extends DeathRecipient {
+ Multicaster(String tag, IBinder binder) {
super(Binder.getCallingUid(), tag, binder);
}
public void binderDied() {
- Log.e(TAG, "WifiMulticaster binderDied");
+ Log.e(TAG, "Multicaster binderDied");
synchronized (mMulticasters) {
int i = mMulticasters.indexOf(this);
if (i != -1) {
@@ -1910,7 +2036,7 @@ public class WifiService extends IWifiManager.Stub {
}
public String toString() {
- return "WifiMulticaster{" + mTag + " binder=" + mBinder + "}";
+ return "Multicaster{" + mTag + " binder=" + mBinder + "}";
}
public int getUid() {
@@ -1918,12 +2044,12 @@ public class WifiService extends IWifiManager.Stub {
}
}
- public void enableWifiMulticast(IBinder binder, String tag) {
- enforceChangePermission();
+ public void acquireMulticastLock(IBinder binder, String tag) {
+ enforceMulticastChangePermission();
synchronized (mMulticasters) {
mMulticastEnabled++;
- mMulticasters.add(new WifiMulticaster(tag, binder));
+ mMulticasters.add(new Multicaster(tag, binder));
// Note that we could call stopPacketFiltering only when
// our new size == 1 (first call), but this function won't
// be called often and by making the stopPacket call each
@@ -1941,15 +2067,15 @@ public class WifiService extends IWifiManager.Stub {
}
}
- public void disableWifiMulticast() {
- enforceChangePermission();
+ public void releaseMulticastLock() {
+ enforceMulticastChangePermission();
int uid = Binder.getCallingUid();
synchronized (mMulticasters) {
mMulticastDisabled++;
int size = mMulticasters.size();
for (int i = size - 1; i >= 0; i--) {
- WifiMulticaster m = mMulticasters.get(i);
+ Multicaster m = mMulticasters.get(i);
if ((m != null) && (m.getUid() == uid)) {
removeMulticasterLocked(i, uid);
}
@@ -1959,7 +2085,10 @@ public class WifiService extends IWifiManager.Stub {
private void removeMulticasterLocked(int i, int uid)
{
- mMulticasters.remove(i);
+ Multicaster removed = mMulticasters.remove(i);
+ if (removed != null) {
+ removed.unlinkDeathRecipient();
+ }
if (mMulticasters.size() == 0) {
WifiNative.startPacketFiltering();
}
@@ -1973,7 +2102,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
- public boolean isWifiMulticastEnabled() {
+ public boolean isMulticastEnabled() {
enforceAccessPermission();
synchronized (mMulticasters) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3fa5baf..2dd70ef 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -77,6 +77,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TokenWatcher;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseIntArray;
@@ -133,16 +134,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean SHOW_TRANSACTIONS = false;
-
+
static final boolean PROFILE_ORIENTATION = false;
static final boolean BLUR = true;
static final boolean localLOGV = DEBUG;
-
+
static final int LOG_WM_NO_SURFACE_MEMORY = 31000;
-
+
/** How long to wait for first key repeat, in milliseconds */
static final int KEY_REPEAT_FIRST_DELAY = 750;
-
+
/** How long to wait for subsequent key repeats, in milliseconds */
static final int KEY_REPEAT_DELAY = 50;
@@ -150,16 +151,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* for multiple windows of the same type and Z-ordering adjustment
* with TYPE_LAYER_OFFSET. */
static final int TYPE_LAYER_MULTIPLIER = 10000;
-
+
/** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
* or below others in the same layer. */
static final int TYPE_LAYER_OFFSET = 1000;
-
+
/** How much to increment the layer for each window, to reserve room
* for effect surfaces between them.
*/
static final int WINDOW_LAYER_MULTIPLIER = 5;
-
+
/** The maximum length we will accept for a loaded animation duration:
* this is 10 seconds.
*/
@@ -173,21 +174,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
/** Adjustment to time to perform a dim, to make it more dramatic.
*/
static final int DIM_DURATION_MULTIPLIER = 6;
+
+ 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;
static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
-
+
/** The minimum time between dispatching touch events. */
int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
// Last touch event time
long mLastTouchEventTime = 0;
-
+
// Last touch event type
int mLastTouchEventType = OTHER_EVENT;
-
+
// Time to wait before calling useractivity again. This saves CPU usage
// when we get a flood of touch events.
static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
@@ -195,10 +200,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Last time we call user activity
long mLastUserActivityCallTime = 0;
- // Last time we updated battery stats
+ // Last time we updated battery stats
long mLastBatteryStatsCallTime = 0;
-
+
private static final String SYSTEM_SECURE = "ro.secure";
+ private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
/**
* Condition waited on by {@link #reenableKeyguard} to know the call to
@@ -224,20 +230,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Context mContext;
final boolean mHaveInputMethods;
-
+
final boolean mLimitedAlphaCompositing;
-
+
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
final IActivityManager mActivityManager;
-
+
final IBatteryStats mBatteryStats;
-
+
/**
* All currently active sessions with clients.
*/
final HashSet<Session> mSessions = new HashSet<Session>();
-
+
/**
* Mapping from an IWindow IBinder to the server's Window object.
* This is also used as the lock for all of our state.
@@ -255,7 +261,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* over them.
*/
final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
-
+
/**
* Window tokens that are in the process of exiting, but still
* on screen for animations.
@@ -314,9 +320,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* list or contain windows that need to be force removed.
*/
ArrayList<WindowState> mForceRemoves;
-
+
IInputMethodManager mInputMethodManager;
-
+
SurfaceSession mFxSession;
Surface mDimSurface;
boolean mDimShown;
@@ -326,9 +332,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
long mLastDimAnimTime;
Surface mBlurSurface;
boolean mBlurShown;
-
+
int mTransactionSequence = 0;
-
+
final float[] mTmpFloats = new float[9];
boolean mSafeMode;
@@ -340,7 +346,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int mLastRotationFlags;
ArrayList<IRotationWatcher> mRotationWatchers
= new ArrayList<IRotationWatcher>();
-
+
boolean mLayoutNeeded = true;
boolean mAnimationPending = false;
boolean mDisplayFrozen = false;
@@ -352,7 +358,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// perform a rotation animation when turning off shows the lock screen which
// changes the orientation.
PowerManager.WakeLock mScreenFrozenLock;
-
+
// State management of app transitions. When we are preparing for a
// transition, mNextAppTransition will be the kind of transition to
// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
@@ -365,40 +371,40 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean mSkipAppTransitionAnimation = false;
final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
-
+
//flag to detect fat touch events
boolean mFatTouch = false;
Display mDisplay;
-
+
H mH = new H();
WindowState mCurrentFocus = null;
WindowState mLastFocus = null;
-
+
// This just indicates the window the input method is on top of, not
// necessarily the window its input is going to.
WindowState mInputMethodTarget = null;
WindowState mUpcomingInputMethodTarget = null;
boolean mInputMethodTargetWaitingAnim;
int mInputMethodAnimLayerAdjustment;
-
+
WindowState mInputMethodWindow = null;
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
AppWindowToken mFocusedApp = null;
PowerManagerService mPowerManager;
-
+
float mWindowAnimationScale = 1.0f;
float mTransitionAnimationScale = 1.0f;
-
+
final KeyWaiter mKeyWaiter = new KeyWaiter();
final KeyQ mQueue;
final InputDispatcherThread mInputThread;
// Who is holding the screen on.
Session mHoldingScreenOn;
-
+
/**
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
@@ -408,14 +414,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private ViewServer mViewServer;
final Rect mTempRect = new Rect();
-
+
final Configuration mTempConfiguration = new Configuration();
+ int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods) {
WMThread thr = new WMThread(context, pm, haveInputMethods);
thr.start();
-
+
synchronized (thr) {
while (thr.mService == null) {
try {
@@ -424,17 +431,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
return thr.mService;
}
-
+
static class WMThread extends Thread {
WindowManagerService mService;
-
+
private final Context mContext;
private final PowerManagerService mPM;
private final boolean mHaveInputMethods;
-
+
public WMThread(Context context, PowerManagerService pm,
boolean haveInputMethods) {
super("WindowManager");
@@ -442,19 +449,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mPM = pm;
mHaveInputMethods = haveInputMethods;
}
-
+
public void run() {
Looper.prepare();
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_DISPLAY);
-
+
synchronized (this) {
mService = s;
notifyAll();
}
-
+
Looper.loop();
}
}
@@ -465,7 +472,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private final Context mContext;
private final PowerManagerService mPM;
boolean mRunning = false;
-
+
public PolicyThread(WindowManagerPolicy policy,
WindowManagerService service, Context context,
PowerManagerService pm) {
@@ -475,7 +482,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mContext = context;
mPM = pm;
}
-
+
public void run() {
Looper.prepare();
//Looper.myLooper().setMessageLogging(new LogPrinter(
@@ -483,12 +490,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
mPolicy.init(mContext, mService, mPM);
-
+
synchronized (this) {
mRunning = true;
notifyAll();
}
-
+
Looper.loop();
}
}
@@ -499,7 +506,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mHaveInputMethods = haveInputMethods;
mLimitedAlphaCompositing = context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_limitedAlpha);
-
+
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -515,14 +522,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
-
+
mQueue = new KeyQ();
mInputThread = new InputDispatcherThread();
-
+
PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
thr.start();
-
+
synchronized (thr) {
while (!thr.mRunning) {
try {
@@ -531,9 +538,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
mInputThread.start();
-
+
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
@@ -586,12 +593,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return -1;
}
-
+
private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
final IWindow client = win.mClient;
final WindowToken token = win.mToken;
final ArrayList localmWindows = mWindows;
-
+
final int N = localmWindows.size();
final WindowState attached = win.mAttachedWindow;
int i;
@@ -616,12 +623,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
int newIdx = findIdxBasedOnAppTokens(win);
if(newIdx != -1) {
- //there is a window above this one associated with the same
- //apptoken note that the window could be a floating window
- //that was created later or a window at the top of the list of
+ //there is a window above this one associated with the same
+ //apptoken note that the window could be a floating window
+ //that was created later or a window at the top of the list of
//windows associated with this token.
localmWindows.add(newIdx+1, win);
- }
+ }
}
}
} else {
@@ -647,7 +654,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// we need to look some more.
if (pos != null) {
// Move behind any windows attached to this one.
- WindowToken atoken =
+ WindowToken atoken =
mTokenMap.get(((WindowState)pos).mClient.asBinder());
if (atoken != null) {
final int NC = atoken.windows.size();
@@ -770,12 +777,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
if (win.mAppToken != null && addToToken) {
win.mAppToken.allAppWindows.add(win);
}
}
-
+
static boolean canBeImeTarget(WindowState w) {
final int fl = w.mAttrs.flags
& (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
@@ -784,7 +791,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return false;
}
-
+
int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
final ArrayList localmWindows = mWindows;
final int N = localmWindows.size();
@@ -793,12 +800,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
while (i > 0) {
i--;
w = (WindowState)localmWindows.get(i);
-
+
//Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
// + Integer.toHexString(w.mAttrs.flags));
if (canBeImeTarget(w)) {
//Log.i(TAG, "Putting input method here!");
-
+
// Yet more tricksyness! If this window is a "starting"
// window, we do actually want to be on top of it, but
// it is not -really- where input will go. So if the caller
@@ -816,16 +823,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
break;
}
}
-
+
mUpcomingInputMethodTarget = w;
-
+
if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
+ w + " willMove=" + willMove);
-
+
if (willMove && w != null) {
final WindowState curTarget = mInputMethodTarget;
if (curTarget != null && curTarget.mAppToken != null) {
-
+
// Now some fun for dealing with window animations that
// modify the Z order. We need to look at all windows below
// the current target that are in this app, finding the highest
@@ -851,14 +858,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pos--;
}
}
-
+
if (highestTarget != null) {
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
+ mNextAppTransition + " " + highestTarget
+ " animating=" + highestTarget.isAnimating()
+ " layer=" + highestTarget.mAnimLayer
+ " new layer=" + w.mAnimLayer);
-
+
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
// If we are currently setting up for an animation,
// hold everything until we can find out what will happen.
@@ -877,7 +884,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
//Log.i(TAG, "Placing input method @" + (i+1));
if (w != null) {
if (willMove) {
@@ -904,7 +911,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return -1;
}
-
+
void addInputMethodWindowToListLocked(WindowState win) {
int pos = findDesiredInputMethodWindowIndexLocked(true);
if (pos >= 0) {
@@ -917,7 +924,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
addWindowToListInOrderLocked(win, true);
moveInputMethodDialogsLocked(pos);
}
-
+
void setInputMethodAnimLayerAdjustment(int adj) {
if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
mInputMethodAnimLayerAdjustment = adj;
@@ -944,7 +951,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " anim layer: " + imw.mAnimLayer);
}
}
-
+
private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
int wpos = mWindows.indexOf(win);
if (wpos >= 0) {
@@ -963,7 +970,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return interestingPos;
}
-
+
private void reAddWindowToListInOrderLocked(WindowState win) {
addWindowToListInOrderLocked(win, false);
// This is a hack to get all of the child windows added as well
@@ -975,7 +982,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
reAddWindowLocked(wpos, win);
}
}
-
+
void logWindowList(String prefix) {
int N = mWindows.size();
while (N > 0) {
@@ -983,10 +990,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
}
}
-
+
void moveInputMethodDialogsLocked(int pos) {
ArrayList<WindowState> dialogs = mInputMethodDialogs;
-
+
final int N = dialogs.size();
if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
for (int i=0; i<N; i++) {
@@ -996,7 +1003,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, "Window list w/pos=" + pos);
logWindowList(" ");
}
-
+
if (pos >= 0) {
final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
if (pos < mWindows.size()) {
@@ -1027,25 +1034,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
final WindowState imWin = mInputMethodWindow;
final int DN = mInputMethodDialogs.size();
if (imWin == null && DN == 0) {
return false;
}
-
+
int imPos = findDesiredInputMethodWindowIndexLocked(true);
if (imPos >= 0) {
// In this case, the input method windows are to be placed
// immediately above the window they are targeting.
-
+
// First check to see if the input method windows are already
// located here, and contiguous.
final int N = mWindows.size();
WindowState firstImWin = imPos < N
? (WindowState)mWindows.get(imPos) : null;
-
+
// Figure out the actual input method window that should be
// at the bottom of their stack.
WindowState baseImWin = imWin != null
@@ -1054,7 +1061,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState cw = (WindowState)baseImWin.mChildWindows.get(0);
if (cw.mSubLayer < 0) baseImWin = cw;
}
-
+
if (firstImWin == baseImWin) {
// The windows haven't moved... but are they still contiguous?
// First find the top IM window.
@@ -1078,7 +1085,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return false;
}
}
-
+
if (imWin != null) {
if (DEBUG_INPUT_METHOD) {
Log.v(TAG, "Moving IM from " + imPos);
@@ -1099,11 +1106,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
moveInputMethodDialogsLocked(imPos);
}
-
+
} else {
// In this case, the input method windows go in a fixed layer,
// because they aren't currently associated with a focus window.
-
+
if (imWin != null) {
if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
tmpRemoveWindowLocked(0, imWin);
@@ -1117,20 +1124,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
moveInputMethodDialogsLocked(-1);;
}
-
+
}
-
+
if (needAssignLayers) {
assignLayersLocked();
}
-
+
return true;
}
-
+
void adjustInputMethodDialogsLocked() {
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
}
-
+
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets) {
@@ -1138,11 +1145,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
}
-
+
boolean reportNewConfig = false;
WindowState attachedWindow = null;
WindowState win = null;
-
+
synchronized(mWindowMap) {
// Instantiating a Display requires talking with the simulator,
// so don't do it until we know the system is mostly up and
@@ -1153,14 +1160,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.setDisplay(mDisplay);
reportNewConfig = true;
}
-
+
if (mWindowMap.containsKey(client.asBinder())) {
Log.w(TAG, "Window " + client + " is already added");
return WindowManagerImpl.ADD_DUPLICATE_ADD;
}
if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(null, attrs.token);
+ attachedWindow = windowForClientLocked(null, attrs.token);
if (attachedWindow == null) {
Log.w(TAG, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
@@ -1227,7 +1234,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
mPolicy.adjustWindowParamsLw(win.mAttrs);
-
+
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
@@ -1236,9 +1243,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// From now on, no exceptions or errors allowed!
res = WindowManagerImpl.ADD_OKAY;
-
+
final long origId = Binder.clearCallingIdentity();
-
+
if (addToken) {
mTokenMap.put(attrs.token, token);
mTokenList.add(token);
@@ -1252,7 +1259,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
boolean imMayMove = true;
-
+
if (attrs.type == TYPE_INPUT_METHOD) {
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
@@ -1265,18 +1272,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
addWindowToListInOrderLocked(win, true);
}
-
+
win.mEnterAnimationPending = true;
-
+
mPolicy.getContentInsetHintLw(attrs, outContentInsets);
-
+
if (mInTouchMode) {
res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
}
if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
}
-
+
boolean focusChanged = false;
if (win.canReceiveKeys()) {
if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
@@ -1284,15 +1291,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
imMayMove = false;
}
}
-
+
if (imMayMove) {
- moveInputMethodWindowsIfNeededLocked(false);
+ moveInputMethodWindowsIfNeededLocked(false);
}
-
+
assignLayersLocked();
// Don't do layout here, the window must call
// relayout to be displayed, so we'll do it there.
-
+
//dump();
if (focusChanged) {
@@ -1300,7 +1307,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
}
}
-
if (localLOGV) Log.v(
TAG, "New client " + client.asBinder()
+ ": window=" + win);
@@ -1317,16 +1323,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Update Orientation after adding a window, only if the window needs to be
// displayed right away
if (win.isVisibleOrAdding()) {
- if (updateOrientationFromAppTokens(null, null) != null) {
+ if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
sendNewConfiguration();
}
}
}
Binder.restoreCallingIdentity(origId);
-
+
return res;
}
-
+
public void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client);
@@ -1336,7 +1342,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
removeWindowLocked(session, win);
}
}
-
+
public void removeWindowLocked(Session session, WindowState win) {
if (localLOGV || DEBUG_FOCUS) Log.v(
@@ -1346,7 +1352,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ ", surface=" + win.mSurface);
final long origId = Binder.clearCallingIdentity();
-
+
if (DEBUG_APP_TRANSITIONS) Log.v(
TAG, "Remove " + win + ": mSurface=" + win.mSurface
+ " mExiting=" + win.mExiting
@@ -1366,7 +1372,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// If we are not currently running the exit animation, we
// need to see about starting one.
if (wasVisible=win.isWinVisibleLw()) {
-
+
int transit = WindowManagerPolicy.TRANSIT_EXIT;
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
@@ -1403,17 +1409,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
}
-
+
private void removeWindowInnerLocked(Session session, WindowState win) {
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
-
+
win.mRemoved = true;
-
+
if (mInputMethodTarget == win) {
moveInputMethodWindowsIfNeededLocked(false);
}
-
+
mPolicy.removeWindowLw(win);
win.removeLocked();
@@ -1425,7 +1431,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.remove(win);
}
-
+
final WindowToken token = win.mToken;
final AppWindowToken atoken = win.mAppToken;
token.windows.remove(win);
@@ -1462,7 +1468,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.sendMessage(m);
}
}
-
+
if (!mInLayout) {
assignLayersLocked();
mLayoutNeeded = true;
@@ -1493,7 +1499,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
void setInsetsWindow(Session session, IWindow client,
- int touchableInsets, Rect contentInsets,
+ int touchableInsets, Rect contentInsets,
Rect visibleInsets) {
long origId = Binder.clearCallingIdentity();
try {
@@ -1512,7 +1518,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Binder.restoreCallingIdentity(origId);
}
}
-
+
public void getWindowDisplayFrame(Session session, IWindow client,
Rect outDisplayFrame) {
synchronized(mWindowMap) {
@@ -1534,7 +1540,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean inTouchMode;
Configuration newConfig = null;
long origId = Binder.clearCallingIdentity();
-
+
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client);
if (win == null) {
@@ -1546,7 +1552,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (attrs != null) {
mPolicy.adjustWindowParamsLw(attrs);
}
-
+
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
@@ -1578,11 +1584,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean imMayMove = (flagChanges&(
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
-
+
boolean focusMayChange = win.mViewVisibility != viewVisibility
|| ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
-
+
win.mRelayoutCalled = true;
final int oldVisibility = win.mViewVisibility;
win.mViewVisibility = viewVisibility;
@@ -1670,17 +1676,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
//System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
}
-
+
// updateFocusedWindowLocked() already assigned layers so we only need to
// reassign them at this point if the IM window state gets shuffled
boolean assignLayers = false;
-
+
if (imMayMove) {
if (moveInputMethodWindowsIfNeededLocked(false)) {
assignLayers = true;
}
}
-
+
mLayoutNeeded = true;
win.mGivenInsetsPending = insetsPending;
if (assignLayers) {
@@ -1696,7 +1702,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
outVisibleInsets.set(win.mVisibleInsets);
if (localLOGV) Log.v(
TAG, "Relayout given client " + client.asBinder()
- + ", requestedWidth=" + requestedWidth
+ + ", requestedWidth=" + requestedWidth
+ ", requestedHeight=" + requestedHeight
+ ", viewVisibility=" + viewVisibility
+ "\nRelayout returning frame=" + outFrame
@@ -1711,9 +1717,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (newConfig != null) {
sendNewConfiguration();
}
-
+
Binder.restoreCallingIdentity(origId);
-
+
return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
| (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0);
}
@@ -1750,7 +1756,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return null;
}
-
+
private void applyEnterAnimationLocked(WindowState win) {
int transit = WindowManagerPolicy.TRANSIT_SHOW;
if (win.mEnterAnimationPending) {
@@ -1768,7 +1774,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// an animation of the same type, then just leave that one alone.
return true;
}
-
+
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
@@ -1833,7 +1839,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return null;
}
-
+
private boolean applyAnimationLocked(AppWindowToken wtoken,
WindowManager.LayoutParams lp, int transit, boolean enter) {
// Only apply an animation if the display isn't frozen. If it is
@@ -1932,7 +1938,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (Binder.getCallingPid() == Process.myPid()) {
return true;
}
-
+
if (mContext.checkCallingPermission(permission)
== PackageManager.PERMISSION_GRANTED) {
return true;
@@ -1944,7 +1950,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.w(TAG, msg);
return false;
}
-
+
AppWindowToken findAppWindowToken(IBinder token) {
WindowToken wtoken = mTokenMap.get(token);
if (wtoken == null) {
@@ -1952,13 +1958,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return wtoken.appWindowToken;
}
-
+
public void addWindowToken(IBinder token, int type) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addWindowToken()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
+
synchronized(mWindowMap) {
WindowToken wtoken = mTokenMap.get(token);
if (wtoken != null) {
@@ -1970,11 +1976,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mTokenList.add(wtoken);
}
}
-
+
public void removeWindowToken(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"removeWindowToken()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
final long origId = Binder.clearCallingIdentity();
@@ -1985,17 +1991,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean delayed = false;
if (!wtoken.hidden) {
wtoken.hidden = true;
-
+
final int N = wtoken.windows.size();
boolean changed = false;
-
+
for (int i=0; i<N; i++) {
WindowState win = wtoken.windows.get(i);
if (win.isAnimating()) {
delayed = true;
}
-
+
if (win.isVisibleNow()) {
applyAnimationLocked(win,
WindowManagerPolicy.TRANSIT_EXIT, false);
@@ -2010,12 +2016,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
performLayoutAndPlaceSurfacesLocked();
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
}
-
+
if (delayed) {
mExitingTokens.add(wtoken);
}
}
-
+
} else {
Log.w(TAG, "Attempted to remove non-existing token: " + token);
}
@@ -2027,9 +2033,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int groupId, int requestedOrientation, boolean fullscreen) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
+
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken != null) {
@@ -2044,19 +2050,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (localLOGV) Log.v(TAG, "Adding new app token: " + wtoken);
mTokenMap.put(token.asBinder(), wtoken);
mTokenList.add(wtoken);
-
+
// Application tokens start out hidden.
wtoken.hidden = true;
wtoken.hiddenRequested = true;
-
+
//dump();
}
}
-
+
public void setAppGroupId(IBinder token, int groupId) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppStartingIcon()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -2068,7 +2074,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken.groupId = groupId;
}
}
-
+
public int getOrientationFromWindowsLocked() {
int pos = mWindows.size() - 1;
while (pos >= 0) {
@@ -2092,7 +2098,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
-
+
public int getOrientationFromAppTokensLocked() {
int pos = mAppTokens.size() - 1;
int curGroup = 0;
@@ -2134,7 +2140,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// to use the orientation behind it, then just take whatever
// orientation it has and ignores whatever is under it.
lastFullscreen = wtoken.appFullscreen;
- if (lastFullscreen
+ if (lastFullscreen
&& or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
return or;
}
@@ -2151,11 +2157,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
-
+
public Configuration updateOrientationFromAppTokens(
Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
+ if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+ "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;
synchronized(mWindowMap) {
config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
}
@@ -2163,14 +2183,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
- Binder.restoreCallingIdentity(ident);
return config;
}
-
+
/*
* The orientation is computed from non-application windows first. If none of
* the non-application windows specify orientation, the orientation is computed from
- * application tokens.
+ * application tokens.
* @see android.view.IWindowManager#updateOrientationFromAppTokens(
* android.os.IBinder)
*/
@@ -2180,7 +2199,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
long ident = Binder.clearCallingIdentity();
try {
int req = computeForcedAppOrientationLocked();
-
+
if (req != mForcedAppOrientation) {
changed = true;
mForcedAppOrientation = req;
@@ -2188,7 +2207,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//action like disabling/enabling sensors etc.,
mPolicy.setCurrentOrientationLw(req);
}
-
+
if (changed) {
changed = setRotationUncheckedLocked(
WindowManagerPolicy.USE_LAST_ROTATION,
@@ -2220,10 +2239,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} finally {
Binder.restoreCallingIdentity(ident);
}
-
+
return null;
}
-
+
int computeForcedAppOrientationLocked() {
int req = getOrientationFromWindowsLocked();
if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
@@ -2231,39 +2250,39 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return req;
}
-
+
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppOrientation()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
+
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken == null) {
Log.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
return;
}
-
+
wtoken.requestedOrientation = requestedOrientation;
}
}
-
+
public int getAppOrientation(IApplicationToken token) {
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
-
+
return wtoken.requestedOrientation;
}
}
-
+
public void setFocusedApp(IBinder token, boolean moveFocusNow) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setFocusedApp()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -2296,9 +2315,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void prepareAppTransition(int transit) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"prepareAppTransition()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
+
synchronized(mWindowMap) {
if (DEBUG_APP_TRANSITIONS) Log.v(
TAG, "Prepare app transition: transit=" + transit
@@ -2306,6 +2325,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!mDisplayFrozen) {
if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
mNextAppTransition = transit;
+ } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
+ && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
+ // Opening a new task always supersedes a close for the anim.
+ mNextAppTransition = transit;
+ } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
+ && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
+ // Opening a new activity always supersedes a close for the anim.
+ mNextAppTransition = transit;
}
mAppTransitionReady = false;
mAppTransitionTimeout = false;
@@ -2321,13 +2348,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public int getPendingAppTransition() {
return mNextAppTransition;
}
-
+
public void executeAppTransition() {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"executeAppTransition()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
+
synchronized(mWindowMap) {
if (DEBUG_APP_TRANSITIONS) Log.v(
TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
@@ -2345,14 +2372,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
IBinder transferFrom, boolean createIfNeeded) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppStartingIcon()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
if (DEBUG_STARTING_WINDOW) Log.v(
TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
+ " transferFrom=" + transferFrom);
-
+
AppWindowToken wtoken = findAppWindowToken(token);
if (wtoken == null) {
Log.w(TAG, "Attempted to set icon of non-existing app token: " + token);
@@ -2365,11 +2392,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mDisplayFrozen) {
return;
}
-
+
if (wtoken.startingData != null) {
return;
}
-
+
if (transferFrom != null) {
AppWindowToken ttoken = findAppWindowToken(transferFrom);
if (ttoken != null) {
@@ -2385,7 +2412,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
"Moving existing starting from " + ttoken
+ " to " + wtoken);
final long origId = Binder.clearCallingIdentity();
-
+
// Transfer the starting window over to the new
// token.
wtoken.startingData = ttoken.startingData;
@@ -2403,7 +2430,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
ttoken.allAppWindows.remove(startingWindow);
addWindowToListInOrderLocked(startingWindow, true);
wtoken.allAppWindows.add(startingWindow);
-
+
// Propagate other interesting state between the
// tokens. If the old token is displayed, we should
// immediately force the new one to be displayed. If
@@ -2433,7 +2460,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken.updateLayers();
ttoken.updateLayers();
}
-
+
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -2463,7 +2490,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!createIfNeeded) {
return;
}
-
+
mStartingIconInTransition = true;
wtoken.startingData = new StartingData(
pkg, theme, nonLocalizedLabel,
@@ -2479,7 +2506,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void setAppWillBeHidden(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppWillBeHidden()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
AppWindowToken wtoken;
@@ -2493,7 +2520,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken.willBeHidden = true;
}
}
-
+
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
boolean visible, int transit, boolean performLayout) {
boolean delayed = false;
@@ -2502,7 +2529,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken.clientHidden = !visible;
wtoken.sendAppVisibilityToClients();
}
-
+
wtoken.willBeHidden = false;
if (wtoken.hidden == visible) {
final int N = wtoken.allAppWindows.size();
@@ -2510,9 +2537,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_APP_TRANSITIONS) Log.v(
TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
+ " performLayout=" + performLayout);
-
+
boolean runningAppAnimation = false;
-
+
if (transit != WindowManagerPolicy.TRANSIT_NONE) {
if (wtoken.animation == sDummyAnimation) {
wtoken.animation = null;
@@ -2523,7 +2550,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
delayed = runningAppAnimation = true;
}
}
-
+
for (int i=0; i<N; i++) {
WindowState win = wtoken.allAppWindows.get(i);
if (win == wtoken.startingWindow) {
@@ -2533,7 +2560,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.isAnimating()) {
delayed = true;
}
-
+
//Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
//win.dump(" ");
if (visible) {
@@ -2568,11 +2595,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
swin.mPolicyVisibilityAfterAnim = false;
}
}
-
+
if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "setTokenVisibilityLocked: " + wtoken
+ ": hidden=" + wtoken.hidden + " hiddenRequested="
+ wtoken.hiddenRequested);
-
+
if (changed && performLayout) {
mLayoutNeeded = true;
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
@@ -2583,14 +2610,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (wtoken.animation != null) {
delayed = true;
}
-
+
return delayed;
}
public void setAppVisibility(IBinder token, boolean visible) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppVisibility()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
AppWindowToken wtoken;
@@ -2610,7 +2637,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " hidden=" + wtoken.hidden
+ " hiddenRequested=" + wtoken.hiddenRequested, e);
}
-
+
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
@@ -2619,7 +2646,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return;
}
wtoken.hiddenRequested = !visible;
-
+
if (DEBUG_APP_TRANSITIONS) Log.v(
TAG, "Setting dummy animation on: " + wtoken);
wtoken.setDummyAnimation();
@@ -2631,7 +2658,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken.allDrawn = false;
wtoken.startingDisplayed = false;
wtoken.startingMoved = false;
-
+
if (wtoken.clientHidden) {
// In the case where we are making an app visible
// but holding off for a transition, we still need
@@ -2647,7 +2674,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return;
}
-
+
final long origId = Binder.clearCallingIdentity();
setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
wtoken.updateReportedVisibilityLocked();
@@ -2688,7 +2715,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
public void startAppFreezingScreenLocked(AppWindowToken wtoken,
int configChanges) {
if (DEBUG_ORIENTATION) {
@@ -2716,11 +2743,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
public void startAppFreezingScreen(IBinder token, int configChanges) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppFreezingScreen()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -2728,7 +2755,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_ORIENTATION) Log.v(TAG, "Skipping set freeze of " + token);
return;
}
-
+
AppWindowToken wtoken = findAppWindowToken(token);
if (wtoken == null || wtoken.appToken == null) {
Log.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
@@ -2739,11 +2766,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Binder.restoreCallingIdentity(origId);
}
}
-
+
public void stopAppFreezingScreen(IBinder token, boolean force) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppFreezingScreen()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -2758,11 +2785,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Binder.restoreCallingIdentity(origId);
}
}
-
+
public void removeAppToken(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"removeAppToken()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
AppWindowToken wtoken = null;
@@ -2807,7 +2834,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
Log.w(TAG, "Attempted to remove non-existing app token: " + token);
}
-
+
if (!delayed && wtoken != null) {
wtoken.updateReportedVisibilityLocked();
}
@@ -2841,13 +2868,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, " #" + i + ": " + mAppTokens.get(i).token);
}
}
-
+
void dumpWindowsLocked() {
for (int i=mWindows.size()-1; i>=0; i--) {
Log.v(TAG, " #" + i + ": " + mWindows.get(i));
}
}
-
+
private int findWindowOffsetLocked(int tokenPos) {
final int NW = mWindows.size();
@@ -2918,7 +2945,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return index;
}
-
+
private final int reAddAppWindowsLocked(int index, WindowToken token) {
final int NW = token.windows.size();
for (int i=0; i<NW; i++) {
@@ -2930,7 +2957,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void moveAppToken(int index, IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"moveAppToken()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -2945,7 +2972,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAppTokens.add(index, wtoken);
if (DEBUG_REORDER) Log.v(TAG, "Moved " + token + " to " + index + ":");
if (DEBUG_REORDER) dumpAppTokensLocked();
-
+
final long origId = Binder.clearCallingIdentity();
if (DEBUG_REORDER) Log.v(TAG, "Removing windows in " + token + ":");
if (DEBUG_REORDER) dumpWindowsLocked();
@@ -3012,7 +3039,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void moveAppTokensToTop(List<IBinder> tokens) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"moveAppTokensToTop()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
final long origId = Binder.clearCallingIdentity();
@@ -3033,7 +3060,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void moveAppTokensToBottom(List<IBinder> tokens) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"moveAppTokensToBottom()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
final long origId = Binder.clearCallingIdentity();
@@ -3056,7 +3083,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// -------------------------------------------------------------
// Misc IWindowSession methods
// -------------------------------------------------------------
-
+
public void disableKeyguard(IBinder token, String tag) {
if (mContext.checkCallingPermission(android.Manifest.permission.DISABLE_KEYGUARD)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3110,17 +3137,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public boolean inKeyguardRestrictedInputMode() {
return mPolicy.inKeyguardRestrictedKeyInputMode();
}
-
+
static float fixScale(float scale) {
if (scale < 0) scale = 0;
else if (scale > 20) scale = 20;
return Math.abs(scale);
}
-
+
public void setAnimationScale(int which, float scale) {
if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
"setAnimationScale()")) {
- return;
+ throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
}
if (scale < 0) scale = 0;
@@ -3130,15 +3157,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
case 0: mWindowAnimationScale = fixScale(scale); break;
case 1: mTransitionAnimationScale = fixScale(scale); break;
}
-
+
// Persist setting
mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
}
-
+
public void setAnimationScales(float[] scales) {
if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
"setAnimationScale()")) {
- return;
+ throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
}
if (scales != null) {
@@ -3149,11 +3176,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mTransitionAnimationScale = fixScale(scales[1]);
}
}
-
+
// Persist setting
mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
}
-
+
public float getAnimationScale(int which) {
switch (which) {
case 0: return mWindowAnimationScale;
@@ -3161,63 +3188,63 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return 0;
}
-
+
public float[] getAnimationScales() {
return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
}
-
+
public int getSwitchState(int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getSwitchState()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getSwitchState(sw);
}
-
+
public int getSwitchStateForDevice(int devid, int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getSwitchStateForDevice()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getSwitchState(devid, sw);
}
-
+
public int getScancodeState(int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getScancodeState()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getScancodeState(sw);
}
-
+
public int getScancodeStateForDevice(int devid, int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getScancodeStateForDevice()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getScancodeState(devid, sw);
}
-
+
public int getKeycodeState(int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getKeycodeState()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getKeycodeState(sw);
}
-
+
public int getKeycodeStateForDevice(int devid, int sw) {
if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
"getKeycodeStateForDevice()")) {
- return -1;
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
}
return KeyInputQueue.getKeycodeState(devid, sw);
}
-
+
public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
return KeyInputQueue.hasKeys(keycodes, keyExists);
}
-
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (mSystemBooted) {
@@ -3225,10 +3252,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
mSystemBooted = true;
}
-
+
performEnableScreen();
}
-
+
public void enableScreenIfNeededLocked() {
if (mDisplayEnabled) {
return;
@@ -3238,7 +3265,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
}
-
+
public void performEnableScreen() {
synchronized(mWindowMap) {
if (mDisplayEnabled) {
@@ -3247,7 +3274,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!mSystemBooted) {
return;
}
-
+
// Don't enable the screen until all existing windows
// have been drawn.
final int N = mWindows.size();
@@ -3257,7 +3284,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return;
}
}
-
+
mDisplayEnabled = true;
if (false) {
Log.i(TAG, "ENABLING SCREEN!");
@@ -3280,41 +3307,41 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
}
-
+
mPolicy.enableScreenAfterBoot();
-
+
// Make sure the last requested orientation has been applied.
setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
}
-
+
public void setInTouchMode(boolean mode) {
synchronized(mWindowMap) {
mInTouchMode = mode;
}
}
- public void setRotation(int rotation,
+ public void setRotation(int rotation,
boolean alwaysSendConfiguration, int animFlags) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"setRotation()")) {
- return;
+ throw new SecurityException("Requires SET_ORIENTATION permission");
}
setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
}
-
+
public void setRotationUnchecked(int rotation,
boolean alwaysSendConfiguration, int animFlags) {
if(DEBUG_ORIENTATION) Log.v(TAG,
"alwaysSendConfiguration set to "+alwaysSendConfiguration);
-
+
long origId = Binder.clearCallingIdentity();
boolean changed;
synchronized(mWindowMap) {
changed = setRotationUncheckedLocked(rotation, animFlags);
}
-
+
if (changed) {
sendNewConfiguration();
synchronized(mWindowMap) {
@@ -3325,10 +3352,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//update configuration ignoring orientation change
sendNewConfiguration();
}
-
+
Binder.restoreCallingIdentity(origId);
}
-
+
public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
boolean changed;
if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
@@ -3342,9 +3369,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mRotation, mDisplayEnabled);
if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
changed = mDisplayEnabled && mRotation != rotation;
-
+
if (changed) {
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Log.v(TAG,
"Rotation changed to " + rotation
+ " from " + mRotation
+ " (forceApp=" + mForcedAppOrientation
@@ -3373,10 +3400,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
} //end if changed
-
+
return changed;
}
-
+
public int getRotation() {
return mRotation;
}
@@ -3388,14 +3415,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (mWindowMap) {
for (int i=0; i<mRotationWatchers.size(); i++) {
if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
- mRotationWatchers.remove(i);
+ IRotationWatcher removed = mRotationWatchers.remove(i);
+ if (removed != null) {
+ removed.asBinder().unlinkToDeath(this, 0);
+ }
i--;
}
}
}
}
};
-
+
synchronized (mWindowMap) {
try {
watcher.asBinder().linkToDeath(dr, 0);
@@ -3403,7 +3433,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RemoteException e) {
// Client died, no cleanup needed.
}
-
+
return mRotation;
}
}
@@ -3419,7 +3449,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* @see com.android.server.ViewServer#VIEW_SERVER_DEFAULT_PORT
*/
public boolean startViewServer(int port) {
- if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
+ if (isSystemSecure()) {
return false;
}
@@ -3436,7 +3466,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
try {
return mViewServer.start();
} catch (IOException e) {
- Log.w(TAG, "View server did not start");
+ Log.w(TAG, "View server did not start");
}
}
return false;
@@ -3451,6 +3481,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return false;
}
+ private boolean isSystemSecure() {
+ return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
+ "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ }
+
/**
* Stops the view server if it exists.
*
@@ -3460,7 +3495,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* @see com.android.server.ViewServer
*/
public boolean stopViewServer() {
- if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
+ if (isSystemSecure()) {
return false;
}
@@ -3482,7 +3517,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* @see com.android.server.ViewServer
*/
public boolean isViewServerRunning() {
- if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
+ if (isSystemSecure()) {
return false;
}
@@ -3503,7 +3538,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* @return False if an error occured, true otherwise.
*/
boolean viewServerListWindows(Socket client) {
- if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
+ if (isSystemSecure()) {
return false;
}
@@ -3570,7 +3605,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* not indicate whether the command itself was successful.
*/
boolean viewServerWindowCommand(Socket client, String command, String parameters) {
- if ("1".equals(SystemProperties.get(SYSTEM_SECURE, "0"))) {
+ if (isSystemSecure()) {
return false;
}
@@ -3660,13 +3695,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RemoteException e) {
}
}
-
+
public Configuration computeNewConfiguration() {
synchronized (mWindowMap) {
return computeNewConfigurationLocked();
}
}
-
+
Configuration computeNewConfigurationLocked() {
Configuration config = new Configuration();
if (!computeNewConfigurationLocked(config)) {
@@ -3687,7 +3722,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return config;
}
-
+
boolean computeNewConfigurationLocked(Configuration config) {
if (mDisplay == null) {
return false;
@@ -3702,12 +3737,46 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
config.orientation = orientation;
+
+ if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+ // Note we only do this once because at this point we don't
+ // expect the screen to change in this way at runtime, and want
+ // to avoid all of this computation for every config change.
+ DisplayMetrics dm = new DisplayMetrics();
+ mDisplay.getMetrics(dm);
+ int longSize = dw;
+ int shortSize = dh;
+ if (longSize < shortSize) {
+ int tmp = longSize;
+ longSize = shortSize;
+ shortSize = tmp;
+ }
+ longSize = (int)(longSize/dm.density);
+ shortSize = (int)(shortSize/dm.density);
+
+ // These semi-magic numbers define our compatibility modes for
+ // applications with different screens. Don't change unless you
+ // make sure to test lots and lots of apps!
+ if (longSize < 470) {
+ // This is shorter than an HVGA normal density screen (which
+ // is 480 pixels on its long side).
+ screenLayout = Configuration.SCREENLAYOUT_SMALL;
+ } else if (longSize > 490 && shortSize > 330) {
+ // This is larger than an HVGA normal density screen (which
+ // is 480x320 pixels).
+ screenLayout = Configuration.SCREENLAYOUT_LARGE;
+ } else {
+ screenLayout = Configuration.SCREENLAYOUT_NORMAL;
+ }
+ }
+ config.screenLayout = screenLayout;
+
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
mPolicy.adjustConfigurationLw(config);
return true;
}
-
+
// -------------------------------------------------------------
// Input Events and Focus Management
// -------------------------------------------------------------
@@ -3771,15 +3840,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
/**
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
- private boolean dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
+ private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
"dispatchPointer " + ev);
Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
- ev, true, false);
-
+ ev, true, false, pid, uid);
+
int action = ev.getAction();
-
+
if (action == MotionEvent.ACTION_UP) {
// let go of our target
mKeyWaiter.mMotionTarget = null;
@@ -3801,20 +3870,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.recycleEvent(qev);
}
ev.recycle();
- return false;
+ return INJECT_FAILED;
}
if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
if (qev != null) {
mQueue.recycleEvent(qev);
}
ev.recycle();
- return true;
+ return INJECT_SUCCEEDED;
}
-
+
WindowState target = (WindowState)targetObj;
-
+
final long eventTime = ev.getEventTime();
-
+
//Log.i(TAG, "Sending " + ev + " to " + target);
if (uid != 0 && uid != target.mSession.mUid) {
@@ -3828,11 +3897,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.recycleEvent(qev);
}
ev.recycle();
- return false;
+ return INJECT_NO_PERMISSION;
}
}
-
- if ((target.mAttrs.flags &
+
+ if ((target.mAttrs.flags &
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
//target wants to ignore fat touch events
boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
@@ -3859,7 +3928,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if(mFatTouch) {
//two cases here
//an invalid down followed by 0 or moves(valid or invalid)
- //a valid down, invalid move, more moves. want to ignore till up
+ //a valid down, invalid move, more moves. want to ignore till up
returnFlag = true;
} else if(cheekPress) {
//valid down followed by invalid moves
@@ -3878,7 +3947,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.recycleEvent(qev);
}
ev.recycle();
- return false;
+ return INJECT_FAILED;
}
} //end if target
@@ -3944,7 +4013,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mKeyWaiter.bindTargetWindowLocked(target);
}
}
-
+
// finally offset the event to the target's coordinate system and
// dispatch the event.
try {
@@ -3952,7 +4021,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, "Delivering pointer " + qev + " to " + target);
}
target.mClient.dispatchPointer(ev, eventTime);
- return true;
+ return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
mKeyWaiter.mMotionTarget = null;
@@ -3963,36 +4032,36 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// removed.
}
}
- return false;
+ return INJECT_FAILED;
}
-
+
/**
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
- private boolean dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
+ private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
if (DEBUG_INPUT) Log.v(
TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
-
+
Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
- ev, false, false);
+ ev, false, false, pid, uid);
if (focusObj == null) {
Log.w(TAG, "No focus window, dropping trackball: " + ev);
if (qev != null) {
mQueue.recycleEvent(qev);
}
ev.recycle();
- return false;
+ return INJECT_FAILED;
}
if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
if (qev != null) {
mQueue.recycleEvent(qev);
}
ev.recycle();
- return true;
+ return INJECT_SUCCEEDED;
}
-
+
WindowState focus = (WindowState)focusObj;
-
+
if (uid != 0 && uid != focus.mSession.mUid) {
if (mContext.checkPermission(
android.Manifest.permission.INJECT_EVENTS, pid, uid)
@@ -4004,12 +4073,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.recycleEvent(qev);
}
ev.recycle();
- return false;
+ return INJECT_NO_PERMISSION;
}
}
-
+
final long eventTime = ev.getEventTime();
-
+
synchronized(mWindowMap) {
if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(focus,
@@ -4021,10 +4090,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mKeyWaiter.bindTargetWindowLocked(focus);
}
}
-
+
try {
focus.mClient.dispatchTrackball(ev, eventTime);
- return true;
+ return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
try {
@@ -4034,28 +4103,28 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// removed.
}
}
-
- return false;
+
+ return INJECT_FAILED;
}
-
+
/**
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
- private boolean dispatchKey(KeyEvent event, int pid, int uid) {
+ private int dispatchKey(KeyEvent event, int pid, int uid) {
if (DEBUG_INPUT) Log.v(TAG, "Dispatch key: " + event);
Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
- null, false, false);
+ null, false, false, pid, uid);
if (focusObj == null) {
Log.w(TAG, "No focus window, dropping: " + event);
- return false;
+ return INJECT_FAILED;
}
if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
- return true;
+ return INJECT_SUCCEEDED;
}
-
+
WindowState focus = (WindowState)focusObj;
-
+
if (DEBUG_INPUT) Log.v(
TAG, "Dispatching to " + focus + ": " + event);
@@ -4066,10 +4135,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.w(TAG, "Permission denied: injecting key event from pid "
+ pid + " uid " + uid + " to window " + focus
+ " owned by uid " + focus.mSession.mUid);
- return false;
+ return INJECT_NO_PERMISSION;
}
}
-
+
synchronized(mWindowMap) {
mKeyWaiter.bindTargetWindowLocked(focus);
}
@@ -4077,14 +4146,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// NOSHIP extra state logging
mKeyWaiter.recordDispatchState(event, focus);
// END NOSHIP
-
+
try {
if (DEBUG_INPUT || DEBUG_FOCUS) {
Log.v(TAG, "Delivering key " + event.getKeyCode()
+ " to " + focus);
}
focus.mClient.dispatchKey(event);
- return true;
+ return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
try {
@@ -4094,14 +4163,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// removed.
}
}
-
- return false;
+
+ return INJECT_FAILED;
}
-
+
public void pauseKeyDispatching(IBinder _token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"pauseKeyDispatching()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized (mWindowMap) {
@@ -4115,7 +4184,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void resumeKeyDispatching(IBinder _token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"resumeKeyDispatching()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized (mWindowMap) {
@@ -4129,18 +4198,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void setEventDispatching(boolean enabled) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"resumeKeyDispatching()")) {
- return;
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized (mWindowMap) {
mKeyWaiter.setEventDispatchingLocked(enabled);
}
}
-
+
/**
* Injects a keystroke event into the UI.
- *
- * @param ev A motion event describing the keystroke action. (Be sure to use
+ *
+ * @param ev A motion event describing the keystroke action. (Be sure to use
* {@link SystemClock#uptimeMillis()} as the timebase.)
* @param sync If true, wait for the event to be completed before returning to the caller.
* @return Returns true if event was dispatched, false if it was dropped for any reason
@@ -4162,47 +4231,80 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
- boolean result = dispatchKey(newEvent, Binder.getCallingPid(), Binder.getCallingUid());
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ final int result = dispatchKey(newEvent, pid, uid);
if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
}
- return result;
+ Binder.restoreCallingIdentity(ident);
+ switch (result) {
+ case INJECT_NO_PERMISSION:
+ throw new SecurityException(
+ "Injecting to another application requires INJECT_EVENT permission");
+ case INJECT_SUCCEEDED:
+ return true;
+ }
+ return false;
}
/**
* Inject a pointer (touch) event into the UI.
- *
- * @param ev A motion event describing the pointer (touch) action. (As noted in
- * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
+ *
+ * @param ev A motion event describing the pointer (touch) action. (As noted in
+ * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
* {@link SystemClock#uptimeMillis()} as the timebase.)
* @param sync If true, wait for the event to be completed before returning to the caller.
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
- boolean result = dispatchPointer(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ final int result = dispatchPointer(null, ev, pid, uid);
if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
+ }
+ Binder.restoreCallingIdentity(ident);
+ switch (result) {
+ case INJECT_NO_PERMISSION:
+ throw new SecurityException(
+ "Injecting to another application requires INJECT_EVENT permission");
+ case INJECT_SUCCEEDED:
+ return true;
}
- return result;
+ return false;
}
-
+
/**
* Inject a trackball (navigation device) event into the UI.
- *
- * @param ev A motion event describing the trackball action. (As noted in
- * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
+ *
+ * @param ev A motion event describing the trackball action. (As noted in
+ * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
* {@link SystemClock#uptimeMillis()} as the timebase.)
* @param sync If true, wait for the event to be completed before returning to the caller.
* @return Returns true if event was dispatched, false if it was dropped for any reason
*/
public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
- boolean result = dispatchTrackball(null, ev, Binder.getCallingPid(), Binder.getCallingUid());
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ final int result = dispatchTrackball(null, ev, pid, uid);
if (sync) {
- mKeyWaiter.waitForNextEventTarget(null, null, null, false, true);
+ mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
}
- return result;
+ Binder.restoreCallingIdentity(ident);
+ switch (result) {
+ case INJECT_NO_PERMISSION:
+ throw new SecurityException(
+ "Injecting to another application requires INJECT_EVENT permission");
+ case INJECT_SUCCEEDED:
+ return true;
+ }
+ return false;
}
-
+
private WindowState getFocusedWindow() {
synchronized (mWindowMap) {
return getFocusedWindowLocked();
@@ -4212,7 +4314,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private WindowState getFocusedWindowLocked() {
return mCurrentFocus;
}
-
+
/**
* This class holds the state for dispatching key events. This state
* is protected by the KeyWaiter instance, NOT by the window lock. You
@@ -4234,7 +4336,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private boolean wasFrozen;
private boolean focusPaused;
private WindowState curFocus;
-
+
DispatchState(KeyEvent theEvent, WindowState theFocus) {
focus = theFocus;
event = theEvent;
@@ -4256,7 +4358,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
focusPaused = theFocus.mToken.paused;
}
}
-
+
public String toString() {
return "{{" + event + " to " + focus + " @ " + time
+ " lw=" + lastWin + " lb=" + lastBinder
@@ -4275,10 +4377,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public static final int RETURN_NOTHING = 0;
public static final int RETURN_PENDING_POINTER = 1;
public static final int RETURN_PENDING_TRACKBALL = 2;
-
+
final Object SKIP_TARGET_TOKEN = new Object();
final Object CONSUMED_EVENT_TOKEN = new Object();
-
+
private WindowState mLastWin = null;
private IBinder mLastBinder = null;
private boolean mFinished = true;
@@ -4286,10 +4388,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private boolean mEventDispatching = true;
private long mTimeToSwitch = 0;
/* package */ boolean mWasFrozen = false;
-
+
// Target of Motion events
WindowState mMotionTarget;
-
+
// Windows above the target who would like to receive an "outside"
// touch event for any down events outside of them.
WindowState mOutsideTouchTargets;
@@ -4301,7 +4403,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
*/
Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
MotionEvent nextMotion, boolean isPointerEvent,
- boolean failIfTimeout) {
+ boolean failIfTimeout, int callingPid, int callingUid) {
long startTime = SystemClock.uptimeMillis();
long keyDispatchingTimeout = 5 * 1000;
long waitedFor = 0;
@@ -4319,7 +4421,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
", mLastWin=" + mLastWin);
if (targetIsNew) {
Object target = findTargetWindow(nextKey, qev, nextMotion,
- isPointerEvent);
+ isPointerEvent, callingPid, callingUid);
if (target == SKIP_TARGET_TOKEN) {
// The user has pressed a special key, and we are
// dropping all pending events before it.
@@ -4334,9 +4436,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
targetWin = (WindowState)target;
}
-
+
AppWindowToken targetApp = null;
-
+
// Now: is it okay to send the next event to this window?
synchronized (this) {
// First: did we come here based on the last window not
@@ -4345,7 +4447,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!targetIsNew && mLastWin == null) {
continue;
}
-
+
// We never dispatch events if not finished with the
// last one, or the display is frozen.
if (mFinished && !mDisplayFrozen) {
@@ -4364,7 +4466,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (targetIsNew && !targetWin.mToken.paused) {
return targetWin;
}
-
+
// If we didn't find a target window, and there is no
// focused app window, then just eat the events.
} else if (mFocusedApp == null) {
@@ -4374,7 +4476,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return null;
}
}
-
+
if (DEBUG_INPUT) Log.v(
TAG, "Waiting for last key in " + mLastBinder
+ " target=" + targetWin
@@ -4385,10 +4487,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ (targetWin != null ? targetWin.mToken.paused : false)
+ " mFocusedApp=" + mFocusedApp
+ " mCurrentFocus=" + mCurrentFocus);
-
+
targetApp = targetWin != null
? targetWin.mAppToken : mFocusedApp;
-
+
long curTimeout = keyDispatchingTimeout;
if (mTimeToSwitch != 0) {
long now = SystemClock.uptimeMillis();
@@ -4404,7 +4506,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
curTimeout = switchTimeout;
}
}
-
+
try {
// after that continue
// processing keys, so we don't get stuck.
@@ -4468,7 +4570,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (this) {
if (abort && (mLastWin == targetWin || targetWin == null)) {
mFinished = true;
- if (mLastWin != null) {
+ if (mLastWin != null) {
if (DEBUG_INPUT) Log.v(TAG,
"Window " + mLastWin +
" timed out on key input");
@@ -4493,41 +4595,56 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
- MotionEvent nextMotion, boolean isPointerEvent) {
+ MotionEvent nextMotion, boolean isPointerEvent,
+ int callingPid, int callingUid) {
mOutsideTouchTargets = null;
-
+
if (nextKey != null) {
// Find the target window for a normal key event.
final int keycode = nextKey.getKeyCode();
final int repeatCount = nextKey.getRepeatCount();
final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
+
if (!dispatch) {
- mPolicy.interceptKeyTi(null, keycode,
- nextKey.getMetaState(), down, repeatCount);
+ if (callingUid == 0 ||
+ mContext.checkPermission(
+ android.Manifest.permission.INJECT_EVENTS,
+ callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ mPolicy.interceptKeyTi(null, keycode,
+ nextKey.getMetaState(), down, repeatCount);
+ }
Log.w(TAG, "Event timeout during app switch: dropping "
+ nextKey);
return SKIP_TARGET_TOKEN;
}
-
+
// System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
-
+
WindowState focus = null;
synchronized(mWindowMap) {
focus = getFocusedWindowLocked();
}
-
+
wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-
- if (mPolicy.interceptKeyTi(focus,
- keycode, nextKey.getMetaState(), down, repeatCount)) {
- return CONSUMED_EVENT_TOKEN;
+
+ if (callingUid == 0 ||
+ (focus != null && callingUid == focus.mSession.mUid) ||
+ mContext.checkPermission(
+ android.Manifest.permission.INJECT_EVENTS,
+ callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ if (mPolicy.interceptKeyTi(focus,
+ keycode, nextKey.getMetaState(), down, repeatCount)) {
+ return CONSUMED_EVENT_TOKEN;
+ }
}
-
+
return focus;
-
+
} else if (!isPointerEvent) {
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
if (!dispatch) {
@@ -4535,20 +4652,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ nextMotion);
return SKIP_TARGET_TOKEN;
}
-
+
WindowState focus = null;
synchronized(mWindowMap) {
focus = getFocusedWindowLocked();
}
-
+
wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
return focus;
}
-
+
if (nextMotion == null) {
return SKIP_TARGET_TOKEN;
}
-
+
boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
KeyEvent.KEYCODE_UNKNOWN);
if (!dispatch) {
@@ -4556,18 +4673,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ nextMotion);
return SKIP_TARGET_TOKEN;
}
-
+
// Find the target window for a pointer event.
int action = nextMotion.getAction();
final float xf = nextMotion.getX();
final float yf = nextMotion.getY();
final long eventTime = nextMotion.getEventTime();
-
+
final boolean screenWasOff = qev != null
&& (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
-
+
WindowState target = null;
-
+
synchronized(mWindowMap) {
synchronized (this) {
if (action == MotionEvent.ACTION_DOWN) {
@@ -4580,12 +4697,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ mMotionTarget);
mMotionTarget = null;
}
-
+
// ACTION_DOWN is special, because we need to lock next events to
// the window we'll land onto.
final int x = (int)xf;
final int y = (int)yf;
-
+
final ArrayList windows = mWindows;
final int N = windows.size();
WindowState topErrWindow = null;
@@ -4646,7 +4763,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
break;
}
-
+
if ((flags & WindowManager.LayoutParams
.FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
child.mNextOutsideTouch = mOutsideTouchTargets;
@@ -4663,18 +4780,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mMotionTarget = null;
}
}
-
+
target = mMotionTarget;
}
}
-
+
wakeupIfNeeded(target, eventType(nextMotion));
-
+
// Pointer events are a little different -- if there isn't a
// target found for any event, then just drop it.
return target != null ? target : SKIP_TARGET_TOKEN;
}
-
+
boolean checkShouldDispatchKey(int keycode) {
synchronized (this) {
if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
@@ -4688,14 +4805,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return true;
}
}
-
+
void bindTargetWindowLocked(WindowState win,
int pendingWhat, QueuedEvent pendingMotion) {
synchronized (this) {
bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
}
}
-
+
void bindTargetWindowLocked(WindowState win) {
synchronized (this) {
bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
@@ -4713,7 +4830,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
releasePendingPointerLocked(s);
s.mPendingPointerMove = pendingMotion;
s.mPendingPointerWindow = win;
- if (DEBUG_INPUT) Log.v(TAG,
+ if (DEBUG_INPUT) Log.v(TAG,
"bindTargetToWindow " + s.mPendingPointerMove);
} else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
releasePendingTrackballLocked(s);
@@ -4722,7 +4839,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
void releasePendingPointerLocked(Session s) {
if (DEBUG_INPUT) Log.v(TAG,
"releasePendingPointer " + s.mPendingPointerMove);
@@ -4731,14 +4848,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
s.mPendingPointerMove = null;
}
}
-
+
void releasePendingTrackballLocked(Session s) {
if (s.mPendingTrackballMove != null) {
mQueue.recycleEvent(s.mPendingTrackballMove);
s.mPendingTrackballMove = null;
}
}
-
+
MotionEvent finishedKey(Session session, IWindow client, boolean force,
int returnWhat) {
if (DEBUG_INPUT) Log.v(
@@ -4767,7 +4884,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
session.mPendingTrackballMove = null;
session.mPendingTrackballWindow = null;
}
-
+
if (mLastBinder == client.asBinder()) {
if (DEBUG_INPUT) Log.v(
TAG, "finishedKey: last paused="
@@ -4783,7 +4900,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
notifyAll();
}
}
-
+
if (qev != null) {
MotionEvent res = (MotionEvent)qev.event;
if (DEBUG_INPUT) Log.v(TAG,
@@ -4803,7 +4920,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
notifyAll();
}
}
-
+
void handleNewWindowLocked(WindowState newWindow) {
if (!newWindow.canReceiveKeys()) {
return;
@@ -4904,7 +5021,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
notifyAll();
}
}
-
+
void appSwitchComing() {
synchronized (this) {
// Don't wait for more than .5 seconds for app to finish
@@ -4917,13 +5034,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
notifyAll();
}
}
-
+
private final void doFinishedKeyLocked(boolean doRecycle) {
if (mLastWin != null) {
releasePendingPointerLocked(mLastWin.mSession);
releasePendingTrackballLocked(mLastWin.mSession);
}
-
+
if (mLastWin == null || !mLastWin.mToken.paused
|| !mLastWin.isVisibleLw()) {
// If the current window has been paused, we aren't -really-
@@ -4939,7 +5056,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private class KeyQ extends KeyInputQueue
implements KeyInputQueue.FilterCallback {
PowerManager.WakeLock mHoldingScreen;
-
+
KeyQ() {
super(mContext);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
@@ -4953,7 +5070,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mPolicy.preprocessInputEventTq(event)) {
return true;
}
-
+
switch (event.type) {
case RawInputEvent.EV_KEY: {
// XXX begin hack
@@ -4973,11 +5090,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
// XXX end hack
-
+
boolean screenIsOff = !mPowerManager.screenIsOn();
boolean screenIsDim = !mPowerManager.screenIsBright();
int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
-
+
if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
mPowerManager.goToSleep(event.when);
}
@@ -4992,7 +5109,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mPowerManager.userActivity(event.when, false,
LocalPowerManager.BUTTON_EVENT, false);
}
-
+
if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
filterQueue(this);
@@ -5003,7 +5120,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return false;
}
}
-
+
case RawInputEvent.EV_REL: {
boolean screenIsOff = !mPowerManager.screenIsOn();
boolean screenIsDim = !mPowerManager.screenIsBright();
@@ -5020,7 +5137,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return true;
}
-
+
case RawInputEvent.EV_ABS: {
boolean screenIsOff = !mPowerManager.screenIsOn();
boolean screenIsDim = !mPowerManager.screenIsBright();
@@ -5037,7 +5154,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return true;
}
-
+
default:
return true;
}
@@ -5057,7 +5174,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return FILTER_KEEP;
}
}
-
+
/**
* Must be called with the main window manager lock held.
*/
@@ -5078,11 +5195,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mSafeMode = mPolicy.detectSafeMode();
return mSafeMode;
}
-
+
public void systemReady() {
mPolicy.systemReady();
}
-
+
private final class InputDispatcherThread extends Thread {
// Time to wait when there is nothing to do: 9999 seconds.
static final int LONG_WAIT=9999*1000;
@@ -5090,7 +5207,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public InputDispatcherThread() {
super("InputDispatcher");
}
-
+
@Override
public void run() {
while (true) {
@@ -5101,11 +5218,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
private void process() {
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
+
// The last key event we saw
KeyEvent lastKey = null;
@@ -5113,12 +5230,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
long lastKeyTime = SystemClock.uptimeMillis();
long nextKeyTime = lastKeyTime+LONG_WAIT;
- // How many successive repeats we generated
+ // How many successive repeats we generated
int keyRepeatCount = 0;
// Need to report that configuration has changed?
boolean configChanged = false;
-
+
while (true) {
long curTime = SystemClock.uptimeMillis();
@@ -5199,14 +5316,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mQueue.recycleEvent(ev);
break;
}
-
+
} else if (configChanged) {
configChanged = false;
sendNewConfiguration();
-
+
} else if (lastKey != null) {
curTime = SystemClock.uptimeMillis();
-
+
// Timeout occurred while key was down. If it is at or
// past the key repeat time, dispatch the repeat.
if (DEBUG_INPUT) Log.v(
@@ -5215,7 +5332,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (curTime < nextKeyTime) {
continue;
}
-
+
lastKeyTime = nextKeyTime;
nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
keyRepeatCount++;
@@ -5223,14 +5340,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "Key repeat: count=" + keyRepeatCount
+ ", next @ " + nextKeyTime);
dispatchKey(KeyEvent.changeTimeRepeat(lastKey, curTime, keyRepeatCount), 0, 0);
-
+
} else {
curTime = SystemClock.uptimeMillis();
-
+
lastKeyTime = curTime;
nextKeyTime = curTime + LONG_WAIT;
}
-
+
} catch (Exception e) {
Log.e(TAG,
"Input thread received uncaught exception: " + e, e);
@@ -5253,14 +5370,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
SurfaceSession mSurfaceSession;
int mNumWindow = 0;
boolean mClientDead = false;
-
+
/**
* Current pointer move event being dispatched to client window... must
* hold key lock to access.
*/
QueuedEvent mPendingPointerMove;
WindowState mPendingPointerWindow;
-
+
/**
* Current trackball move event being dispatched to client window... must
* hold key lock to access.
@@ -5280,7 +5397,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
sb.append(mUid);
sb.append("}");
mStringName = sb.toString();
-
+
synchronized (mWindowMap) {
if (mInputMethodManager == null && mHaveInputMethods) {
IBinder b = ServiceManager.getService(
@@ -5311,7 +5428,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Binder.restoreCallingIdentity(ident);
}
}
-
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -5336,6 +5453,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RemoteException e) {
}
synchronized(mWindowMap) {
+ mClient.asBinder().unlinkToDeath(this, 0);
mClientDead = true;
killSessionLocked();
}
@@ -5345,11 +5463,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int viewVisibility, Rect outContentInsets) {
return addWindow(this, window, attrs, viewVisibility, outContentInsets);
}
-
+
public void remove(IWindow window) {
removeWindow(this, window);
}
-
+
public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
boolean insetsPending, Rect outFrame, Rect outContentInsets,
@@ -5358,21 +5476,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
requestedWidth, requestedHeight, viewFlags, insetsPending,
outFrame, outContentInsets, outVisibleInsets, outSurface);
}
-
+
public void setTransparentRegion(IWindow window, Region region) {
setTransparentRegionWindow(this, window, region);
}
-
+
public void setInsets(IWindow window, int touchableInsets,
Rect contentInsets, Rect visibleInsets) {
setInsetsWindow(this, window, touchableInsets, contentInsets,
visibleInsets);
}
-
+
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
getWindowDisplayFrame(this, window, outDisplayFrame);
}
-
+
public void finishDrawing(IWindow window) {
if (localLOGV) Log.v(
TAG, "IWindow finishDrawing called for " + window);
@@ -5392,7 +5510,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return mKeyWaiter.finishedKey(this, window, false,
KeyWaiter.RETURN_PENDING_POINTER);
}
-
+
public MotionEvent getPendingTrackballMove(IWindow window) {
if (localLOGV) Log.v(
TAG, "IWindow getPendingMotionEvent called for " + window);
@@ -5424,7 +5542,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -5439,7 +5557,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mNumWindow--;
killSessionLocked();
}
-
+
void killSessionLocked() {
if (mNumWindow <= 0 && mClientDead) {
mSessions.remove(this);
@@ -5458,7 +5576,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
pw.print(" mClientDead="); pw.print(mClientDead);
@@ -5519,11 +5637,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean mHaveFrame;
WindowState mNextOutsideTouch;
-
+
// Actual frame shown on-screen (may be modified by animation)
final Rect mShownFrame = new Rect();
final Rect mLastShownFrame = new Rect();
-
+
/**
* Insets that determine the actually visible area
*/
@@ -5543,19 +5661,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* given internal insets before laying out other windows based on it.
*/
boolean mGivenInsetsPending;
-
+
/**
* These are the content insets that were given during layout for
* this window, to be applied to windows behind it.
*/
final Rect mGivenContentInsets = new Rect();
-
+
/**
* These are the visible insets that were given during layout for
* this window, to be applied to windows behind it.
*/
final Rect mGivenVisibleInsets = new Rect();
-
+
/**
* Flag indicating whether the touchable region should be adjusted by
* the visible insets; if false the area outside the visible insets is
@@ -5563,7 +5681,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* tests.
*/
int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
-
+
// Current transformation being applied.
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
@@ -5602,7 +5720,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// where we don't yet have a surface, but should have one soon, so
// we can give the window focus before waiting for the relayout.
boolean mRelayoutCalled;
-
+
// This is set after the Surface has been created but before the
// window has been drawn. During this time the surface is hidden.
boolean mDrawPending;
@@ -5617,7 +5735,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// to delay showing the surface until all windows in a token are ready
// to be shown.
boolean mReadyToShow;
-
+
// Set when the window has been shown in the screen the first time.
boolean mHasDrawn;
@@ -5626,17 +5744,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Currently on the mDestroySurface list?
boolean mDestroying;
-
+
// Completely remove from window manager after exit animation?
boolean mRemoveOnExit;
// Set when the orientation is changing and this window has not yet
// been updated for the new orientation.
boolean mOrientationChanging;
-
+
// Is this window now (or just being) removed?
boolean mRemoved;
-
+
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
@@ -5662,7 +5780,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return;
}
mDeathRecipient = deathRecipient;
-
+
if ((mAttrs.type >= FIRST_SUB_WINDOW &&
mAttrs.type <= LAST_SUB_WINDOW)) {
// The multiplier here is to reserve space for multiple
@@ -5738,7 +5856,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
w = mAttrs.width == mAttrs.FILL_PARENT ? pw : mRequestedWidth;
h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
}
-
+
final Rect container = mContainingFrame;
container.set(pf);
@@ -5747,12 +5865,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Rect content = mContentFrame;
content.set(cf);
-
+
final Rect visible = mVisibleFrame;
visible.set(vf);
-
+
final Rect frame = mFrame;
-
+
//System.out.println("In: w=" + w + " h=" + h + " container=" +
// container + " x=" + mAttrs.x + " y=" + mAttrs.y);
@@ -5764,7 +5882,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// 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;
@@ -5775,19 +5893,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (visible.top < frame.top) visible.top = frame.top;
if (visible.right > frame.right) visible.right = frame.right;
if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
-
+
final Rect contentInsets = mContentInsets;
contentInsets.left = content.left-frame.left;
contentInsets.top = content.top-frame.top;
contentInsets.right = frame.right-content.right;
contentInsets.bottom = frame.bottom-content.bottom;
-
+
final Rect visibleInsets = mVisibleInsets;
visibleInsets.left = visible.left-frame.left;
visibleInsets.top = visible.top-frame.top;
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
-
+
if (localLOGV) {
//if ("com.google.android.youtube".equals(mAttrs.packageName)
// && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
@@ -5800,7 +5918,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//}
}
}
-
+
public Rect getFrameLw() {
return mFrame;
}
@@ -5828,11 +5946,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public Rect getGivenContentInsetsLw() {
return mGivenContentInsets;
}
-
+
public Rect getGivenVisibleInsetsLw() {
return mGivenVisibleInsets;
}
-
+
public WindowManager.LayoutParams getAttrs() {
return mAttrs;
}
@@ -5840,7 +5958,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public int getSurfaceLayer() {
return mLayer;
}
-
+
public IApplicationToken getAppToken() {
return mAppToken != null ? mAppToken.appToken : null;
}
@@ -5874,7 +5992,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAnimation = null;
}
}
-
+
Surface createSurfaceLocked() {
if (mSurface == null) {
mDrawPending = true;
@@ -5914,7 +6032,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
try {
mSurface = new Surface(
- mSession.mSurfaceSession, mSession.mPid,
+ mSession.mSurfaceSession, mSession.mPid,
0, w, h, mAttrs.format, flags);
} catch (Surface.OutOfResourcesException e) {
Log.w(TAG, "OutOfResourcesException creating surface");
@@ -5924,7 +6042,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.e(TAG, "Exception creating surface", e);
return null;
}
-
+
if (localLOGV) Log.v(
TAG, "Got surface: " + mSurface
+ ", set left=" + mFrame.left + " top=" + mFrame.top
@@ -5961,7 +6079,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return mSurface;
}
-
+
void destroySurfaceLocked() {
// Window is no longer on-screen, so can no longer receive
// key events... if we were waiting for it to finish
@@ -5974,7 +6092,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mAppToken != null && this == mAppToken.startingWindow) {
mAppToken.startingDisplayed = false;
}
-
+
if (localLOGV) Log.v(
TAG, "Window " + this
+ " destroying surface " + mSurface + ", session " + mSession);
@@ -6064,7 +6182,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
enableScreenIfNeededLocked();
applyEnterAnimationLocked(this);
-
+
int i = mChildWindows.size();
while (i > 0) {
i--;
@@ -6074,7 +6192,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
c.performShowLocked();
}
}
-
+
if (mAttrs.type != TYPE_APPLICATION_STARTING
&& mAppToken != null) {
mAppToken.firstWindowDrawn = true;
@@ -6090,13 +6208,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return true;
}
-
+
// This must be called while inside a transaction. Returns true if
// there is more animation to run.
boolean stepAnimationLocked(long currentTime, int dw, int dh) {
if (!mDisplayFrozen) {
// We will run animations as long as the display isn't frozen.
-
+
if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
mHasTransformation = true;
mHasLocalTransformation = true;
@@ -6154,7 +6272,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mLocalAnimating = true;
mAnimation = null;
}
-
+
if (!mAnimating && !mLocalAnimating) {
return false;
}
@@ -6163,7 +6281,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "Animation done in " + this + ": exiting=" + mExiting
+ ", reportedVisible="
+ (mAppToken != null ? mAppToken.reportedVisible : false));
-
+
mAnimating = false;
mLocalAnimating = false;
mAnimation = null;
@@ -6187,7 +6305,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mFinishedStarting.add(mAppToken);
mH.sendEmptyMessage(H.FINISHED_STARTING);
}
-
+
finishExit();
if (mAppToken != null) {
@@ -6203,16 +6321,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ ": exiting=" + mExiting
+ " remove=" + mRemoveOnExit
+ " windowAnimating=" + isWindowAnimating());
-
+
final int N = mChildWindows.size();
for (int i=0; i<N; i++) {
((WindowState)mChildWindows.get(i)).finishExit();
}
-
+
if (!mExiting) {
return;
}
-
+
if (isWindowAnimating()) {
return;
}
@@ -6239,7 +6357,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mRemoveOnExit = false;
}
}
-
+
boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
if (dsdx < .99999f || dsdx > 1.00001f) return false;
if (dtdy < .99999f || dtdy > 1.00001f) return false;
@@ -6247,7 +6365,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (dsdy < -.000001f || dsdy > .000001f) return false;
return true;
}
-
+
void computeShownFrameLocked() {
final boolean selfTransformation = mHasLocalTransformation;
Transformation attachedTransformation =
@@ -6258,7 +6376,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
? mAppToken.transformation : null;
if (selfTransformation || attachedTransformation != null
|| appTransformation != null) {
- // cache often used attributes locally
+ // cache often used attributes locally
final Rect frame = mFrame;
final float tmpFloats[] = mTmpFloats;
final Matrix tmpMatrix = mTmpMatrix;
@@ -6280,7 +6398,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Here we must not transform the position of the surface
// since it is already included in the transformation.
//Log.i(TAG, "Transform: " + matrix);
-
+
tmpMatrix.getValues(tmpFloats);
mDsDx = tmpFloats[Matrix.MSCALE_X];
mDtDx = tmpFloats[Matrix.MSKEW_X];
@@ -6315,14 +6433,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
//Log.i(TAG, "Not applying alpha transform");
}
-
+
if (localLOGV) Log.v(
TAG, "Continuing animation in " + this +
": " + mShownFrame +
", alpha=" + mTransformation.getAlpha());
return;
}
-
+
mShownFrame.set(mFrame);
mShownAlpha = mAlpha;
mDsDx = 1;
@@ -6330,7 +6448,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mDsDy = 0;
mDtDy = 1;
}
-
+
/**
* Is this window visible? It is not visible if there is no
* surface, or we are in the process of running an exit animation
@@ -6393,7 +6511,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
&& (!mAttachedHidden || mAnimating);
}
}
-
+
/**
* Like isOnScreen(), but we don't return true if the window is part
* of a transition that has not yet been started.
@@ -6412,7 +6530,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final AppWindowToken atoken = mAppToken;
return mAnimation != null
|| (attached != null && attached.mAnimation != null)
- || (atoken != null &&
+ || (atoken != null &&
(atoken.animation != null
|| atoken.inPendingTransaction));
}
@@ -6454,7 +6572,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return false;
}
-
+
boolean isFullscreenOpaque(int screenWidth, int screenHeight) {
if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null
|| mAnimation != null || mDrawPending || mCommitDrawPending) {
@@ -6546,7 +6664,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
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);
@@ -6662,7 +6780,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
}
}
-
+
// -------------------------------------------------------------
// Window Token State
// -------------------------------------------------------------
@@ -6673,17 +6791,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// The type of window this token is for, as per WindowManager.LayoutParams.
final int windowType;
-
+
// Set if this token was explicitly added by a client, so should
// not be removed when all windows are removed.
final boolean explicit;
-
+
// For printing.
String stringName;
-
+
// If this is an AppWindowToken, this is non-null.
AppWindowToken appWindowToken;
-
+
// All of the windows associated with this token.
final ArrayList<WindowState> windows = new ArrayList<WindowState>();
@@ -6734,7 +6852,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
+
// These are used for determining when all windows associated with
// an activity have been drawn, so they can be made visible together
// at the same time.
@@ -6743,20 +6861,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int numDrawnWindows;
boolean inPendingTransaction;
boolean allDrawn;
-
+
// Is this token going to be hidden in a little while? If so, it
// won't be taken into account for setting the screen orientation.
boolean willBeHidden;
-
+
// Is this window's surface needed? This is almost like hidden, except
// it will sometimes be true a little earlier: when the token has
// been shown, but is still waiting for its app transition to execute
// before making its windows shown.
boolean hiddenRequested;
-
+
// Have we told the window clients to hide themselves?
boolean clientHidden;
-
+
// Last visibility state we reported to the app token.
boolean reportedVisible;
@@ -6765,16 +6883,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Have we been asked to have this token keep the screen frozen?
boolean freezingScreen;
-
+
boolean animating;
Animation animation;
boolean hasTransformation;
final Transformation transformation = new Transformation();
-
+
// Offset to the window of all layers in the token, for use by
// AppWindowToken animations.
int animLayerAdjustment;
-
+
// Information about an application starting window if displayed.
StartingData startingData;
WindowState startingWindow;
@@ -6789,7 +6907,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
appWindowToken = this;
appToken = _token;
}
-
+
public void setAnimation(Animation anim) {
if (localLOGV) Log.v(
TAG, "Setting animation in " + this + ": " + anim);
@@ -6804,13 +6922,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else if (zorder == Animation.ZORDER_BOTTOM) {
adj = -TYPE_LAYER_OFFSET;
}
-
+
if (animLayerAdjustment != adj) {
animLayerAdjustment = adj;
updateLayers();
}
}
-
+
public void setDummyAnimation() {
if (animation == null) {
if (localLOGV) Log.v(
@@ -6825,7 +6943,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
animating = true;
}
}
-
+
void updateLayers() {
final int N = allAppWindows.size();
final int adj = animLayerAdjustment;
@@ -6839,7 +6957,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
void sendAppVisibilityToClients() {
final int N = allAppWindows.size();
for (int i=0; i<N; i++) {
@@ -6856,7 +6974,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
void showAllWindowsLocked() {
final int NW = allAppWindows.size();
for (int i=0; i<NW; i++) {
@@ -6866,12 +6984,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
w.performShowLocked();
}
}
-
+
// This must be called while inside a transaction.
boolean stepAnimationLocked(long currentTime, int dw, int dh) {
if (!mDisplayFrozen) {
// We will run animations as long as the display isn't frozen.
-
+
if (animation == sDummyAnimation) {
// This guy is going to animate, but not yet. For now count
// it is not animating for purposes of scheduling transactions;
@@ -6879,7 +6997,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// a real animation and the next call will execute normally.
return false;
}
-
+
if ((allDrawn || animating || startingDisplayed) && animation != null) {
if (!animating) {
if (DEBUG_ANIM) Log.v(
@@ -6915,7 +7033,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
hasTransformation = false;
-
+
if (!animating) {
return false;
}
@@ -6925,7 +7043,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
moveInputMethodWindowsIfNeededLocked(true);
}
-
+
if (DEBUG_ANIM) Log.v(
TAG, "Animation done in " + this
+ ": reportedVisible=" + reportedVisible);
@@ -6935,13 +7053,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
animLayerAdjustment = 0;
updateLayers();
}
-
+
final int N = windows.size();
for (int i=0; i<N; i++) {
((WindowState)windows.get(i)).finishExit();
}
updateReportedVisibilityLocked();
-
+
return false;
}
@@ -6949,11 +7067,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (appToken == null) {
return;
}
-
+
int numInteresting = 0;
int numVisible = 0;
boolean nowGone = true;
-
+
if (DEBUG_VISIBILITY) Log.v(TAG, "Update reported visibility: " + this);
final int N = allAppWindows.size();
for (int i=0; i<N; i++) {
@@ -6987,7 +7105,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
nowGone = false;
}
}
-
+
boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
if (DEBUG_VISIBILITY) Log.v(TAG, "VIS " + this + ": interesting="
+ numInteresting + " visible=" + numVisible);
@@ -7004,7 +7122,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.sendMessage(m);
}
}
-
+
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
@@ -7069,7 +7187,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return stringName;
}
}
-
+
public static WindowManager.LayoutParams findAnimations(
ArrayList<AppWindowToken> order,
ArrayList<AppWindowToken> tokenList1,
@@ -7077,7 +7195,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// We need to figure out which animation to use...
WindowManager.LayoutParams animParams = null;
int animSrc = 0;
-
+
//Log.i(TAG, "Looking for animations...");
for (int i=order.size()-1; i>=0; i--) {
AppWindowToken wtoken = order.get(i);
@@ -7106,10 +7224,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
return animParams;
}
-
+
// -------------------------------------------------------------
// DummyAnimation
// -------------------------------------------------------------
@@ -7123,7 +7241,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
static final Animation sDummyAnimation = new DummyAnimation();
-
+
// -------------------------------------------------------------
// Async Handler
// -------------------------------------------------------------
@@ -7134,7 +7252,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final CharSequence nonLocalizedLabel;
final int labelRes;
final int icon;
-
+
StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel,
int _labelRes, int _icon) {
pkg = _pkg;
@@ -7161,19 +7279,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
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;
-
+
private Session mLastReportedHold;
-
+
public H() {
}
-
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case REPORT_FOCUS_CHANGE: {
WindowState lastFocus;
WindowState newFocus;
-
+
synchronized(mWindowMap) {
lastFocus = mLastFocus;
newFocus = mCurrentFocus;
@@ -7217,7 +7335,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
case REPORT_LOSING_FOCUS: {
ArrayList<WindowState> losers;
-
+
synchronized(mWindowMap) {
losers = mLosingFocus;
mLosingFocus = new ArrayList<WindowState>();
@@ -7249,10 +7367,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Animation has been canceled... do nothing.
return;
}
-
+
if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Add starting "
+ wtoken + ": pkg=" + sd.pkg);
-
+
View view = null;
try {
view = mPolicy.addStartingWindow(
@@ -7379,7 +7497,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RemoteException ex) {
}
} break;
-
+
case WINDOW_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Log.w(TAG, "Window freeze timeout expired.");
@@ -7396,7 +7514,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
break;
}
-
+
case HOLD_SCREEN_CHANGED: {
Session oldHold;
Session newHold;
@@ -7405,7 +7523,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
newHold = (Session)msg.obj;
mLastReportedHold = newHold;
}
-
+
if (oldHold != newHold) {
try {
if (oldHold != null) {
@@ -7423,7 +7541,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
break;
}
-
+
case APP_TRANSITION_TIMEOUT: {
synchronized (mWindowMap) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
@@ -7436,7 +7554,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
break;
}
-
+
case PERSIST_ANIMATION_SCALE: {
Settings.System.putFloat(mContext.getContentResolver(),
Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
@@ -7444,7 +7562,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
break;
}
-
+
case FORCE_GC: {
synchronized(mWindowMap) {
if (mAnimationPending) {
@@ -7464,12 +7582,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Runtime.getRuntime().gc();
break;
}
-
+
case ENABLE_SCREEN: {
performEnableScreen();
break;
}
-
+
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Log.w(TAG, "App freeze timeout expired.");
@@ -7485,14 +7603,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
break;
}
-
+
case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
- if (updateOrientationFromAppTokens(null, null) != null) {
+ if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
sendNewConfiguration();
}
break;
}
-
+
}
}
}
@@ -7526,7 +7644,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return false;
}
-
+
// -------------------------------------------------------------
// Internals
// -------------------------------------------------------------
@@ -7534,7 +7652,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final WindowState windowForClientLocked(Session session, IWindow client) {
return windowForClientLocked(session, client.asBinder());
}
-
+
final WindowState windowForClientLocked(Session session, IBinder client) {
WindowState win = mWindowMap.get(client);
if (localLOGV) Log.v(
@@ -7559,7 +7677,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int curBaseLayer = 0;
int curLayer = 0;
int i;
-
+
for (i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
@@ -7615,11 +7733,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
mInLayout = true;
try {
performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
-
+
int i = mPendingRemove.size()-1;
if (i >= 0) {
while (i >= 0) {
@@ -7655,7 +7773,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int i;
// FIRST LOOP: Perform a layout, if needed.
-
+
while (mLayoutNeeded) {
mPolicy.beginLayoutLw(dw, dh);
@@ -7690,7 +7808,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
// 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
@@ -7721,7 +7839,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
private final void performLayoutAndPlaceSurfacesLockedInner(
boolean recoveringMemory) {
final long currentTime = SystemClock.uptimeMillis();
@@ -7732,13 +7850,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int i;
// FIRST LOOP: Perform a layout, if needed.
-
performLayoutLockedInner();
-
+
if (mFxSession == null) {
mFxSession = new SurfaceSession();
}
-
+
if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
// Initialize state of exiting tokens.
@@ -7752,7 +7869,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
// SECOND LOOP: Execute animations and update visibility of windows.
-
boolean orientationChangeComplete = true;
Session holdScreen = null;
float screenBrightness = -1;
@@ -8063,7 +8179,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged =
!w.mLastVisibleInsets.equals(w.mVisibleInsets);
- if (!w.mLastFrame.equals(w.mFrame)
+ if (!w.mLastFrame.equals(w.mFrame)
|| w.mContentInsetsChanged
|| w.mVisibleInsetsChanged) {
w.mLastFrame.set(w.mFrame);
@@ -8085,7 +8201,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
w.mAppToken.allDrawn = false;
}
}
- if (DEBUG_ORIENTATION) Log.v(TAG,
+ if (DEBUG_ORIENTATION) Log.v(TAG,
"Resizing window " + w + " to " + w.mFrame);
mResizingWindows.add(w);
} else if (w.mOrientationChanging) {
@@ -8275,7 +8391,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ mDimSurface + ": CREATE");
try {
- mDimSurface = new Surface(mFxSession, 0,
+ mDimSurface = new Surface(mFxSession, 0,
-1, 16, 16,
PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
@@ -8330,7 +8446,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
+ mBlurSurface + ": CREATE");
try {
- mBlurSurface = new Surface(mFxSession, 0,
+ mBlurSurface = new Surface(mFxSession, 0,
-1, 16, 16,
PixelFormat.OPAQUE,
Surface.FX_SURFACE_BLUR);
@@ -8384,7 +8500,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
more = false;
}
-
+
// Do we need to continue animating?
if (more) {
if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
@@ -8410,7 +8526,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
if (!blurring && mBlurShown) {
if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
+ ": HIDE");
@@ -8428,7 +8544,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
Surface.closeTransaction();
-
+
if (DEBUG_ORIENTATION && mDisplayFrozen) Log.v(TAG,
"With display frozen, orientationChangeComplete="
+ orientationChangeComplete);
@@ -8441,7 +8557,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
stopFreezingDisplayLocked();
}
}
-
+
i = mResizingWindows.size();
if (i > 0) {
do {
@@ -8459,7 +8575,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} while (i > 0);
mResizingWindows.clear();
}
-
+
// Destroy the surface of any windows that are no longer visible.
i = mDestroySurface.size();
if (i > 0) {
@@ -8518,13 +8634,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
}
}
-
+
/**
* Have the surface flinger show a surface, robustly dealing with
* error conditions. In particular, if there is not enough memory
* to show the surface, then we will try to get rid of other surfaces
* in order to succeed.
- *
+ *
* @return Returns true if the surface was successfully shown.
*/
boolean showSurfaceRobustlyLocked(WindowState win) {
@@ -8536,22 +8652,22 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RuntimeException e) {
Log.w(TAG, "Failure showing surface " + win.mSurface + " in " + win);
}
-
+
reclaimSomeSurfaceMemoryLocked(win, "show");
-
+
return false;
}
-
+
void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) {
final Surface surface = win.mSurface;
-
+
EventLog.writeEvent(LOG_WM_NO_SURFACE_MEMORY, win.toString(),
win.mSession.mPid, operation);
-
+
if (mForceRemoves == null) {
mForceRemoves = new ArrayList<WindowState>();
}
-
+
long callingIdentity = Binder.clearCallingIdentity();
try {
// There was some problem... first, do a sanity check of the
@@ -8585,7 +8701,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
boolean killedApps = false;
if (!leakedSurface) {
Log.w(TAG, "No leaked surfaces; killing applicatons!");
@@ -8609,7 +8725,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
+
if (leakedSurface || killedApps) {
// We managed to reclaim some memory, so get rid of the trouble
// surface and ask the app to request another one.
@@ -8618,7 +8734,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
surface.clear();
win.mSurface = null;
}
-
+
try {
win.mClient.dispatchGetNewSurface();
} catch (RemoteException e) {
@@ -8628,7 +8744,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Binder.restoreCallingIdentity(callingIdentity);
}
}
-
+
private boolean updateFocusedWindowLocked(int mode) {
WindowState newFocus = computeFocusedWindowLocked();
if (mCurrentFocus != newFocus) {
@@ -8641,7 +8757,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
-
+
final WindowState imWindow = mInputMethodWindow;
if (newFocus != imWindow && oldFocus != imWindow) {
if (moveInputMethodWindowsIfNeededLocked(
@@ -8657,7 +8773,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
assignLayersLocked();
}
}
-
+
if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
mKeyWaiter.handleNewWindowLocked(newFocus);
}
@@ -8685,13 +8801,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ ", canReceive=" + win.canReceiveKeys());
AppWindowToken thisApp = win.mAppToken;
-
+
// If this window's application has been removed, just skip it.
if (thisApp != null && thisApp.removed) {
i--;
continue;
}
-
+
// If there is a focused app, don't allow focus to go to any
// windows below it. If this is an application window, step
// through the app tokens until we find its app.
@@ -8748,9 +8864,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
return;
}
-
+
mScreenFrozenLock.acquire();
-
+
long now = SystemClock.uptimeMillis();
//Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
if (mFreezeGcPending != 0) {
@@ -8763,32 +8879,32 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
mFreezeGcPending = now;
}
-
+
mDisplayFrozen = true;
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
mAppTransitionReady = true;
}
-
+
if (PROFILE_ORIENTATION) {
File file = new File("/data/system/frozen");
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
Surface.freezeDisplay(0);
}
-
+
private void stopFreezingDisplayLocked() {
if (!mDisplayFrozen) {
return;
}
-
+
mDisplayFrozen = false;
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
if (PROFILE_ORIENTATION) {
Debug.stopMethodTracing();
}
Surface.unfreezeDisplay(0);
-
+
// Reset the key delivery timeout on unfreeze, too. We force a wakeup here
// too because regular key delivery processing should resume immediately.
synchronized (mKeyWaiter) {
@@ -8804,10 +8920,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.removeMessages(H.FORCE_GC);
mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
2000);
-
+
mScreenFrozenLock.release();
}
-
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
@@ -8817,7 +8933,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ ", uid=" + Binder.getCallingUid());
return;
}
-
+
synchronized(mWindowMap) {
pw.println("Current Window Manager state:");
for (int i=mWindows.size()-1; i>=0; i--) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9471eff..2fe4dd4 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,7 +17,7 @@
package com.android.server.am;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.RuntimeInit;
+import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
import com.android.server.ProcessStats;
@@ -30,22 +30,25 @@ import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AlertDialog;
+import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
-import android.app.IIntentReceiver;
-import android.app.IIntentSender;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.app.ResultInfo;
+import android.backup.IBackupManager;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -78,6 +81,9 @@ 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;
@@ -92,10 +98,13 @@ 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.PrintWriter;
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
@@ -117,11 +126,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
+ static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_SERVICE = localLOGV || false;
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PROCESSES = localLOGV || false;
static final boolean DEBUG_USER_LEAVING = localLOGV || false;
static final boolean DEBUG_RESULTS = localLOGV || false;
+ static final boolean DEBUG_BACKUP = localLOGV || true;
static final boolean VALIDATE_TOKENS = false;
static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -191,6 +202,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Maximum number of recent tasks that we can remember.
static final int MAX_RECENT_TASKS = 20;
+ // Amount of time after a call to stopAppSwitches() during which we will
+ // prevent further untrusted switches from happening.
+ static final long APP_SWITCH_DELAY_TIME = 5*1000;
+
// How long until we reset a task when the user returns to it. Currently
// 30 minutes.
static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
@@ -273,6 +288,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// because the user interacts with it so much.
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;
+
// 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.
@@ -301,6 +320,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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;
@@ -328,6 +348,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final ArrayList mHistory = new ArrayList();
/**
+ * Description of a request to start a new activity, which has been held
+ * due to app switches being disabled.
+ */
+ class PendingActivityLaunch {
+ HistoryRecord r;
+ HistoryRecord sourceRecord;
+ Uri[] grantedUriPermissions;
+ int grantedMode;
+ boolean onlyIfNeeded;
+ }
+
+ final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
+ = new ArrayList<PendingActivityLaunch>();
+
+ /**
* 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
@@ -605,6 +640,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
= new ArrayList<ServiceRecord>();
/**
+ * Backup/restore process management
+ */
+ String mBackupAppName = null;
+ BackupRecord mBackupTarget = null;
+
+ /**
* List of PendingThumbnailsRecord objects of clients who are still
* waiting to receive all of the thumbnails for a task.
*/
@@ -704,6 +745,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int mFactoryTest;
+ boolean mCheckedForSetup;
+
+ /**
+ * The time at which we will allow normal application switches again,
+ * after a call to {@link #stopAppSwitches()}.
+ */
+ long mAppSwitchesAllowedTime;
+
+ /**
+ * This is set to true after the first switch after mAppSwitchesAllowedTime
+ * is set; any switches after that will clear the time.
+ */
+ boolean mDidAppSwitch;
+
/**
* Set while we are wanting to sleep, to prevent any
* activities from being started/resumed.
@@ -757,6 +812,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
int[] mProcDeaths = new int[20];
+ /**
+ * This is set if we had to do a delayed dexopt of an app before launching
+ * it, to increasing the ANR timeouts in that case.
+ */
+ boolean mDidDexOpt;
+
String mDebugApp = null;
boolean mWaitForDebugger = false;
boolean mDebugTransient = false;
@@ -852,6 +913,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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;
AlertDialog mUidAlert;
@@ -910,6 +972,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
d.show();
proc.anrDialog = d;
}
+
+ ensureScreenEnabled();
} break;
case SHOW_FACTORY_ERROR_MSG: {
Dialog d = new FactoryErrorDialog(
@@ -952,6 +1016,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
+ mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
+ return;
+ }
broadcastTimeout();
} break;
case PAUSE_TIMEOUT_MSG: {
@@ -962,9 +1032,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activityPaused(token, null, true);
} break;
case IDLE_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
+ return;
+ }
// 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);
activityIdleInternal(token, true);
} break;
@@ -980,6 +1057,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
activityIdle(token);
} break;
case SERVICE_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
+ return;
+ }
serviceTimeout((ProcessRecord)msg.obj);
} break;
case UPDATE_TIME_ZONE: {
@@ -1016,6 +1100,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} break;
case LAUNCH_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
+ mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
+ return;
+ }
synchronized (ActivityManagerService.this) {
if (mLaunchingActivity.isHeld()) {
Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
@@ -1036,11 +1126,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
case PROC_START_TIMEOUT_MSG: {
+ if (mDidDexOpt) {
+ mDidDexOpt = false;
+ Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ nmsg.obj = msg.obj;
+ mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
+ return;
+ }
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
processStartTimedOutLocked(app);
}
}
+ case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
+ synchronized (ActivityManagerService.this) {
+ doPendingActivityLaunchesLocked(true);
+ }
+ }
}
}
};
@@ -1301,6 +1403,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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 =
@@ -1316,6 +1420,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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 =
@@ -1382,7 +1488,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (mProcessStatsThread) {
final long now = SystemClock.uptimeMillis();
boolean haveNewCpuStats = false;
-
+
if (MONITOR_CPU_USAGE &&
mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
mLastCpuTime = now;
@@ -1414,7 +1520,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- synchronized(mBatteryStatsService.getActiveStatistics()) {
+ final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
+ synchronized(bstats) {
synchronized(mPidsSelfLocked) {
if (haveNewCpuStats) {
if (mBatteryStatsService.isOnBattery()) {
@@ -1426,12 +1533,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (pr != null) {
BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+ } else {
+ BatteryStatsImpl.Uid.Proc ps =
+ bstats.getProcessStatsLocked(st.name, st.pid);
+ if (ps != null) {
+ ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+ }
}
}
}
}
}
-
+
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
mBatteryStatsService.getActiveStatistics().writeLocked();
@@ -1495,6 +1608,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return null;
}
+ private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
+ int i = mHistory.size()-1;
+ while (i >= 0) {
+ HistoryRecord r = (HistoryRecord)mHistory.get(i);
+ if (!r.finishing && !r.delayedResume && r != notTop) {
+ return r;
+ }
+ i--;
+ }
+ return null;
+ }
+
/**
* This is a simplified version of topRunningActivityLocked that provides a number of
* optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
@@ -1531,6 +1656,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return proc;
}
+ private void ensurePackageDexOpt(String packageName) {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ try {
+ if (pm.performDexOpt(packageName)) {
+ mDidDexOpt = true;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
private boolean isNextTransitionForward() {
int transit = mWindowManager.getPendingAppTransition();
return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
@@ -1590,6 +1725,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r.isHomeActivity) {
mHomeProcess = app;
}
+ ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
@@ -1640,6 +1776,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.stopped = true;
}
+ // Launch the new version setup screen if needed. We do this -after-
+ // launching the initial activity (that is, home), so that it can have
+ // a chance to initialize itself while in the background, making the
+ // switch back to it faster and look better.
+ startSetupActivityLocked();
+
return true;
}
@@ -1995,6 +2137,25 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (prev != null) {
prev.resumeKeyDispatchingLocked();
}
+
+ if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
+ long diff = 0;
+ synchronized (mProcessStatsThread) {
+ diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
+ }
+ if (diff > 0) {
+ BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
+ synchronized (bsi) {
+ BatteryStatsImpl.Uid.Proc ps =
+ bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
+ prev.info.packageName);
+ if (ps != null) {
+ ps.addForegroundTimeLocked(diff);
+ }
+ }
+ }
+ }
+ prev.cpuTimeAtResume = 0; // reset it
}
/**
@@ -2027,6 +2188,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
next.resumeKeyDispatchingLocked();
ensureActivitiesVisibleLocked(null, 0);
mWindowManager.executeAppTransition();
+
+ // Mark the point when the activity is resuming
+ // TODO: To be more accurate, the mark should be before the onCreate,
+ // not after the onResume. But for subsequent starts, onResume is fine.
+ if (next.app != null) {
+ synchronized (mProcessStatsThread) {
+ next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
+ }
+ } else {
+ next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
+ }
}
/**
@@ -2191,6 +2363,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ private boolean startHomeActivityLocked() {
+ if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
+ && mTopAction == null) {
+ // We are running in factory test mode, but unable to find
+ // the factory test app, so just sit around displaying the
+ // error message and don't try to start anything.
+ return false;
+ }
+ Intent intent = new Intent(
+ mTopAction,
+ mTopData != null ? Uri.parse(mTopData) : null);
+ intent.setComponent(mTopComponent);
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ intent.addCategory(Intent.CATEGORY_HOME);
+ }
+ ActivityInfo aInfo =
+ intent.resolveActivityInfo(mContext.getPackageManager(),
+ STOCK_PM_FLAGS);
+ if (aInfo != null) {
+ intent.setComponent(new ComponentName(
+ aInfo.applicationInfo.packageName, aInfo.name));
+ // Don't do this if the home app is currently being
+ // instrumented.
+ ProcessRecord app = getProcessRecordLocked(aInfo.processName,
+ aInfo.applicationInfo.uid);
+ if (app == null || app.instrumentationClass == null) {
+ intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivityLocked(null, intent, null, null, 0, aInfo,
+ null, null, 0, 0, 0, false, false);
+ }
+ }
+
+
+ return true;
+ }
+
+ /**
+ * Starts the "new version setup screen" if appropriate.
+ */
+ private void startSetupActivityLocked() {
+ // Only do this once per boot.
+ if (mCheckedForSetup) {
+ return;
+ }
+
+ // We will show this screen if the current one is a different
+ // version than the last one shown, and we are not running in
+ // low-level factory test mode.
+ final ContentResolver resolver = mContext.getContentResolver();
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
+ Settings.Secure.getInt(resolver,
+ Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
+ mCheckedForSetup = true;
+
+ // See if we should be showing the platform update setup UI.
+ Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
+ List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.GET_META_DATA);
+
+ // We don't allow third party apps to replace this.
+ ResolveInfo ri = null;
+ for (int i=0; ris != null && i<ris.size(); i++) {
+ if ((ris.get(i).activityInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ ri = ris.get(i);
+ break;
+ }
+ }
+
+ if (ri != null) {
+ String vers = ri.activityInfo.metaData != null
+ ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
+ : null;
+ if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
+ vers = ri.activityInfo.applicationInfo.metaData.getString(
+ Intent.METADATA_SETUP_VERSION);
+ }
+ String lastVers = Settings.Secure.getString(
+ resolver, Settings.Secure.LAST_SETUP_SHOWN);
+ if (vers != null && !vers.equals(lastVers)) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(new ComponentName(
+ ri.activityInfo.packageName, ri.activityInfo.name));
+ startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
+ null, null, 0, 0, 0, false, false);
+ }
+ }
+ }
+ }
+
/**
* Ensure that the top activity in the stack is resumed.
*
@@ -2212,39 +2474,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
- if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
- && mTopAction == null) {
- // We are running in factory test mode, but unable to find
- // the factory test app, so just sit around displaying the
- // error message and don't try to start anything.
- return false;
- }
- Intent intent = new Intent(
- mTopAction,
- mTopData != null ? Uri.parse(mTopData) : null);
- intent.setComponent(mTopComponent);
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- intent.addCategory(Intent.CATEGORY_HOME);
- }
- ActivityInfo aInfo =
- intent.resolveActivityInfo(mContext.getPackageManager(),
- STOCK_PM_FLAGS);
- if (aInfo != null) {
- intent.setComponent(new ComponentName(
- aInfo.applicationInfo.packageName, aInfo.name));
- // Don't do this if the home app is currently being
- // instrumented.
- ProcessRecord app = getProcessRecordLocked(aInfo.processName,
- aInfo.applicationInfo.uid);
- if (app == null || app.instrumentationClass == null) {
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityLocked(null, intent, null, null, 0, aInfo,
- null, null, 0, 0, 0, false, false);
- }
- }
- return true;
+ return startHomeActivityLocked();
}
+ next.delayedResume = false;
+
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
// Make sure we have executed any pending transitions, since there
@@ -2471,7 +2705,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
- private final void startActivityLocked(HistoryRecord r, boolean newTask) {
+ private final void startActivityLocked(HistoryRecord r, boolean newTask,
+ boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
@@ -2558,7 +2793,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if ((r.intent.getFlags()
&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
- doShow = topRunningActivityLocked(null) == r;
+ doShow = topRunningNonDelayedActivityLocked(null) == r;
}
}
if (SHOW_APP_STARTING_ICON && doShow) {
@@ -2588,13 +2823,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWindowManager.validateAppTokens(mHistory);
}
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
}
/**
* Perform clear operation as requested by
- * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: assuming the top task on the
- * stack is the one that the new activity is being launched in, look for
+ * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
+ * stack to the given task, then look for
* an instance of that activity in the stack and, if found, finish all
* activities on top of it and return the instance.
*
@@ -2602,9 +2839,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* @return Returns the old activity that should be continue to be used,
* or null if none was found.
*/
- private final HistoryRecord performClearTopTaskLocked(int taskId,
+ private final HistoryRecord performClearTaskLocked(int taskId,
HistoryRecord newR, boolean doClear) {
int i = mHistory.size();
+
+ // First find the requested task.
+ while (i > 0) {
+ i--;
+ HistoryRecord r = (HistoryRecord)mHistory.get(i);
+ if (r.task.taskId == taskId) {
+ i++;
+ break;
+ }
+ }
+
+ // Now clear it.
while (i > 0) {
i--;
HistoryRecord r = (HistoryRecord)mHistory.get(i);
@@ -2636,7 +2885,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// instance of the activity so a new fresh one can be started.
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret, false);
+ int index = indexOfTokenLocked(ret);
if (index >= 0) {
finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
null, "clear");
@@ -2729,7 +2978,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord sourceRecord = null;
HistoryRecord resultRecord = null;
if (resultTo != null) {
- int index = indexOfTokenLocked(resultTo, false);
+ int index = indexOfTokenLocked(resultTo);
if (DEBUG_RESULTS) Log.v(
TAG, "Sending result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
@@ -2840,15 +3089,75 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
intent, resolvedType, aInfo, mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
- HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
- != 0 ? r : null;
-
+ if (mResumedActivity == null
+ || mResumedActivity.info.applicationInfo.uid != callingUid) {
+ if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
+ PendingActivityLaunch pal = new PendingActivityLaunch();
+ pal.r = r;
+ pal.sourceRecord = sourceRecord;
+ pal.grantedUriPermissions = grantedUriPermissions;
+ pal.grantedMode = grantedMode;
+ pal.onlyIfNeeded = onlyIfNeeded;
+ mPendingActivityLaunches.add(pal);
+ return START_SWITCHES_CANCELED;
+ }
+ }
+
+ if (mDidAppSwitch) {
+ // This is the second allowed switch since we stopped switches,
+ // so now just generally allow switches. Use case: user presses
+ // home (switches disabled, switch to home, mDidAppSwitch now true);
+ // user taps a home icon (coming from home so allowed, we hit here
+ // and now allow anyone to switch again).
+ mAppSwitchesAllowedTime = 0;
+ } else {
+ mDidAppSwitch = true;
+ }
+
+ doPendingActivityLaunchesLocked(false);
+
+ return startActivityUncheckedLocked(r, sourceRecord,
+ grantedUriPermissions, grantedMode, onlyIfNeeded, true);
+ }
+
+ private final void doPendingActivityLaunchesLocked(boolean doResume) {
+ final int N = mPendingActivityLaunches.size();
+ if (N <= 0) {
+ return;
+ }
+ for (int i=0; i<N; i++) {
+ PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
+ startActivityUncheckedLocked(pal.r, pal.sourceRecord,
+ pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
+ doResume && i == (N-1));
+ }
+ mPendingActivityLaunches.clear();
+ }
+
+ private final int startActivityUncheckedLocked(HistoryRecord r,
+ HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
+ int grantedMode, boolean onlyIfNeeded, boolean doResume) {
+ final Intent intent = r.intent;
+ final int callingUid = r.launchedFromUid;
+
+ int launchFlags = intent.getFlags();
+
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Log.v(TAG,
"startActivity() => mUserLeaving=" + mUserLeaving);
+ // If the caller has asked not to resume at this point, we make note
+ // of this in the record so that we can skip it when trying to find
+ // the top running activity.
+ if (!doResume) {
+ r.delayedResume = true;
+ }
+
+ HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
+ != 0 ? r : null;
+
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
@@ -2856,7 +3165,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (onlyIfNeeded) {
HistoryRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
- checkedCaller = topRunningActivityLocked(notTop);
+ checkedCaller = topRunningNonDelayedActivityLocked(notTop);
}
if (!checkedCaller.realActivity.equals(r.realActivity)) {
// Caller is not the same as launcher, so always needed.
@@ -2894,7 +3203,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
- if (resultRecord != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new
// task... yet the caller has requested a result back. Well, that
// is pretty messed up, so instead immediately send back a cancel
@@ -2902,10 +3211,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// dependency on its originator.
Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
+ r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
- resultRecord = null;
}
boolean addingToTask = false;
@@ -2916,7 +3224,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If bring to front is requested, and no result is requested, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
- if (resultRecord == null) {
+ if (r.resultTo == null) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
@@ -2938,7 +3246,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// to have the same behavior as if a new instance was
// being started, which means not bringing it to the front
// if the caller is not itself in the front.
- HistoryRecord curTop = topRunningActivityLocked(notTop);
+ HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop.task != taskTop.task) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
boolean callerAtFront = sourceRecord == null
@@ -2959,7 +3267,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// the client said not to do anything if that
// is the case, so this is it! And for paranoia, make
// sure we have correctly resumed the top activity.
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
return START_RETURN_INTENT_TO_CALLER;
}
if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
@@ -2969,7 +3279,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// from the task up to the one being started. In most
// cases this means we are resetting the task to its
// initial state.
- HistoryRecord top = performClearTopTaskLocked(
+ HistoryRecord top = performClearTaskLocked(
taskTop.task.taskId, r, true);
if (top != null) {
if (top.frontOfTask) {
@@ -3035,7 +3345,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We didn't do anything... but it was needed (a.k.a., client
// don't use that intent!) And for paranoia, make
// sure we have correctly resumed the top activity.
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
return START_TASK_TO_FRONT;
}
}
@@ -3052,8 +3364,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the activity being launched is the same as the one currently
// at the top, then we need to check if it should only be launched
// once.
- HistoryRecord top = topRunningActivityLocked(notTop);
- if (top != null && resultRecord == null) {
+ HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
+ if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity)) {
if (top.app != null && top.app.thread != null) {
if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
@@ -3062,7 +3374,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
if (onlyIfNeeded) {
// We don't need to start a new activity, and
// the client said not to do anything if that
@@ -3077,9 +3391,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} else {
- if (resultRecord != null) {
+ if (r.resultTo != null) {
sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
+ r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
}
return START_CLASS_NOT_FOUND;
@@ -3088,7 +3402,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean newTask = false;
// Should this be considered a new task?
- if (resultRecord == null && !addingToTask
+ if (r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// todo: should do better management of integers.
mCurTask++;
@@ -3108,14 +3422,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// In this case, we are adding the activity to an existing
// task, but the caller has asked to clear that task if the
// activity is already running.
- HistoryRecord top = performClearTopTaskLocked(
+ HistoryRecord top = performClearTaskLocked(
sourceRecord.task.taskId, r, true);
if (top != null) {
logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
return START_DELIVERED_TO_TOP;
}
} else if (!addingToTask &&
@@ -3128,7 +3444,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord top = moveActivityToFrontLocked(where);
logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
- resumeTopActivityLocked(null);
+ if (doResume) {
+ resumeTopActivityLocked(null);
+ }
return START_DELIVERED_TO_TOP;
}
}
@@ -3157,7 +3475,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
}
logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
- startActivityLocked(r, newTask);
+ startActivityLocked(r, newTask, doResume);
return START_SUCCESS;
}
@@ -3226,7 +3544,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized (this) {
- int index = indexOfTokenLocked(callingActivity, false);
+ int index = indexOfTokenLocked(callingActivity);
if (index < 0) {
return false;
}
@@ -3376,7 +3694,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public void setRequestedOrientation(IBinder token,
int requestedOrientation) {
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -3398,7 +3716,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public int getRequestedOrientation(IBinder token) {
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
@@ -3454,7 +3772,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
TAG, "Finishing activity: token=" + token
+ ", result=" + resultCode + ", data=" + resultData);
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return false;
}
@@ -3578,7 +3896,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
int mode) {
- final int index = indexOfTokenLocked(r, false);
+ final int index = indexOfTokenLocked(r);
if (index < 0) {
return null;
}
@@ -3703,7 +4021,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -4253,7 +4571,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
- int index = indexOfTokenLocked(token, true);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -4523,6 +4841,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mPendingBroadcast = null;
scheduleBroadcastsLocked();
}
+ if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
+ Log.w(TAG, "Unattached app died before backup, skipping");
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // Can't happen; the backup manager is local
+ }
+ }
} else {
Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
}
@@ -4587,6 +4915,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.thread = thread;
app.curAdj = app.setAdj = -100;
+ app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false;
@@ -4610,11 +4939,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWaitForDebugger = mOrigWaitForDebugger;
}
}
+ // If the app is being launched for restore or full backup, set it up specially
+ boolean isRestrictedBackupMode = false;
+ if (mBackupTarget != null && mBackupAppName.equals(processName)) {
+ isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
+ || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
+ }
+ ensurePackageDexOpt(app.instrumentationInfo != null
+ ? app.instrumentationInfo.packageName
+ : app.info.packageName);
+ if (app.instrumentationClass != null) {
+ ensurePackageDexOpt(app.instrumentationClass.getPackageName());
+ }
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
- mConfiguration, getCommonServicesLocked());
+ isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
updateLRUListLocked(app, false);
app.lastRequestedGc = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -4695,6 +5036,18 @@ 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);
+ ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
+ try {
+ thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
+ } catch (Exception e) {
+ Log.w(TAG, "Exception scheduling backup agent creation: ");
+ e.printStackTrace();
+ }
+ }
+
if (badApp) {
// todo: Also need to kill application to deal with all
// kinds of exceptions.
@@ -4790,7 +5143,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
// Get the activity record.
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
@@ -4911,6 +5264,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ final void ensureScreenEnabled() {
+ boolean enableScreen;
+ synchronized (this) {
+ enableScreen = !mBooted;
+ mBooted = true;
+ }
+
+ if (enableScreen) {
+ EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
+ SystemClock.uptimeMillis());
+ enableScreenAfterBoot();
+ }
+ }
+
public final void activityPaused(IBinder token, Bundle icicle) {
// Refuse possible leaked file descriptors
if (icicle != null && icicle.hasFileDescriptors()) {
@@ -4930,7 +5297,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord r = null;
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
r = (HistoryRecord)mHistory.get(index);
if (!timeout) {
@@ -4961,7 +5328,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
r = (HistoryRecord)mHistory.get(index);
r.thumbnail = thumbnail;
@@ -4991,7 +5358,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
if (r.state == ActivityState.DESTROYING) {
@@ -5018,7 +5385,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private HistoryRecord getCallingRecordLocked(IBinder token) {
- int index = indexOfTokenLocked(token, true);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
if (r != null) {
@@ -5030,7 +5397,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public ComponentName getActivityClassForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
return r.intent.getComponent();
@@ -5041,7 +5408,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public String getPackageForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
return r.packageName;
@@ -5080,7 +5447,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
HistoryRecord activity = null;
if (type == INTENT_SENDER_ACTIVITY_RESULT) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return null;
}
@@ -6251,6 +6618,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
"moveTaskToFront()");
synchronized(this) {
+ if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+ Binder.getCallingUid(), "Task to front")) {
+ return;
+ }
final long origId = Binder.clearCallingIdentity();
try {
int N = mRecentTasks.size();
@@ -6335,6 +6706,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
"moveTaskToBack()");
synchronized(this) {
+ if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
+ if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+ Binder.getCallingUid(), "Task to back")) {
+ return;
+ }
+ }
final long origId = Binder.clearCallingIdentity();
moveTaskToBackLocked(task);
Binder.restoreCallingIdentity(origId);
@@ -6438,6 +6815,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
"moveTaskBackwards()");
synchronized(this) {
+ if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+ Binder.getCallingUid(), "Task backwards")) {
+ return;
+ }
final long origId = Binder.clearCallingIdentity();
moveTaskBackwardsLocked(task);
Binder.restoreCallingIdentity(origId);
@@ -6587,7 +6968,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
if (r == null) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -6670,6 +7051,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
app.pubProviders.put(cpi.name, cpr);
app.addPackage(cpi.applicationInfo.packageName);
+ ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
return providers;
@@ -7179,6 +7561,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public void stopAppSwitches() {
+ if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.STOP_APP_SWITCHES);
+ }
+
+ synchronized(this) {
+ mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ + APP_SWITCH_DELAY_TIME;
+ mDidAppSwitch = false;
+ mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+ Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
+ mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
+ }
+ }
+
+ public void resumeAppSwitches() {
+ if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.STOP_APP_SWITCHES);
+ }
+
+ synchronized(this) {
+ // Note that we don't execute any pending app switches... we will
+ // let those wait until either the timeout, or the next start
+ // activity request.
+ mAppSwitchesAllowedTime = 0;
+ }
+ }
+
+ boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
+ String name) {
+ if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
+ return true;
+ }
+
+ final int perm = checkComponentPermission(
+ android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
+ callingUid, -1);
+ if (perm == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ Log.w(TAG, name + " request from " + callingUid + " stopped");
+ return false;
+ }
+
public void setDebugApp(String packageName, boolean waitForDebugger,
boolean persistent) {
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
@@ -7595,6 +8026,31 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return handleAppCrashLocked(app);
}
+ private ComponentName getErrorReportReceiver(ProcessRecord app) {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ try {
+ // was an installer package name specified when this app was
+ // installed?
+ String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
+ if (installerPackageName == null) {
+ return null;
+ }
+
+ // is there an Activity in this package that handles ACTION_APP_ERROR?
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ intent.setPackage(installerPackageName);
+ ResolveInfo info = pm.resolveIntent(intent, null, 0);
+ if (info == null || info.activityInfo == null) {
+ return null;
+ }
+
+ return new ComponentName(installerPackageName, info.activityInfo.name);
+ } catch (RemoteException e) {
+ // will return null and no error report will be delivered
+ }
+ return null;
+ }
+
void makeAppNotRespondingLocked(ProcessRecord app,
String tag, String shortMsg, String longMsg, byte[] crashData) {
app.notResponding = true;
@@ -7713,6 +8169,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void startAppProblemLocked(ProcessRecord app) {
+ app.errorReportReceiver = getErrorReportReceiver(app);
skipCurrentReceiverLocked(app);
}
@@ -7745,7 +8202,6 @@ 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;
synchronized (this) {
if (app != null) {
@@ -7834,16 +8290,103 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int res = result.get();
+ Intent appErrorIntent = null;
synchronized (this) {
if (r != null) {
mProcessCrashTimes.put(r.info.processName, r.info.uid,
SystemClock.uptimeMillis());
}
+ if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+ appErrorIntent = createAppErrorIntentLocked(r);
+ res = AppErrorDialog.FORCE_QUIT;
+ }
+ }
+
+ if (appErrorIntent != null) {
+ try {
+ mContext.startActivity(appErrorIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "bug report receiver dissappeared", e);
+ }
}
return res;
}
+ Intent createAppErrorIntentLocked(ProcessRecord r) {
+ ApplicationErrorReport report = createAppErrorReportLocked(r);
+ if (report == null) {
+ return null;
+ }
+ Intent result = new Intent(Intent.ACTION_APP_ERROR);
+ result.setComponent(r.errorReportReceiver);
+ result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+ result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return result;
+ }
+
+ ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
+ if (r.errorReportReceiver == null) {
+ return null;
+ }
+
+ if (!r.crashing && !r.notResponding) {
+ 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();
+ } 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
+ }
+
+ return null;
+ }
+
public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
// assume our apps are happy - lazy create the list
List<ActivityManager.ProcessErrorStateInfo> errList = null;
@@ -8475,9 +9018,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " #" + i + ":");
r.dump(pw, prefix + " ");
} else if (inclOomAdj) {
- pw.println(String.format("%s%s #%2d: oom_adj=%3d %s",
+ pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
prefix, (r.persistent ? persistentLabel : normalLabel),
- i, r.setAdj, r.toString()));
+ i, r.setAdj, r.setSchedGroup, r.toString()));
} else {
pw.println(String.format("%s%s #%2d: %s",
prefix, (r.persistent ? persistentLabel : normalLabel),
@@ -8540,7 +9083,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return false;
}
- private final int indexOfTokenLocked(IBinder token, boolean required) {
+ private final int indexOfTokenLocked(IBinder token) {
int count = mHistory.size();
// convert the token to an entry in the history.
@@ -8554,19 +9097,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break;
}
}
- if (index < 0 && required) {
- RuntimeInit.crash(TAG, new InvalidTokenException(token));
- }
return index;
}
- static class InvalidTokenException extends Exception {
- InvalidTokenException(IBinder token) {
- super("Bad activity token: " + token);
- }
- }
-
private final void killServicesLocked(ProcessRecord app,
boolean allowRestart) {
// Report disconnected services.
@@ -8790,6 +9324,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.receivers.clear();
}
+ // 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");
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // can't happen; backup manager is local
+ }
+ }
+
// If the caller is restarting this app, then leave it in its
// current lists and let the caller take care of it.
if (restarting) {
@@ -9130,6 +9676,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
+ ensurePackageDexOpt(r.serviceInfo.packageName);
app.thread.scheduleCreateService(r, r.serviceInfo);
created = true;
} finally {
@@ -9579,7 +10126,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord activity = null;
if (token != null) {
- int aindex = indexOfTokenLocked(token, false);
+ int aindex = indexOfTokenLocked(token);
if (aindex < 0) {
Log.w(TAG, "Binding with unknown activity: " + token);
return 0;
@@ -9906,6 +10453,128 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
// =========================================================
+ // BACKUP AND RESTORE
+ // =========================================================
+
+ // Cause the target app to be launched if necessary and its backup agent
+ // 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);
+ enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
+
+ synchronized(this) {
+ // !!! TODO: currently no check here that we're already bound
+ BatteryStatsImpl.Uid.Pkg.Serv ss = null;
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
+ }
+
+ BackupRecord r = new BackupRecord(ss, app, backupMode);
+ ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
+ // startProcessLocked() returns existing proc's record if it's already running
+ ProcessRecord proc = startProcessLocked(app.processName, app,
+ false, 0, "backup", hostingName);
+ if (proc == null) {
+ Log.e(TAG, "Unable to start backup agent process " + r);
+ return false;
+ }
+
+ r.app = proc;
+ mBackupTarget = r;
+ mBackupAppName = app.packageName;
+
+ // Try not to kill the process during backup
+ updateOomAdjLocked(proc);
+
+ // 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);
+ try {
+ proc.thread.scheduleCreateBackupAgent(app, backupMode);
+ } catch (RemoteException e) {
+ // !!! TODO: notify the backup manager that we crashed, or rely on
+ // death notices, or...?
+ }
+ } else {
+ if (DEBUG_BACKUP) Log.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
+ // mBackupAppName describe the app, so that when it binds back to the AM we
+ // know that it's scheduled for a backup-agent operation.
+ }
+
+ return true;
+ }
+
+ // A backup agent has just come up
+ public void backupAgentCreated(String agentPackageName, IBinder agent) {
+ if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
+ + " = " + agent);
+
+ synchronized(this) {
+ if (!agentPackageName.equals(mBackupAppName)) {
+ Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
+ return;
+ }
+
+ long oldIdent = Binder.clearCallingIdentity();
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentConnected(agentPackageName, agent);
+ } catch (RemoteException e) {
+ // can't happen; the backup manager service is local
+ } catch (Exception e) {
+ Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldIdent);
+ }
+ }
+ }
+
+ // done with this agent
+ public void unbindBackupAgent(ApplicationInfo appInfo) {
+ if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
+ if (appInfo == null) {
+ Log.w(TAG, "unbind backup agent for null app");
+ return;
+ }
+
+ synchronized(this) {
+ if (mBackupAppName == null) {
+ Log.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");
+ return;
+ }
+
+ ProcessRecord proc = mBackupTarget.app;
+ mBackupTarget = null;
+ mBackupAppName = null;
+
+ // Not backing this app up any more; reset its OOM adjustment
+ updateOomAdjLocked(proc);
+
+ // If the app crashed during backup, 'thread' will be null here
+ if (proc.thread != null) {
+ try {
+ proc.thread.scheduleDestroyBackupAgent(appInfo);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception when unbinding backup agent:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ // =========================================================
// BROADCASTS
// =========================================================
@@ -10078,7 +10747,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST_LIGHT) Log.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
if ((resultTo != null) && !ordered) {
@@ -10114,6 +10783,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ }
}
}
}
@@ -10176,8 +10849,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- final ContentResolver resolver = mContext.getContentResolver();
-
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
@@ -10200,8 +10871,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ActivityThread.getPackageManager().queryIntentReceivers(
intent, resolvedType, STOCK_PM_FLAGS);
}
- registeredReceivers = mReceiverResolver.queryIntent(resolver,
- intent, resolvedType, false);
+ registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
@@ -10573,9 +11243,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
boolean started = false;
try {
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
"Delivering to component " + r.curComponent
+ ": " + r);
+ ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
r.resultCode, r.resultData, r.resultExtras, r.ordered);
started = true;
@@ -10643,12 +11314,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
+ if (filter.receiverList.app != null) {
+ // Bump hosting application to no longer be in background
+ // scheduling class. Note that we can't do that if there
+ // isn't an app... but we can only be in that case for
+ // things that directly call the IActivityManager API, which
+ // are already core system stuff so don't matter for this.
+ r.curApp = filter.receiverList.app;
+ filter.receiverList.app.curReceiver = r;
+ updateOomAdjLocked();
+ }
}
try {
- if (DEBUG_BROADCAST) {
+ if (DEBUG_BROADCAST_LIGHT) {
int seq = r.intent.getIntExtra("seq", -1);
- Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
- + " app=" + filter.receiverList.app);
+ Log.i(TAG, "Delivering to " + filter.receiverList.app
+ + " (seq=" + seq + "): " + r);
}
performReceive(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode,
@@ -10662,6 +11343,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
+ if (filter.receiverList.app != null) {
+ filter.receiverList.app.curReceiver = null;
+ }
}
}
}
@@ -10685,6 +11369,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Log.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,
@@ -10692,6 +11378,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ target + ": " + r);
deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
}
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
+ + r);
}
// Now take care of the next serialized one...
@@ -10717,10 +11405,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ boolean looped = false;
+
do {
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ updateOomAdjLocked();
+ }
return;
}
r = mOrderedBroadcasts.get(0);
@@ -10777,9 +11473,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
+ + r);
+
// ... and on to the next...
mOrderedBroadcasts.remove(0);
r = null;
+ looped = true;
continue;
}
} while (r == null);
@@ -10793,6 +11493,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (recIdx == 0) {
r.dispatchTime = r.startTime;
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
+ + r);
if (DEBUG_BROADCAST) Log.v(TAG,
"Submitting BROADCAST_TIMEOUT_MSG for "
+ (r.startTime + BROADCAST_TIMEOUT));
@@ -11135,6 +11837,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
+
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.updateConfiguration(mConfiguration);
+ }
}
}
@@ -11380,6 +12087,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
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);
+ adj = BACKUP_APP_ADJ;
+ }
+ }
+
if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
// If this process has active services running in it, we would
// like to avoid killing it unless it would prevent the current
@@ -11506,7 +12221,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
app.curAdj = adj;
-
+ app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
+ ? Process.THREAD_GROUP_BG_NONINTERACTIVE
+ : Process.THREAD_GROUP_DEFAULT;
+
return adj;
}
@@ -11651,6 +12369,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return false;
}
}
+ if (app.setSchedGroup != app.curSchedGroup) {
+ app.setSchedGroup = app.curSchedGroup;
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
+ "Setting process group of " + app.processName
+ + " to " + app.curSchedGroup);
+ if (true) {
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ Process.setProcessGroup(app.pid, app.curSchedGroup);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+ if (false) {
+ if (app.thread != null) {
+ try {
+ app.thread.setSchedulingGroup(app.curSchedGroup);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
}
return true;
@@ -11942,51 +12686,63 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public boolean profileControl(String process, boolean start,
- String path) throws RemoteException {
+ String path, ParcelFileDescriptor fd) throws RemoteException {
- synchronized (this) {
- // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
- // its own permission.
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
-
- ProcessRecord proc = null;
- try {
- int pid = Integer.parseInt(process);
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(pid);
+ try {
+ synchronized (this) {
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
}
- } catch (NumberFormatException e) {
- }
-
- if (proc == null) {
- HashMap<String, SparseArray<ProcessRecord>> all
- = mProcessNames.getMap();
- SparseArray<ProcessRecord> procs = all.get(process);
- if (procs != null && procs.size() > 0) {
- proc = procs.valueAt(0);
+
+ if (start && fd == null) {
+ throw new IllegalArgumentException("null fd");
}
- }
-
- if (proc == null || proc.thread == null) {
- throw new IllegalArgumentException("Unknown process: " + process);
- }
-
- boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
- if (isSecure) {
- if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + proc);
+
+ ProcessRecord proc = null;
+ try {
+ int pid = Integer.parseInt(process);
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ if (proc == null) {
+ HashMap<String, SparseArray<ProcessRecord>> all
+ = mProcessNames.getMap();
+ SparseArray<ProcessRecord> procs = all.get(process);
+ if (procs != null && procs.size() > 0) {
+ proc = procs.valueAt(0);
+ }
+ }
+
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
+ if (isSecure) {
+ if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
}
- }
- try {
- proc.thread.profilerControl(start, path);
+ proc.thread.profilerControl(start, path, fd);
+ fd = null;
return true;
- } catch (RemoteException e) {
- throw new IllegalStateException("Process disappeared");
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ } finally {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
}
}
}
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 3fcfad0..33894d6 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -19,17 +19,22 @@ package com.android.server.am;
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
class AppErrorDialog extends BaseErrorDialog {
+ private final static String TAG = "AppErrorDialog";
+
private final AppErrorResult mResult;
private final ProcessRecord mProc;
// Event 'what' codes
static final int FORCE_QUIT = 0;
static final int DEBUG = 1;
+ static final int FORCE_QUIT_AND_REPORT = 2;
// 5-minute timeout, then we automatically dismiss the crash dialog
static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
@@ -58,12 +63,22 @@ class AppErrorDialog extends BaseErrorDialog {
setCancelable(false);
- setButton(res.getText(com.android.internal.R.string.force_close),
- mHandler.obtainMessage(FORCE_QUIT));
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ res.getText(com.android.internal.R.string.force_close),
+ mHandler.obtainMessage(FORCE_QUIT));
+
if ((flags&1) != 0) {
- setButton(res.getText(com.android.internal.R.string.debug),
+ 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),
+ mHandler.obtainMessage(FORCE_QUIT_AND_REPORT));
+ }
+
setTitle(res.getText(com.android.internal.R.string.aerr_title));
getWindow().addFlags(FLAG_SYSTEM_ERROR);
getWindow().setTitle("Application Error: " + app.info.processName);
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index 7390ed0..03c2a04 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -18,7 +18,10 @@ package com.android.server.am;
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
@@ -26,6 +29,13 @@ import android.os.Process;
import android.util.Log;
class AppNotRespondingDialog extends BaseErrorDialog {
+ private static final String TAG = "AppNotRespondingDialog";
+
+ // Event 'what' codes
+ static final int FORCE_CLOSE = 1;
+ static final int WAIT = 2;
+ static final int WAIT_AND_REPORT = 3;
+
private final ActivityManagerService mService;
private final ProcessRecord mProc;
@@ -67,10 +77,19 @@ class AppNotRespondingDialog extends BaseErrorDialog {
? res.getString(resid, name1.toString(), name2.toString())
: res.getString(resid, name1.toString()));
- setButton(res.getText(com.android.internal.R.string.force_close),
- mHandler.obtainMessage(1));
- setButton2(res.getText(com.android.internal.R.string.wait),
- mHandler.obtainMessage(2));
+ setButton(DialogInterface.BUTTON_POSITIVE,
+ res.getText(com.android.internal.R.string.force_close),
+ mHandler.obtainMessage(FORCE_CLOSE));
+ setButton(DialogInterface.BUTTON_NEUTRAL,
+ res.getText(com.android.internal.R.string.wait),
+ mHandler.obtainMessage(WAIT));
+
+ if (app.errorReportReceiver != null) {
+ setButton(DialogInterface.BUTTON_NEGATIVE,
+ res.getText(com.android.internal.R.string.report),
+ mHandler.obtainMessage(WAIT_AND_REPORT));
+ }
+
setTitle(res.getText(com.android.internal.R.string.anr_title));
getWindow().addFlags(FLAG_SYSTEM_ERROR);
getWindow().setTitle("Application Not Responding: " + app.info.processName);
@@ -81,16 +100,23 @@ class AppNotRespondingDialog extends BaseErrorDialog {
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
+ Intent appErrorIntent = null;
switch (msg.what) {
- case 1:
+ case FORCE_CLOSE:
// Kill the application.
mService.killAppAtUsersRequest(mProc,
AppNotRespondingDialog.this, true);
break;
- case 2:
+ case WAIT_AND_REPORT:
+ case WAIT:
// Continue waiting for the application.
synchronized (mService) {
ProcessRecord app = mProc;
+
+ if (msg.what == WAIT_AND_REPORT) {
+ appErrorIntent = mService.createAppErrorIntentLocked(app);
+ }
+
app.notResponding = false;
app.notRespondingReport = null;
if (app.anrDialog == AppNotRespondingDialog.this) {
@@ -99,6 +125,14 @@ class AppNotRespondingDialog extends BaseErrorDialog {
}
break;
}
+
+ if (appErrorIntent != null) {
+ try {
+ getContext().startActivity(appErrorIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "bug report receiver dissappeared", e);
+ }
+ }
}
};
}
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/java/com/android/server/am/BackupRecord.java
new file mode 100644
index 0000000..5ac8e0d
--- /dev/null
+++ b/services/java/com/android/server/am/BackupRecord.java
@@ -0,0 +1,57 @@
+/*
+ * 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.am;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import android.content.pm.ApplicationInfo;
+
+/** @hide */
+class BackupRecord {
+ // backup/restore modes
+ public static final int BACKUP_NORMAL = 0;
+ public static final int BACKUP_FULL = 1;
+ public static final int RESTORE = 2;
+
+ final BatteryStatsImpl.Uid.Pkg.Serv stats;
+ String stringName; // cached toString() output
+ final ApplicationInfo appInfo; // information about BackupAgent's app
+ final int backupMode; // full backup / incremental / restore
+ ProcessRecord app; // where this agent is running or null
+
+ // ----- Implementation -----
+
+ BackupRecord(BatteryStatsImpl.Uid.Pkg.Serv _agentStats, ApplicationInfo _appInfo,
+ int _backupMode) {
+ stats = _agentStats;
+ appInfo = _appInfo;
+ backupMode = _backupMode;
+ }
+
+ public String toString() {
+ if (stringName != null) {
+ return stringName;
+ }
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("BackupRecord{")
+ .append(Integer.toHexString(System.identityHashCode(this)))
+ .append(' ').append(appInfo.packageName)
+ .append(' ').append(appInfo.name)
+ .append(' ').append(appInfo.backupAgentName).append('}');
+ return stringName = sb.toString();
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 0387be5..39a1ee0 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -16,17 +16,19 @@
package com.android.server.am;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BatteryStatsImpl;
-
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -177,10 +179,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
- public void notePhoneSignalStrength(int asu) {
+ public void notePhoneSignalStrength(SignalStrength signalStrength) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.notePhoneSignalStrengthLocked(asu);
+ mStats.notePhoneSignalStrengthLocked(signalStrength);
}
}
@@ -190,7 +192,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
}
}
-
+
+ public void noteAirplaneMode(boolean airplaneMode) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteAirplaneModeLocked(airplaneMode);
+ }
+ }
+
public void noteWifiOn(int uid) {
enforceCallingPermission();
synchronized (mStats) {
@@ -205,6 +214,34 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
+ public void noteStartAudio(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteAudioOnLocked(uid);
+ }
+ }
+
+ public void noteStopAudio(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteAudioOffLocked(uid);
+ }
+ }
+
+ public void noteStartVideo(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteVideoOnLocked(uid);
+ }
+ }
+
+ public void noteStopVideo(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteVideoOffLocked(uid);
+ }
+ }
+
public void noteWifiRunning() {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 4057ae8..da55049 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import android.app.IIntentReceiver;
+import android.content.IIntentReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 1488791..b3fc313 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -66,6 +66,7 @@ class HistoryRecord extends IApplicationToken.Stub {
int theme; // resource identifier of activity's theme.
TaskRecord task; // the task this is in.
long startTime; // when we starting launching this activity
+ long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
Configuration configuration; // configuration activity was last running in
HistoryRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
@@ -85,6 +86,7 @@ class HistoryRecord extends IApplicationToken.Stub {
boolean launchFailed; // set if a launched failed, to abort on 2nd try
boolean haveState; // have we gotten the last activity state?
boolean stopped; // is activity pause finished?
+ boolean delayedResume; // not yet resumed because of stopped app switches?
boolean finishing; // activity in pending finish list?
boolean configDestroy; // need to destroy due to config change?
int configChangeFlags; // which config values have changed
@@ -146,6 +148,7 @@ class HistoryRecord extends IApplicationToken.Stub {
pw.print(" icicle="); pw.println(icicle);
pw.print(prefix); pw.print("state="); pw.print(state);
pw.print(" stopped="); pw.print(stopped);
+ pw.print(" delayedResume="); pw.print(delayedResume);
pw.print(" finishing="); pw.println(finishing);
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
@@ -191,6 +194,7 @@ class HistoryRecord extends IApplicationToken.Stub {
launchFailed = false;
haveState = false;
stopped = false;
+ delayedResume = false;
finishing = false;
configDestroy = false;
keysPaused = false;
@@ -459,6 +463,12 @@ class HistoryRecord extends IApplicationToken.Stub {
return false;
}
+ if (service.mDidDexOpt) {
+ // Give more time since we were dexopting.
+ service.mDidDexOpt = false;
+ return false;
+ }
+
if (r.app.instrumentationClass == null) {
service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
} else {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 4381392..fa2a100 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -17,8 +17,8 @@
package com.android.server.am;
import android.app.IActivityManager;
-import android.app.IIntentSender;
-import android.app.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.IIntentReceiver;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Binder;
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 68aebc3..3f59710 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -56,6 +56,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
int setRawAdj; // Last set OOM unlimited adjustment for this process
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
+ int curSchedGroup; // Currently desired scheduling class
+ int setSchedGroup; // Last set to background scheduling class
boolean isForeground; // Is this app running the foreground UI?
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
@@ -107,6 +109,10 @@ class ProcessRecord implements Watchdog.PssRequestor {
ActivityManager.ProcessErrorStateInfo crashingReport;
ActivityManager.ProcessErrorStateInfo notRespondingReport;
+ // Who will be notified of the error. This is usually an activity in the
+ // app that installed the package.
+ ComponentName errorReportReceiver;
+
void dump(PrintWriter pw, String prefix) {
if (info.className != null) {
pw.print(prefix); pw.print("class="); pw.println(info.className);
@@ -143,6 +149,8 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.print(" setRaw="); pw.print(setRawAdj);
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
+ pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
+ pw.print(" setSchedGroup="); pw.println(setSchedGroup);
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
pw.print(" setIsForeground="); pw.print(setIsForeground);
pw.print(" foregroundServices="); pw.print(foregroundServices);
@@ -157,7 +165,14 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.print(" "); pw.print(crashDialog);
pw.print(" notResponding="); pw.print(notResponding);
pw.print(" " ); pw.print(anrDialog);
- pw.print(" bad="); pw.println(bad);
+ pw.print(" bad="); pw.print(bad);
+
+ // crashing or notResponding is always set before errorReportReceiver
+ if (errorReportReceiver != null) {
+ pw.print(" errorReportReceiver=");
+ pw.print(errorReportReceiver.flattenToShortString());
+ }
+ pw.println();
}
if (activities.size() > 0) {
pw.print(prefix); pw.print("activities="); pw.println(activities);
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java
index 0facefc..32c24c6 100644
--- a/services/java/com/android/server/am/ReceiverList.java
+++ b/services/java/com/android/server/am/ReceiverList.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import android.app.IIntentReceiver;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 866334b..2d58659 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -56,9 +56,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1004;
+ private static final int VERSION = 1005;
- private static final int CHECKIN_VERSION = 3;
+ private static final int CHECKIN_VERSION = 4;
private static final String FILE_PREFIX = "usage-";
@@ -82,7 +82,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
// this lock held.
final Object mFileLock;
// Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
- private String mResumedPkg;
+ private String mLastResumedPkg;
+ private String mLastResumedComp;
+ private boolean mIsResumed;
private File mFile;
private String mFileLeaf;
//private File mBackupFile;
@@ -92,11 +94,16 @@ public final class UsageStatsService extends IUsageStats.Stub {
private int mLastWriteDay;
static class TimeStats {
+ int count;
int[] times = new int[NUM_LAUNCH_TIME_BINS];
TimeStats() {
}
+ void incCount() {
+ count++;
+ }
+
void add(int val) {
final int[] bins = LAUNCH_TIME_BINS;
for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
@@ -109,6 +116,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
TimeStats(Parcel in) {
+ count = in.readInt();
final int[] localTimes = times;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
localTimes[i] = in.readInt();
@@ -116,6 +124,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
void writeToParcel(Parcel out) {
+ out.writeInt(count);
final int[] localTimes = times;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
out.writeInt(localTimes[i]);
@@ -152,8 +161,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void updateResume() {
- mLaunchCount ++;
+ void updateResume(boolean launched) {
+ if (launched) {
+ mLaunchCount ++;
+ }
mResumedTime = SystemClock.elapsedRealtime();
}
@@ -162,6 +173,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
mUsageTime += (mPausedTime - mResumedTime);
}
+ void addLaunchCount(String comp) {
+ TimeStats times = mLaunchTimes.get(comp);
+ if (times == null) {
+ times = new TimeStats();
+ mLaunchTimes.put(comp, times);
+ }
+ times.incCount();
+ }
+
void addLaunchTime(String comp, int millis) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -436,43 +456,70 @@ public final class UsageStatsService extends IUsageStats.Stub {
public void noteResumeComponent(ComponentName componentName) {
enforceCallingPermission();
String pkgName;
- if ((componentName == null) ||
- ((pkgName = componentName.getPackageName()) == null)) {
- return;
- }
- if ((mResumedPkg != null) && (mResumedPkg.equalsIgnoreCase(pkgName))) {
- // Moving across activities in same package. just return
- return;
- }
- if (localLOGV) Log.i(TAG, "started component:"+pkgName);
synchronized (mStatsLock) {
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+
+ final boolean samePackage = pkgName.equals(mLastResumedPkg);
+ if (mIsResumed) {
+ if (samePackage) {
+ Log.w(TAG, "Something wrong here, didn't expect "
+ + pkgName + " to be resumed");
+ return;
+ }
+
+ if (mLastResumedPkg != null) {
+ // We last resumed some other package... just pause it now
+ // to recover.
+ Log.w(TAG, "Unexpected resume of " + pkgName
+ + " while already resumed in " + mLastResumedPkg);
+ PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+ if (pus != null) {
+ pus.updatePause();
+ }
+ }
+ }
+
+ final boolean sameComp = samePackage
+ && componentName.getClassName().equals(mLastResumedComp);
+
+ mIsResumed = true;
+ mLastResumedPkg = pkgName;
+ mLastResumedComp = componentName.getClassName();
+
+ if (localLOGV) Log.i(TAG, "started component:" + pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
pus = new PkgUsageStatsExtended();
mStats.put(pkgName, pus);
}
- pus.updateResume();
+ pus.updateResume(!samePackage);
+ if (!sameComp) {
+ pus.addLaunchCount(mLastResumedComp);
+ }
}
- mResumedPkg = pkgName;
}
public void notePauseComponent(ComponentName componentName) {
enforceCallingPermission();
- String pkgName;
- if ((componentName == null) ||
- ((pkgName = componentName.getPackageName()) == null)) {
- return;
- }
- if ((mResumedPkg == null) || (!pkgName.equalsIgnoreCase(mResumedPkg))) {
- Log.w(TAG, "Something wrong here, Didn't expect "+pkgName+" to be paused");
- return;
- }
- if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
-
- // Persist current data to file if needed.
- writeStatsToFile(false);
synchronized (mStatsLock) {
+ String pkgName;
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+ if (!mIsResumed) {
+ Log.w(TAG, "Something wrong here, didn't expect "
+ + pkgName + " to be paused");
+ return;
+ }
+ mIsResumed = false;
+
+ if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
+
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
// Weird some error here
@@ -481,6 +528,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
pus.updatePause();
}
+
+ // Persist current data to file if needed.
+ writeStatsToFile(false);
}
public void noteLaunchTime(ComponentName componentName, int millis) {
@@ -631,9 +681,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (isCompactOutput) {
sb.append("P:");
sb.append(pkgName);
- sb.append(",");
+ sb.append(',');
sb.append(pus.mLaunchCount);
- sb.append(",");
+ sb.append(',');
sb.append(pus.mUsageTime);
sb.append('\n');
final int NC = pus.mLaunchTimes.size();
@@ -642,6 +692,8 @@ public final class UsageStatsService extends IUsageStats.Stub {
sb.append("A:");
sb.append(ent.getKey());
TimeStats times = ent.getValue();
+ sb.append(',');
+ sb.append(times.count);
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
sb.append(",");
sb.append(times.times[i]);
@@ -665,25 +717,26 @@ public final class UsageStatsService extends IUsageStats.Stub {
sb.append(" ");
sb.append(ent.getKey());
TimeStats times = ent.getValue();
+ sb.append(": ");
+ sb.append(times.count);
+ sb.append(" starts");
int lastBin = 0;
- boolean first = true;
for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
if (times.times[i] != 0) {
- sb.append(first ? ": " : ", ");
+ sb.append(", ");
sb.append(lastBin);
sb.append('-');
sb.append(LAUNCH_TIME_BINS[i]);
- sb.append('=');
+ sb.append("ms=");
sb.append(times.times[i]);
- first = false;
}
lastBin = LAUNCH_TIME_BINS[i];
}
if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
- sb.append(first ? ": " : ", ");
+ sb.append(", ");
sb.append(">=");
sb.append(lastBin);
- sb.append('=');
+ sb.append("ms=");
sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
}
sb.append('\n');
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 0b161d6..7a8d4e5 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -41,6 +41,7 @@ import android.os.RemoteException;
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;
@@ -57,6 +58,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsLocationProvider;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
import com.android.internal.telephony.cdma.TtyIntent;
import com.android.server.am.BatteryStatsService;
@@ -97,7 +99,7 @@ public class StatusBarPolicy {
private IBinder mBatteryIcon;
private IconData mBatteryData;
private boolean mBatteryFirst = true;
- private boolean mBatteryPlugged;
+ private int mBatteryPlugged;
private int mBatteryLevel;
private int mBatteryThreshold = 0; // index into mBatteryThresholds
private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
@@ -106,50 +108,146 @@ public class StatusBarPolicy {
private View mBatteryView;
private int mBatteryViewSequence;
private boolean mBatteryShowLowOnEndCall = false;
+ private boolean mSentLowBatteryBroadcast = false;
private static final boolean SHOW_LOW_BATTERY_WARNING = true;
// phone
private TelephonyManager mPhone;
private IBinder mPhoneIcon;
+ private IBinder mPhoneEvdoIcon;
//***** Signal strength icons
private IconData mPhoneData;
+ private IconData mPhoneEvdoData;
//GSM/UMTS
private static final int[] sSignalImages = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_0,
- com.android.internal.R.drawable.stat_sys_signal_1,
- com.android.internal.R.drawable.stat_sys_signal_2,
- com.android.internal.R.drawable.stat_sys_signal_3,
- com.android.internal.R.drawable.stat_sys_signal_4
- };
+ com.android.internal.R.drawable.stat_sys_signal_0,
+ com.android.internal.R.drawable.stat_sys_signal_1,
+ com.android.internal.R.drawable.stat_sys_signal_2,
+ com.android.internal.R.drawable.stat_sys_signal_3,
+ com.android.internal.R.drawable.stat_sys_signal_4
+ };
private static final int[] sSignalImages_r = new int[] {
- com.android.internal.R.drawable.stat_sys_r_signal_0,
- com.android.internal.R.drawable.stat_sys_r_signal_1,
- com.android.internal.R.drawable.stat_sys_r_signal_2,
- com.android.internal.R.drawable.stat_sys_r_signal_3,
- com.android.internal.R.drawable.stat_sys_r_signal_4
- };
+ com.android.internal.R.drawable.stat_sys_r_signal_0,
+ com.android.internal.R.drawable.stat_sys_r_signal_1,
+ com.android.internal.R.drawable.stat_sys_r_signal_2,
+ com.android.internal.R.drawable.stat_sys_r_signal_3,
+ com.android.internal.R.drawable.stat_sys_r_signal_4
+ };
//CDMA
private static final int[] sSignalImages_cdma = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_0_cdma,
- com.android.internal.R.drawable.stat_sys_signal_1_cdma,
- com.android.internal.R.drawable.stat_sys_signal_2_cdma,
- com.android.internal.R.drawable.stat_sys_signal_3_cdma,
- com.android.internal.R.drawable.stat_sys_signal_4_cdma
+ com.android.internal.R.drawable.stat_sys_signal_cdma_0,
+ com.android.internal.R.drawable.stat_sys_signal_cdma_1,
+ com.android.internal.R.drawable.stat_sys_signal_cdma_2,
+ com.android.internal.R.drawable.stat_sys_signal_cdma_3,
+ com.android.internal.R.drawable.stat_sys_signal_cdma_4
};
- private static final int[] sSignalImages_r_cdma = new int[] {
- com.android.internal.R.drawable.stat_sys_r_signal_0_cdma,
- com.android.internal.R.drawable.stat_sys_r_signal_1_cdma,
- com.android.internal.R.drawable.stat_sys_r_signal_2_cdma,
- com.android.internal.R.drawable.stat_sys_r_signal_3_cdma,
- com.android.internal.R.drawable.stat_sys_r_signal_4_cdma
+ private static final int[] sRoamingIndicatorImages_cdma = new int[] {
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
+ // 1 is Standard Roaming Indicator OFF
+ // TODO T: image never used, remove and put 0 instead?
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+
+ // 2 is Standard Roaming Indicator FLASHING
+ // TODO T: image never used, remove and put 0 instead?
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+
+ // 3-12 Standard ERI
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //3
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+
+ // 13-63 Reserved for Standard ERI
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //13
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+
+ // 64-127 Reserved for Non Standard (Operator Specific) ERI
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //64
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0,
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_0 //83
+
+ // 128-255 Reserved
};
- private static final int[] sSignalImages_ra_cdma = new int[] {
- com.android.internal.R.drawable.stat_sys_ra_signal_0_cdma,
- com.android.internal.R.drawable.stat_sys_ra_signal_1_cdma,
- com.android.internal.R.drawable.stat_sys_ra_signal_2_cdma,
- com.android.internal.R.drawable.stat_sys_ra_signal_3_cdma,
- com.android.internal.R.drawable.stat_sys_ra_signal_4_cdma
+ // EVDO
+ private static final int[] sSignalImages_evdo = new int[] {
+ com.android.internal.R.drawable.stat_sys_signal_evdo_0,
+ com.android.internal.R.drawable.stat_sys_signal_evdo_1,
+ com.android.internal.R.drawable.stat_sys_signal_evdo_2,
+ com.android.internal.R.drawable.stat_sys_signal_evdo_3,
+ com.android.internal.R.drawable.stat_sys_signal_evdo_4
};
//***** Data connection icons
@@ -179,12 +277,14 @@ public class StatusBarPolicy {
com.android.internal.R.drawable.stat_sys_data_in_evdo,
com.android.internal.R.drawable.stat_sys_data_out_evdo,
com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
+ com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
};
private static final int[] sDataNetType_1xrtt = new int[] {
com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
+ com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
};
// Assume it's all good unless we hear otherwise. We don't always seem
@@ -194,7 +294,7 @@ public class StatusBarPolicy {
int mDataState = TelephonyManager.DATA_DISCONNECTED;
int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
ServiceState mServiceState;
- int mSignalAsu = -1;
+ SignalStrength mSignalStrength;
// data connection
private IBinder mDataIcon;
@@ -249,6 +349,10 @@ public class StatusBarPolicy {
private IBinder mTTYModeIcon;
private IconData mTTYModeEnableIconData;
+ // Cdma Roaming Indicator, ERI
+ private IBinder mCdmaRoamingIndicatorIcon;
+ private IconData mCdmaRoamingIndicatorIconData;
+
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -306,6 +410,7 @@ public class StatusBarPolicy {
private StatusBarPolicy(Context context, StatusBarService service) {
mContext = context;
mService = service;
+ mSignalStrength = new SignalStrength();
mBatteryStats = BatteryStatsService.getService();
// clock
@@ -321,14 +426,21 @@ public class StatusBarPolicy {
// phone_signal
mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
- mPhoneData = IconData.makeIcon("phone_signal",
+ mPhoneData = IconData.makeIcon("phone_signal",
null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
mPhoneIcon = service.addIcon(mPhoneData, null);
+
+ // phone_evdo_signal
+ mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal",
+ null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0);
+ mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null);
+ service.setIconVisibility(mPhoneEvdoIcon, false);
+
// register for phone state notifications.
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTH
+ | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
@@ -351,6 +463,12 @@ public class StatusBarPolicy {
mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null);
service.setIconVisibility(mTTYModeIcon, false);
+ // Cdma Roaming Indicator, ERI
+ mCdmaRoamingIndicatorIconData = IconData.makeIcon("cdma_eri",
+ null, com.android.internal.R.drawable.stat_sys_roaming_cdma_0, 0, 0);
+ mCdmaRoamingIndicatorIcon = service.addIcon(mCdmaRoamingIndicatorIconData, null);
+ service.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+
// bluetooth status
mBluetoothData = IconData.makeIcon("bluetooth",
null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
@@ -464,7 +582,7 @@ public class StatusBarPolicy {
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
mService.updateIcon(mBatteryIcon, mBatteryData, null);
- boolean plugged = intent.getIntExtra("plugged", 0) != 0;
+ int plugged = intent.getIntExtra("plugged", 0);
int level = intent.getIntExtra("level", -1);
if (false) {
Log.d(TAG, "updateBattery level=" + level
@@ -475,7 +593,7 @@ public class StatusBarPolicy {
+ " mBatteryFirst=" + mBatteryFirst);
}
- boolean oldPlugged = mBatteryPlugged;
+ int oldPlugged = mBatteryPlugged;
int oldThreshold = mBatteryThreshold;
pickNextBatteryLevel(level);
@@ -502,11 +620,12 @@ public class StatusBarPolicy {
Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
+ " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
}
- if (!plugged
- && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
+ if (plugged == 0
+ && ((oldPlugged != 0 && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
|| (mBatteryThreshold > oldThreshold
&& mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
// Broadcast the low battery warning
+ mSentLowBatteryBroadcast = true;
mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
if (SHOW_LOW_BATTERY_WARNING) {
@@ -522,7 +641,11 @@ public class StatusBarPolicy {
mBatteryShowLowOnEndCall = true;
}
}
- } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) {
+ } else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) {
+ if (mSentLowBatteryBroadcast == true) {
+ mSentLowBatteryBroadcast = false;
+ mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY));
+ }
if (SHOW_LOW_BATTERY_WARNING) {
if (mLowBatteryDialog != null) {
mLowBatteryDialog.dismiss();
@@ -611,6 +734,23 @@ public class StatusBarPolicy {
b.setView(v);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setPositiveButton(android.R.string.ok, null);
+
+ final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_NO_HISTORY);
+ if (intent.resolveActivity(mContext.getPackageManager()) != null) {
+ b.setNegativeButton(com.android.internal.R.string.battery_low_why,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mContext.startActivity(intent);
+ if (mLowBatteryDialog != null) {
+ mLowBatteryDialog.dismiss();
+ }
+ }
+ });
+ }
AlertDialog d = b.create();
d.setOnDismissListener(mLowBatteryListener);
@@ -629,7 +769,7 @@ public class StatusBarPolicy {
}
if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
if (mBatteryShowLowOnEndCall) {
- if (!mBatteryPlugged) {
+ if (mBatteryPlugged == 0) {
showLowBatteryWarning();
}
mBatteryShowLowOnEndCall = false;
@@ -666,8 +806,8 @@ public class StatusBarPolicy {
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
- public void onSignalStrengthChanged(int asu) {
- mSignalAsu = asu;
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ mSignalStrength = signalStrength;
updateSignalStrength();
}
@@ -675,6 +815,7 @@ public class StatusBarPolicy {
public void onServiceStateChanged(ServiceState state) {
mServiceState = state;
updateSignalStrength();
+ updateCdmaRoamingIcon();
updateDataIcon();
}
@@ -696,7 +837,6 @@ public class StatusBarPolicy {
updateDataIcon();
}
};
-
private final void updateSimState(Intent intent) {
String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
@@ -723,25 +863,31 @@ public class StatusBarPolicy {
updateDataIcon();
}
- private final void updateSignalStrength() {
- int asu = mSignalAsu;
- ServiceState ss = mServiceState;
+ private boolean isCdma() {
+ return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
+ }
- boolean hasService = true;
-
- if (ss != null) {
- int state = ss.getState();
- switch (state) {
+ private boolean hasService() {
+ if (mServiceState != null) {
+ switch (mServiceState.getState()) {
case ServiceState.STATE_OUT_OF_SERVICE:
case ServiceState.STATE_POWER_OFF:
- hasService = false;
- break;
+ return false;
+ default:
+ return true;
}
} else {
- hasService = false;
+ return false;
}
+ }
- if (!hasService) {
+ private final void updateSignalStrength() {
+ int iconLevel = -1;
+ int evdoIconLevel = -1;
+ int[] iconList;
+ int[] evdoIconList;
+
+ if (!hasService()) {
//Log.d(TAG, "updateSignalStrength: no service");
if (Settings.System.getInt(mContext.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) == 1) {
@@ -750,48 +896,92 @@ public class StatusBarPolicy {
mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
}
mService.updateIcon(mPhoneIcon, mPhoneData, null);
+ mService.setIconVisibility(mPhoneEvdoIcon,false);
return;
}
- // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
- // asu = 0 (-113dB or less) is very weak
- // signal, its better to show 0 bars to the user in such cases.
- // asu = 99 is a special case, where the signal strength is unknown.
- if (asu <= 0 || asu == 99) asu = 0;
- else if (asu >= 16) asu = 4;
- else if (asu >= 8) asu = 3;
- else if (asu >= 4) asu = 2;
- else asu = 1;
-
- int[] iconList;
- if (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
- switch(ss.getExtendedCdmaRoaming()) {
- case ServiceState.REGISTRATION_STATE_ROAMING:
- iconList = this.sSignalImages_r_cdma;
- break;
- case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE:
- iconList = this.sSignalImages_ra_cdma;
- break;
- default:
- iconList = this.sSignalImages_cdma;
- break;
+ if (!isCdma()) {
+ int asu = mSignalStrength.getGsmSignalStrength();
+
+ // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+ // asu = 0 (-113dB or less) is very weak
+ // signal, its better to show 0 bars to the user in such cases.
+ // asu = 99 is a special case, where the signal strength is unknown.
+ if (asu <= 0 || asu == 99) iconLevel = 0;
+ else if (asu >= 16) iconLevel = 4;
+ else if (asu >= 8) iconLevel = 3;
+ else if (asu >= 4) iconLevel = 2;
+ else iconLevel = 1;
+
+ if (mPhone.isNetworkRoaming()) {
+ iconList = sSignalImages_r;
+ } else {
+ iconList = sSignalImages;
}
- } else if (mPhone.isNetworkRoaming()) {
- iconList = sSignalImages_r;
} else {
- iconList = sSignalImages;
+ iconList = this.sSignalImages_cdma;
+
+ int cdmaDbm = mSignalStrength.getCdmaDbm();
+ int cdmaEcio = mSignalStrength.getCdmaEcio();
+ int levelDbm = 0;
+ int levelEcio = 0;
+
+ if (cdmaDbm >= -75) levelDbm = 4;
+ else if (cdmaDbm >= -85) levelDbm = 3;
+ else if (cdmaDbm >= -95) levelDbm = 2;
+ else if (cdmaDbm >= -100) levelDbm = 1;
+ else levelDbm = 0;
+
+ // Ec/Io are in dB*10
+ if (cdmaEcio >= -90) levelEcio = 4;
+ else if (cdmaEcio >= -110) levelEcio = 3;
+ else if (cdmaEcio >= -130) levelEcio = 2;
+ else if (cdmaEcio >= -150) levelEcio = 1;
+ else levelEcio = 0;
+
+ iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
}
- mPhoneData.iconId = iconList[asu];
+ if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+ || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
+ // Use Evdo icon
+ evdoIconList = this.sSignalImages_evdo;
+
+ int evdoEcio = mSignalStrength.getEvdoEcio();
+ int evdoSnr = mSignalStrength.getEvdoSnr();
+ int levelEvdoEcio = 0;
+ int levelEvdoSnr = 0;
+
+ // Ec/Io are in dB*10
+ if (evdoEcio >= -650) levelEvdoEcio = 4;
+ else if (evdoEcio >= -750) levelEvdoEcio = 3;
+ else if (evdoEcio >= -900) levelEvdoEcio = 2;
+ else if (evdoEcio >= -1050) levelEvdoEcio = 1;
+ else levelEvdoEcio = 0;
+
+ if (evdoSnr > 7) levelEvdoSnr = 4;
+ else if (evdoSnr > 5) levelEvdoSnr = 3;
+ else if (evdoSnr > 3) levelEvdoSnr = 2;
+ else if (evdoSnr > 1) levelEvdoSnr = 1;
+ else levelEvdoSnr = 0;
+
+ evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
+
+ mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
+ mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
+ mService.setIconVisibility(mPhoneEvdoIcon,true);
+ } else {
+ mService.setIconVisibility(mPhoneEvdoIcon,false);
+ }
+
+ mPhoneData.iconId = iconList[iconLevel];
mService.updateIcon(mPhoneIcon, mPhoneData, null);
}
private final void updateDataNetType() {
int net = mPhone.getNetworkType();
- ServiceState ss = this.mServiceState;
switch (net) {
-
case TelephonyManager.NETWORK_TYPE_EDGE:
mDataIconList = sDataNetType_e;
break;
@@ -819,32 +1009,51 @@ public class StatusBarPolicy {
int iconId;
boolean visible = true;
- if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
- int data = mDataState;
-
- int[] list = mDataIconList;
-
- ServiceState ss = mServiceState;
-
- boolean hasService = false;
-
- if (ss != null) {
- hasService = (ss.getState() == ServiceState.STATE_IN_SERVICE);
+ if (!isCdma()) {
+ // GSM case, we have to check also the sim state
+ if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) {
+ if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+ switch (mDataActivity) {
+ case TelephonyManager.DATA_ACTIVITY_IN:
+ iconId = mDataIconList[1];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_OUT:
+ iconId = mDataIconList[2];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_INOUT:
+ iconId = mDataIconList[3];
+ break;
+ default:
+ iconId = mDataIconList[0];
+ break;
+ }
+ mDataData.iconId = iconId;
+ mService.updateIcon(mDataIcon, mDataData, null);
+ } else {
+ visible = false;
+ }
+ } else {
+ mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
+ mService.updateIcon(mDataIcon, mDataData, null);
}
-
- if (hasService && data == TelephonyManager.DATA_CONNECTED) {
+ } else {
+ // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+ if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
- iconId = list[1];
+ iconId = mDataIconList[1];
break;
case TelephonyManager.DATA_ACTIVITY_OUT:
- iconId = list[2];
+ iconId = mDataIconList[2];
break;
case TelephonyManager.DATA_ACTIVITY_INOUT:
- iconId = list[3];
+ iconId = mDataIconList[3];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_DORMANT:
+ iconId = mDataIconList[4];
break;
default:
- iconId = list[0];
+ iconId = mDataIconList[0];
break;
}
mDataData.iconId = iconId;
@@ -852,10 +1061,8 @@ public class StatusBarPolicy {
} else {
visible = false;
}
- } else {
- mDataData.iconId = com.android.internal.R.drawable.stat_sys_no_sim;
- mService.updateIcon(mDataIcon, mDataData, null);
}
+
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneDataConnectionState(mPhone.getNetworkType(), visible);
@@ -863,6 +1070,7 @@ public class StatusBarPolicy {
} finally {
Binder.restoreCallingIdentity(ident);
}
+
if (mDataIconVisible != visible) {
mService.setIconVisibility(mDataIcon, visible);
mDataIconVisible = visible;
@@ -873,7 +1081,7 @@ public class StatusBarPolicy {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
final int ringerMode = audioManager.getRingerMode();
final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
- ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+ ringerMode == AudioManager.RINGER_MODE_VIBRATE;
final int iconId = audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)
? com.android.internal.R.drawable.stat_sys_ringer_vibrate
: com.android.internal.R.drawable.stat_sys_ringer_silent;
@@ -905,7 +1113,7 @@ public class StatusBarPolicy {
} else {
return;
}
-
+
if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) {
@@ -920,15 +1128,15 @@ public class StatusBarPolicy {
private final void updateWifi(Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-
+
final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
+
if (!enabled) {
// If disabled, hide the icon. (We show icon when connected.)
mService.setIconVisibility(mWifiIcon, false);
}
-
+
} else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
false);
@@ -937,9 +1145,9 @@ public class StatusBarPolicy {
}
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- final NetworkInfo networkInfo = (NetworkInfo)
+ final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
+
int iconId;
if (networkInfo != null && networkInfo.isConnected()) {
mIsWifiConnected = true;
@@ -986,18 +1194,18 @@ public class StatusBarPolicy {
if (action.equals(GpsLocationProvider.GPS_FIX_CHANGE_ACTION) && enabled) {
// GPS is getting fixes
mService.updateIcon(mGpsIcon, mGpsFixIconData, null);
- mService.setIconVisibility(mGpsIcon, true);
+ mService.setIconVisibility(mGpsIcon, true);
} else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
// GPS is off
- mService.setIconVisibility(mGpsIcon, false);
+ mService.setIconVisibility(mGpsIcon, false);
} else {
// GPS is on, but not receiving fixes
mService.updateIcon(mGpsIcon, mGpsEnabledIconData, null);
- mService.setIconVisibility(mGpsIcon, true);
+ mService.setIconVisibility(mGpsIcon, true);
}
}
- private final void updateTTY(Intent intent) {
+ private final void updateTTY(Intent intent) {
final String action = intent.getAction();
final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false);
@@ -1007,14 +1215,63 @@ public class StatusBarPolicy {
// TTY is on
Log.i(TAG, "updateTTY: set TTY on");
mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null);
- mService.setIconVisibility(mTTYModeIcon, true);
+ mService.setIconVisibility(mTTYModeIcon, true);
} else {
// TTY is off
Log.i(TAG, "updateTTY: set TTY off");
- mService.setIconVisibility(mTTYModeIcon, false);
+ mService.setIconVisibility(mTTYModeIcon, false);
}
}
+ private final void updateCdmaRoamingIcon() {
+ if (!hasService()) {
+ mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+ return;
+ }
+
+ if (!isCdma()) {
+ mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+ return;
+ }
+
+ int[] iconList = sRoamingIndicatorImages_cdma;
+ int iconIndex = mPhone.getCdmaEriIconIndex();
+ int iconMode = mPhone.getCdmaEriIconMode();
+
+ if (iconIndex == -1) {
+ Log.e(TAG, "getCdmaEriIconIndex returned null, skipping ERI icon update");
+ return;
+ }
+
+ if (iconMode == -1) {
+ Log.e(TAG, "getCdmeEriIconMode returned null, skipping ERI icon update");
+ return;
+ }
+
+ if (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) {
+ Log.d(TAG, "Cdma ROAMING_INDICATOR_OFF, removing ERI icon");
+ mService.setIconVisibility(mCdmaRoamingIndicatorIcon, false);
+ return;
+ }
+
+ switch (iconMode) {
+ case EriInfo.ROAMING_ICON_MODE_NORMAL:
+ mCdmaRoamingIndicatorIconData.iconId = iconList[iconIndex];
+ mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
+ mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
+ break;
+ case EriInfo.ROAMING_ICON_MODE_FLASH:
+ mCdmaRoamingIndicatorIconData.iconId =
+ com.android.internal.R.drawable.stat_sys_roaming_cdma_flash;
+ mService.updateIcon(mCdmaRoamingIndicatorIcon, mCdmaRoamingIndicatorIconData, null);
+ mService.setIconVisibility(mCdmaRoamingIndicatorIcon, true);
+ break;
+
+ }
+ mService.updateIcon(mPhoneIcon, mPhoneData, null);
+ }
+
+
private class StatusBarHandler extends Handler {
@Override
public void handleMessage(Message msg) {
@@ -1028,6 +1285,3 @@ public class StatusBarPolicy {
}
}
}
-
-
-
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 5336e27..b44168a 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -19,6 +19,7 @@ package com.android.server.status;
import com.android.internal.R;
import com.android.internal.util.CharSequences;
+import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.app.IStatusBar;
import android.app.PendingIntent;
@@ -118,6 +119,7 @@ public class StatusBarService extends IStatusBar.Stub
public void binderDied() {
Log.i(TAG, "binder died for pkg=" + pkg);
disable(0, token, pkg);
+ token.unlinkToDeath(this, 0);
}
}
@@ -493,6 +495,7 @@ public class StatusBarService extends IStatusBar.Stub
if (what == 0 || !token.isBinderAlive()) {
if (tok != null) {
mDisableRecords.remove(i);
+ tok.token.unlinkToDeath(tok, 0);
}
} else {
if (tok == null) {
@@ -1254,6 +1257,14 @@ public class StatusBarService extends IStatusBar.Stub
public void onClick(View v) {
try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManagerNative.getDefault().resumeAppSwitches();
+ } catch (RemoteException e) {
+ }
+ try {
mIntent.send();
mNotificationCallbacks.onNotificationClick(mPkg, mId);
} catch (PendingIntent.CanceledException e) {
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 695a8a3..7390786 100644
--- a/services/jni/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-#define LOG_TAG "Sensors"
+#define LOG_TAG "SensorService"
+
+#define LOG_NDEBUG 0
+#include "utils/Log.h"
#include <hardware/sensors.h>
@@ -36,6 +39,14 @@ static struct parcel_file_descriptor_offsets_t
jmethodID mConstructor;
} gParcelFileDescriptorOffsets;
+static struct bundle_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+ jmethodID mPutIntArray;
+ jmethodID mPutParcelableArray;
+} gBundleOffsets;
+
/*
* The method below are not thread-safe and not intended to be
*/
@@ -59,21 +70,45 @@ android_init(JNIEnv *env, jclass clazz)
static jobject
android_open(JNIEnv *env, jclass clazz)
{
- int fd = sSensorDevice->open_data_source(sSensorDevice);
- // new FileDescriptor()
- jobject filedescriptor = env->NewObject(
- gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
-
- if (filedescriptor != NULL) {
- env->SetIntField(filedescriptor, gFileDescriptorOffsets.mDescriptor, fd);
- // new ParcelFileDescriptor()
- return env->NewObject(gParcelFileDescriptorOffsets.mClass,
- gParcelFileDescriptorOffsets.mConstructor,
- filedescriptor);
+ native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice);
+ if (!handle) {
+ return NULL;
}
- close(fd);
- return NULL;
+
+ // new Bundle()
+ jobject bundle = env->NewObject(
+ gBundleOffsets.mClass,
+ gBundleOffsets.mConstructor);
+
+ if (handle->numFds > 0) {
+ jobjectArray fdArray = env->NewObjectArray(handle->numFds,
+ gParcelFileDescriptorOffsets.mClass, NULL);
+ for (int i = 0; i < handle->numFds; i++) {
+ // new FileDescriptor()
+ jobject fd = env->NewObject(gFileDescriptorOffsets.mClass,
+ gFileDescriptorOffsets.mConstructor);
+ env->SetIntField(fd, gFileDescriptorOffsets.mDescriptor, handle->data[i]);
+ // new ParcelFileDescriptor()
+ jobject pfd = env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fd);
+ env->SetObjectArrayElement(fdArray, i, pfd);
+ }
+ // bundle.putParcelableArray("fds", fdArray);
+ env->CallVoidMethod(bundle, gBundleOffsets.mPutParcelableArray,
+ env->NewStringUTF("fds"), fdArray);
+ }
+
+ if (handle->numInts > 0) {
+ jintArray intArray = env->NewIntArray(handle->numInts);
+ env->SetIntArrayRegion(intArray, 0, handle->numInts, &handle->data[handle->numInts]);
+ // bundle.putIntArray("ints", intArray);
+ env->CallVoidMethod(bundle, gBundleOffsets.mPutIntArray,
+ env->NewStringUTF("ints"), intArray);
+ }
+
+ // delete the file handle, but don't close any file descriptors
+ native_handle_delete(handle);
+ return bundle;
}
static jboolean
@@ -99,7 +134,7 @@ android_data_wake(JNIEnv *env, jclass clazz)
static JNINativeMethod gMethods[] = {
{"_sensors_control_init", "()I", (void*) android_init },
- {"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open },
+ {"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open },
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
{"_sensors_control_wake", "()I", (void*) android_data_wake },
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
@@ -116,7 +151,15 @@ int register_android_server_SensorService(JNIEnv *env)
clazz = env->FindClass("android/os/ParcelFileDescriptor");
gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+ gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>",
+ "(Ljava/io/FileDescriptor;)V");
+
+ clazz = env->FindClass("android/os/Bundle");
+ gBundleOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gBundleOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
+ gBundleOffsets.mPutIntArray = env->GetMethodID(clazz, "putIntArray", "(Ljava/lang/String;[I)V");
+ gBundleOffsets.mPutParcelableArray = env->GetMethodID(clazz, "putParcelableArray",
+ "(Ljava/lang/String;[Landroid/os/Parcelable;)V");
return jniRegisterNativeMethods(env, "com/android/server/SensorService",
gMethods, NELEM(gMethods));