diff options
Diffstat (limited to 'services/core')
18 files changed, 369 insertions, 174 deletions
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7ecf248..1e21e1c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -343,12 +343,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_INET_CONDITION_HOLD_END = 5; /** - * used internally to set enable/disable cellular data - * arg1 = ENBALED or DISABLED - */ - private static final int EVENT_SET_MOBILE_DATA = 7; - - /** * used internally to clear a wakelock when transitioning * from one net to another */ @@ -1822,20 +1816,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return true; } - /** - * @see ConnectivityManager#getMobileDataEnabled() - */ - public boolean getMobileDataEnabled() { - // TODO: This detail should probably be in DataConnectionTracker's - // which is where we store the value and maybe make this - // asynchronous. - enforceAccessPermission(); - boolean retVal = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MOBILE_DATA, 1) == 1; - if (VDBG) log("getMobileDataEnabled returning " + retVal); - return retVal; - } - public void setDataDependency(int networkType, boolean met) { enforceConnectivityInternalPermission(); @@ -1908,22 +1888,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } }; - /** - * @see ConnectivityManager#setMobileDataEnabled(boolean) - */ - public void setMobileDataEnabled(boolean enabled) { - enforceChangePermission(); - if (DBG) log("setMobileDataEnabled(" + enabled + ")"); - - mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, - (enabled ? ENABLED : DISABLED), 0)); - } - - private void handleSetMobileData(boolean enabled) { - // TODO - handle this - probably generalize passing in a transport type and send to the - // factories? - } - @Override public void setPolicyDataEnable(int networkType, boolean enabled) { // only someone like NPMS should only be calling us @@ -3315,11 +3279,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_MOBILE_DATA: { - boolean enabled = (msg.arg1 == ENABLED); - handleSetMobileData(enabled); - break; - } case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); break; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 88bebcb..fc808ec 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7085,6 +7085,10 @@ public final class ActivityManagerService extends ActivityManagerNative * Creates a new RecentTaskInfo from a TaskRecord. */ private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) { + // Update the task description to reflect any changes in the task stack + tr.updateTaskDescription(); + + // Compose the recent task info ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); rti.id = tr.mActivities.isEmpty() ? -1 : tr.taskId; @@ -9574,11 +9578,13 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - mRecentTasks = mTaskPersister.restoreTasksLocked(); - if (!mRecentTasks.isEmpty()) { - mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks); + if (mRecentTasks == null) { + mRecentTasks = mTaskPersister.restoreTasksLocked(); + if (!mRecentTasks.isEmpty()) { + mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks); + } + mTaskPersister.startPersisting(); } - mTaskPersister.startPersisting(); // Check to see if there are any update receivers to run. if (!mDidUpdate) { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index b948c41..b429b93 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1154,13 +1154,15 @@ final class ActivityRecord { } if (intent == null) { - Slog.e(TAG, "restoreActivity error intent=" + intent); - return null; + throw new XmlPullParserException("restoreActivity error intent=" + intent); } final ActivityManagerService service = stackSupervisor.mService; final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null, null, userId); + if (aInfo == null) { + throw new XmlPullParserException("restoreActivity resolver error."); + } final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid, launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(), null, null, 0, componentSpecified, stackSupervisor, null, null); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index d0ba118..a0440cb 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -37,6 +37,7 @@ import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP; import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; +import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; @@ -346,6 +347,10 @@ final class ActivityStack { mWindowManager = mService.mWindowManager; mStackId = activityContainer.mStackId; mCurrentUser = mService.mCurrentUserId; + // Get the activity screenshot thumbnail dimensions + Resources res = mService.mContext.getResources(); + mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); + mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); } /** @@ -729,42 +734,54 @@ final class ActivityStack { } } + /** + * This resets the saved state from the last screenshot, forcing a new screenshot to be taken + * again when requested. + */ + private void invalidateLastScreenshot() { + mLastScreenshotActivity = null; + if (mLastScreenshotBitmap != null) { + mLastScreenshotBitmap.recycle(); + } + mLastScreenshotBitmap = null; + } + public final Bitmap screenshotActivities(ActivityRecord who) { + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who); if (who.noDisplay) { + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tNo display"); return null; } TaskRecord tr = who.task; - if (mService.getMostRecentTask() != tr && tr.intent != null && - (tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0) { - // If this task is being excluded from recents, we don't want to take - // the expense of capturing a thumbnail, since we will never show it. + if (mService.getMostRecentTask() != tr || isHomeStack()) { + // This is an optimization -- since we never show Home or Recents within Recents itself, + // we can just go ahead and skip taking the screenshot if this is the home stack. In + // the case where the most recent task is not the task that was supplied, then the stack + // has changed, so invalidate the last screenshot(). + invalidateLastScreenshot(); + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tIs Home stack? " + isHomeStack()); return null; } - Resources res = mService.mContext.getResources(); int w = mThumbnailWidth; int h = mThumbnailHeight; - if (w < 0) { - mThumbnailWidth = w = - res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width); - mThumbnailHeight = h = - res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height); - } - if (w > 0) { if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null || mLastScreenshotActivity.state == ActivityState.RESUMED || mLastScreenshotBitmap.getWidth() != w || mLastScreenshotBitmap.getHeight() != h) { + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tUpdating screenshot"); mLastScreenshotActivity = who; mLastScreenshotBitmap = mWindowManager.screenshotApplications( who.appToken, Display.DEFAULT_DISPLAY, w, h, SCREENSHOT_FORCE_565); } if (mLastScreenshotBitmap != null) { + if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tReusing last screenshot"); return mLastScreenshotBitmap.copy(mLastScreenshotBitmap.getConfig(), true); } } + Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h); return null; } @@ -1042,6 +1059,12 @@ final class ActivityStack { } else { next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process } + + // If we are resuming the activity that we had last screenshotted, then we know it will be + // updated, so invalidate the last screenshot to ensure we take a fresh one when requested + if (next == mLastScreenshotActivity) { + invalidateLastScreenshot(); + } } private void setVisibile(ActivityRecord r, boolean visible) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c1a4643..ae7fab3 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -109,6 +109,7 @@ public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG_SAVED_STATE = DEBUG || false; static final boolean DEBUG_STATES = DEBUG || false; static final boolean DEBUG_IDLE = DEBUG || false; + static final boolean DEBUG_SCREENSHOTS = DEBUG || false; public static final int HOME_STACK_ID = 0; @@ -1212,8 +1213,7 @@ public final class ActivityStackSupervisor implements DisplayListener { requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { - resultRecord.removeResultsLocked( - sourceRecord, resultWho, requestCode); + resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode); } if (sourceRecord.launchedFromUid == callingUid) { // The new activity is being launched from the same uid as the previous @@ -1385,7 +1385,7 @@ public final class ActivityStackSupervisor implements DisplayListener { return err; } - ActivityStack adjustStackFocus(ActivityRecord r) { + ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) { final TaskRecord task = r.task; if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) { if (task != null) { @@ -1410,7 +1410,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return container.mStack; } - if (mFocusedStack != mHomeStack) { + if (mFocusedStack != mHomeStack && (!newTask || + mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; @@ -1463,7 +1464,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // 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; + mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving); // If the caller has asked not to resume at this point, we make note @@ -1473,7 +1474,8 @@ public final class ActivityStackSupervisor implements DisplayListener { r.delayedResume = true; } - ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; + ActivityRecord 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 @@ -1496,9 +1498,11 @@ public final class ActivityStackSupervisor implements DisplayListener { case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS: intent.addFlags( Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + launchFlags = intent.getFlags(); break; case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING: intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + launchFlags = intent.getFlags(); break; } final boolean newDocument = intent.isDocument(); @@ -1804,7 +1808,8 @@ public final class ActivityStackSupervisor implements DisplayListener { Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; } - targetStack = adjustStackFocus(r); + newTask = true; + targetStack = adjustStackFocus(r, newTask); targetStack.moveToFront(); if (reuseTask == null) { r.setTask(targetStack.createTaskRecord(getNextTaskId(), @@ -1821,7 +1826,6 @@ public final class ActivityStackSupervisor implements DisplayListener { } else { r.setTask(reuseTask, reuseTask, true); } - newTask = true; if (!movedHome) { if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) @@ -1889,7 +1893,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // This not being started from an existing activity, and not part // of a new task... just put it in the top task, though these days // this case should never happen. - targetStack = adjustStackFocus(r); + targetStack = adjustStackFocus(r, newTask); targetStack.moveToFront(); ActivityRecord prev = targetStack.topActivity(); r.setTask(prev != null ? prev.task @@ -2316,7 +2320,12 @@ public final class ActivityStackSupervisor implements DisplayListener { for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); if (!r.isApplicationActivity() && !stack.isHomeStack()) { - if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); + if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack); + continue; + } + if (!stack.mActivityContainer.isEligibleForNewTasks()) { + if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " + + stack); continue; } final ActivityRecord ar = stack.findTaskLocked(r); @@ -3247,6 +3256,11 @@ public final class ActivityStackSupervisor implements DisplayListener { void setDrawn() { } + // You can always start a new task on a regular ActivityStack. + boolean isEligibleForNewTasks() { + return true; + } + @Override public String toString() { return mIdString + (mActivityDisplay == null ? "N" : "A"); @@ -3327,6 +3341,12 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + // Never start a new task on an ActivityView if it isn't explicitly specified. + @Override + boolean isEligibleForNewTasks() { + return false; + } + private void setSurfaceIfReady() { if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn + " mContainerState=" + mContainerState + " mSurface=" + mSurface); diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index ba3f2fe..3bfaca9 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -155,6 +155,7 @@ public class TaskPersister { File taskFile = recentFiles[taskNdx]; if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName()); BufferedReader reader = null; + boolean deleteFile = false; try { reader = new BufferedReader(new FileReader(taskFile)); final XmlPullParser in = Xml.newPullParser(); @@ -183,10 +184,9 @@ public class TaskPersister { } XmlUtils.skipCurrentTag(in); } - } catch (IOException e) { - Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e); - } catch (XmlPullParserException e) { - Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e); + } catch (Exception e) { + Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error " + e); + deleteFile = true; } finally { if (reader != null) { try { @@ -194,6 +194,9 @@ public class TaskPersister { } catch (IOException e) { } } + if (!DEBUG && deleteFile) { + taskFile.delete(); + } } } @@ -220,7 +223,7 @@ public class TaskPersister { return new ArrayList<TaskRecord>(Arrays.asList(tasksArray)); } - private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) { + private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) { for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) { File file = files[fileNdx]; String filename = file.getName(); @@ -285,8 +288,7 @@ public class TaskPersister { synchronized(mService) { final ArrayList<TaskRecord> tasks = mService.mRecentTasks; persistentTaskIds.clear(); - int taskNdx; - for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { task = tasks.get(taskNdx); if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" + task.isPersistable + " needsPersisting=" + task.needsPersisting); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index b94ea62..1b1fc8b 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -259,13 +259,17 @@ abstract public class ManagedServices { userIds[i])); } - ManagedServiceInfo[] toRemove = new ManagedServiceInfo[mServices.size()]; + ArrayList<ManagedServiceInfo> toRemove = new ArrayList<ManagedServiceInfo>(); final SparseArray<ArrayList<ComponentName>> toAdd = new SparseArray<ArrayList<ComponentName>>(); synchronized (mMutex) { - // unbind and remove all existing services - toRemove = mServices.toArray(toRemove); + // Unbind automatically bound services, retain system services. + for (ManagedServiceInfo service : mServices) { + if (!service.isSystem) { + toRemove.add(service); + } + } final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>(); final ArraySet<String> newPackages = new ArraySet<String>(); diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index d81a25e..66cc532 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -46,12 +46,14 @@ import java.util.Map; * {@hide} */ public class NotificationUsageStats { + private static final boolean ENABLE_SQLITE_LOG = false; + // Guarded by synchronized(this). private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>(); private final SQLiteLog mSQLiteLog; public NotificationUsageStats(Context context) { - mSQLiteLog = new SQLiteLog(context); + mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null; } /** @@ -63,7 +65,9 @@ public class NotificationUsageStats { for (AggregatedStats stats : getAggregatedStatsLocked(notification)) { stats.numPostedByApp++; } - mSQLiteLog.logPosted(notification); + if (ENABLE_SQLITE_LOG) { + mSQLiteLog.logPosted(notification); + } } /** @@ -85,7 +89,9 @@ public class NotificationUsageStats { stats.numRemovedByApp++; stats.collect(notification.stats); } - mSQLiteLog.logRemoved(notification); + if (ENABLE_SQLITE_LOG) { + mSQLiteLog.logRemoved(notification); + } } /** @@ -97,7 +103,9 @@ public class NotificationUsageStats { stats.numDismissedByUser++; stats.collect(notification.stats); } - mSQLiteLog.logDismissed(notification); + if (ENABLE_SQLITE_LOG) { + mSQLiteLog.logDismissed(notification); + } } /** @@ -108,7 +116,9 @@ public class NotificationUsageStats { for (AggregatedStats stats : getAggregatedStatsLocked(notification)) { stats.numClickedByUser++; } - mSQLiteLog.logClicked(notification); + if (ENABLE_SQLITE_LOG) { + mSQLiteLog.logClicked(notification); + } } /** @@ -164,7 +174,9 @@ public class NotificationUsageStats { for (AggregatedStats as : mStats.values()) { as.dump(pw, indent); } - mSQLiteLog.dump(pw, indent); + if (ENABLE_SQLITE_LOG) { + mSQLiteLog.dump(pw, indent); + } } /** diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index 157d749..a629a5f 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -139,56 +139,64 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } private String[] getExtraPeople(Bundle extras) { - String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE); - if (people != null) { - return people; + Object people = extras.get(Notification.EXTRA_PEOPLE); + if (people instanceof String[]) { + return (String[]) people; } - ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE); - if (stringArray != null) { - return (String[]) stringArray.toArray(); + if (people instanceof ArrayList) { + ArrayList arrayList = (ArrayList) people; + + if (arrayList.isEmpty()) { + return null; + } + + if (arrayList.get(0) instanceof String) { + ArrayList<String> stringArray = (ArrayList<String>) arrayList; + return stringArray.toArray(new String[stringArray.size()]); + } + + if (arrayList.get(0) instanceof CharSequence) { + ArrayList<CharSequence> charSeqList = (ArrayList<CharSequence>) arrayList; + final int N = charSeqList.size(); + String[] array = new String[N]; + for (int i = 0; i < N; i++) { + array[i] = charSeqList.get(i).toString(); + } + return array; + } + + return null; } - String string = extras.getString(Notification.EXTRA_PEOPLE); - if (string != null) { - people = new String[1]; - people[0] = string; - return people; + if (people instanceof String) { + String[] array = new String[1]; + array[0] = (String) people; + return array; } - char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE); - if (charArray != null) { - people = new String[1]; - people[0] = new String(charArray); - return people; + + if (people instanceof char[]) { + String[] array = new String[1]; + array[0] = new String((char[]) people); + return array; } - CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE); - if (charSeq != null) { - people = new String[1]; - people[0] = charSeq.toString(); - return people; + if (people instanceof CharSequence) { + String[] array = new String[1]; + array[0] = ((CharSequence) people).toString(); + return array; } - CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE); - if (charSeqArray != null) { + if (people instanceof CharSequence[]) { + CharSequence[] charSeqArray = (CharSequence[]) people; final int N = charSeqArray.length; - people = new String[N]; + String[] array = new String[N]; for (int i = 0; i < N; i++) { - people[i] = charSeqArray[i].toString(); + array[i] = charSeqArray[i].toString(); } - return people; + return array; } - ArrayList<CharSequence> charSeqList = - extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE); - if (charSeqList != null) { - final int N = charSeqList.size(); - people = new String[N]; - for (int i = 0; i < N; i++) { - people[i] = charSeqList.get(i).toString(); - } - return people; - } return null; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b06b090..d505e81 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11775,8 +11775,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } if (removed.size() > 0) { - for (int j=0; j<removed.size(); j++) { - PreferredActivity pa = removed.get(i); + for (int r=0; r<removed.size(); r++) { + PreferredActivity pa = removed.get(r); Slog.w(TAG, "Removing dangling preferred activity: " + pa.mPref.mComponent); pir.removeFilter(pa); diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java index 6d208ff..80030b4 100644 --- a/services/core/java/com/android/server/task/TaskManagerService.java +++ b/services/core/java/com/android/server/task/TaskManagerService.java @@ -16,12 +16,22 @@ package com.android.server.task; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import android.app.task.ITaskManager; +import android.app.task.Task; import android.content.Context; -import android.content.Task; +import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.util.Log; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; import android.util.SparseArray; import com.android.server.task.controllers.TaskStatus; @@ -39,13 +49,6 @@ public class TaskManagerService extends com.android.server.SystemService /** Master list of tasks. */ private final TaskStore mTasks; - /** Check the pending queue and start any tasks. */ - static final int MSG_RUN_PENDING = 0; - /** Initiate the stop task flow. */ - static final int MSG_STOP_TASK = 1; - /** */ - static final int MSG_CHECK_TASKS = 2; - /** * Track Services that have currently active or pending tasks. The index is provided by * {@link TaskStatus#getServiceToken()} @@ -54,6 +57,14 @@ public class TaskManagerService extends com.android.server.SystemService new SparseArray<TaskServiceContext>(); private final TaskHandler mHandler; + private final TaskManagerStub mTaskManagerStub; + + /** Check the pending queue and start any tasks. */ + static final int MSG_RUN_PENDING = 0; + /** Initiate the stop task flow. */ + static final int MSG_STOP_TASK = 1; + /** */ + static final int MSG_CHECK_TASKS = 2; private class TaskHandler extends Handler { @@ -94,21 +105,6 @@ public class TaskManagerService extends com.android.server.SystemService } /** - * Entry point from client to schedule the provided task. - * This will add the task to the - * @param task Task object containing execution parameters - * @param userId The id of the user this task is for. - * @param uId The package identifier of the application this task is for. - * @param canPersistTask Whether or not the client has the appropriate permissions for persisting - * of this task. - * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes. - */ - public int schedule(Task task, int userId, int uId, boolean canPersistTask) { - TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask); - return 0; - } - - /** * Initializes the system service. * <p> * Subclasses must define a single argument constructor that accepts the context @@ -121,11 +117,42 @@ public class TaskManagerService extends com.android.server.SystemService super(context); mTasks = new TaskStore(context); mHandler = new TaskHandler(context.getMainLooper()); + mTaskManagerStub = new TaskManagerStub(); } @Override public void onStart() { + publishBinderService(Context.TASK_SERVICE, mTaskManagerStub); + } + + /** + * Entry point from client to schedule the provided task. + * This will add the task to the + * @param task Task object containing execution parameters + * @param userId The id of the user this task is for. + * @param uId The package identifier of the application this task is for. + * @param canPersistTask Whether or not the client has the appropriate permissions for + * persisting of this task. + * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes. + */ + public int schedule(Task task, int userId, int uId, boolean canPersistTask) { + TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask); + return 0; + } + public List<Task> getPendingTasks(int uid) { + ArrayList<Task> outList = new ArrayList<Task>(3); + synchronized (mTasks) { + final SparseArray<TaskStatus> tasks = mTasks.getTasks(); + final int N = tasks.size(); + for (int i = 0; i < N; i++) { + TaskStatus ts = tasks.get(i); + if (ts.getUid() == uid) { + outList.add(ts.getTask()); + } + } + } + return outList; } // StateChangedListener implementations. @@ -162,7 +189,7 @@ public class TaskManagerService extends com.android.server.SystemService public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) { final TaskServiceContext serviceContext = mActiveServices.get(serviceToken); if (serviceContext == null) { - Log.e(TAG, "Task completed for invalid service context; " + serviceToken); + Slog.e(TAG, "Task completed for invalid service context; " + serviceToken); return; } @@ -203,4 +230,98 @@ public class TaskManagerService extends com.android.server.SystemService private void postCheckTasksMessage() { mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget(); } + + /** + * Binder stub trampoline implementation + */ + final class TaskManagerStub extends ITaskManager.Stub { + /** Cache determination of whether a given app can persist tasks + * key is uid of the calling app; value is undetermined/true/false + */ + private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>(); + + // Determine whether the caller is allowed to persist tasks, with a small cache + // because the lookup is expensive enough that we'd like to avoid repeating it. + // This must be called from within the calling app's binder identity! + private boolean canCallerPersistTasks() { + final boolean canPersist; + final int callingUid = Binder.getCallingUid(); + synchronized (mPersistCache) { + Boolean cached = mPersistCache.get(callingUid); + if (cached) { + canPersist = cached.booleanValue(); + } else { + // Persisting tasks is tantamount to running at boot, so we permit + // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED + // permission + int result = getContext().checkCallingPermission( + android.Manifest.permission.RECEIVE_BOOT_COMPLETED); + canPersist = (result == PackageManager.PERMISSION_GRANTED); + mPersistCache.put(callingUid, canPersist); + } + } + return canPersist; + } + + // ITaskManager implementation + @Override + public int schedule(Task task) throws RemoteException { + final boolean canPersist = canCallerPersistTasks(); + final int uid = Binder.getCallingUid(); + final int userId = UserHandle.getCallingUserId(); + + long ident = Binder.clearCallingIdentity(); + try { + return TaskManagerService.this.schedule(task, userId, uid, canPersist); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public List<Task> getAllPendingTasks() throws RemoteException { + return null; + } + + @Override + public void cancelAll() throws RemoteException { + } + + @Override + public void cancel(int taskId) throws RemoteException { + } + + /** + * "dumpsys" infrastructure + */ + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + + long identityToken = Binder.clearCallingIdentity(); + try { + TaskManagerService.this.dumpInternal(pw); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + } + }; + + void dumpInternal(PrintWriter pw) { + synchronized (mTasks) { + pw.print("Registered tasks:"); + if (mTasks.size() > 0) { + SparseArray<TaskStatus> tasks = mTasks.getTasks(); + for (int i = 0; i < tasks.size(); i++) { + TaskStatus ts = tasks.get(i); + pw.println(); + ts.dump(pw, " "); + } + } else { + pw.println(); + pw.println("No tasks scheduled."); + } + } + pw.println(); + } } diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java index b51cbb3..165445a 100644 --- a/services/core/java/com/android/server/task/TaskServiceContext.java +++ b/services/core/java/com/android/server/task/TaskServiceContext.java @@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * is reused to start concurrent tasks on the TaskService. Information here is unique * to the service. * Functionality provided by this class: - * - Managages wakelock for the service. + * - Manages wakelock for the service. * - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks. * - */ diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java index 3bfc8a5..81187c8 100644 --- a/services/core/java/com/android/server/task/TaskStore.java +++ b/services/core/java/com/android/server/task/TaskStore.java @@ -16,8 +16,8 @@ package com.android.server.task; +import android.app.task.Task; import android.content.Context; -import android.content.Task; import android.util.SparseArray; import com.android.server.task.controllers.TaskStatus; @@ -95,6 +95,13 @@ public class TaskStore { } /** + * @return the number of tasks in the store + */ + public int size() { + return mTasks.size(); + } + + /** * @return The live array of TaskStatus objects. */ public SparseArray<TaskStatus> getTasks() { diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java index 6a4e1f3..a0038c5 100644 --- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java @@ -70,13 +70,10 @@ public class ConnectivityController extends StateController { } /** - * @param userId Id of the user for whom we are updating the connectivity state. + * */ - private void updateTrackedTasks(int userId) { + private void updateTrackedTasks() { for (TaskStatus ts : mTrackedTasks) { - if (ts.userId != userId) { - continue; - } boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity); boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered); if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) { @@ -107,14 +104,13 @@ public class ConnectivityController extends StateController { final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo(); // This broadcast gets sent a lot, only update if the active network has changed. if (activeNetwork.getType() == networkType) { - final int userid = context.getUserId(); mMetered = false; mConnectivity = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); if (mConnectivity) { // No point making the call if we know there's no conn. mMetered = connManager.isActiveNetworkMetered(); } - updateTrackedTasks(userid); + updateTrackedTasks(); } } else { Log.w(TAG, "Unrecognised action in intent: " + action); diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java index d96fedc..d270016 100644 --- a/services/core/java/com/android/server/task/controllers/TaskStatus.java +++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java @@ -16,17 +16,19 @@ package com.android.server.task.controllers; +import android.app.task.Task; import android.content.ComponentName; -import android.content.Task; import android.content.pm.PackageParser; import android.os.Bundle; import android.os.SystemClock; +import android.os.UserHandle; +import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicBoolean; /** * Uniquely identifies a task internally. - * Created from the public {@link android.content.Task} object when it lands on the scheduler. + * Created from the public {@link android.app.task.Task} object when it lands on the scheduler. * Contains current state of the requirements of the task, as well as a function to evaluate * whether it's ready to run. * This object is shared among the various controllers - hence why the different fields are atomic. @@ -36,10 +38,9 @@ import java.util.concurrent.atomic.AtomicBoolean; * @hide */ public class TaskStatus { + final Task task; final int taskId; - final int userId; final int uId; - final ComponentName component; final Bundle extras; final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean(); @@ -57,9 +58,9 @@ public class TaskStatus { private long earliestRunTimeElapsedMillis; private long latestRunTimeElapsedMillis; - /** Provide a unique handle to the service that this task will be run on. */ + /** Provide a handle to the service that this task will be run on. */ public int getServiceToken() { - return component.hashCode() + userId; + return uId; } /** Generate a TaskStatus object for a given task and uid. */ @@ -70,9 +71,8 @@ public class TaskStatus { /** Set up the state of a newly scheduled task. */ TaskStatus(Task task, int userId, int uId) { + this.task = task; this.taskId = task.getTaskId(); - this.userId = userId; - this.component = task.getService(); this.extras = task.getExtras(); this.uId = uId; @@ -100,16 +100,20 @@ public class TaskStatus { hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY; } + public Task getTask() { + return task; + } + public int getTaskId() { return taskId; } public ComponentName getServiceComponent() { - return component; + return task.getService(); } public int getUserId() { - return userId; + return UserHandle.getUserId(uId); } public int getUid() { @@ -161,9 +165,9 @@ public class TaskStatus { @Override public int hashCode() { - int result = component.hashCode(); + int result = getServiceComponent().hashCode(); result = 31 * result + taskId; - result = 31 * result + userId; + result = 31 * result + uId; return result; } @@ -174,7 +178,14 @@ public class TaskStatus { TaskStatus that = (TaskStatus) o; return ((taskId == that.taskId) - && (userId == that.userId) - && (component.equals(that.component))); + && (uId == that.uId) + && (getServiceComponent().equals(that.getServiceComponent()))); + } + + // Dumpsys infrastructure + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("Task "); pw.println(taskId); + pw.print(prefix); pw.print("uid="); pw.println(uId); + pw.print(prefix); pw.print("component="); pw.println(task.getService()); } } diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 47ce3b6..f18939f 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -63,6 +63,11 @@ public class TrustAgentWrapper { public void handleMessage(Message msg) { switch (msg.what) { case MSG_GRANT_TRUST: + if (!isConnected()) { + Log.w(TAG, "Agent is not connected, cannot grant trust: " + + mName.flattenToShortString()); + return; + } mTrusted = true; mMessage = (CharSequence) msg.obj; boolean initiatedByUser = msg.arg1 != 0; @@ -119,6 +124,7 @@ public class TrustAgentWrapper { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); mTrustAgentService = ITrustAgentService.Stub.asInterface(service); + mTrustManagerService.mArchive.logAgentConnected(mUserId, name); setCallback(mCallback); } @@ -179,7 +185,10 @@ public class TrustAgentWrapper { public void unbind() { if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); + mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); mContext.unbindService(mConnection); + mTrustAgentService = null; + mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); } public boolean isConnected() { diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java index aad156c..56950d2 100644 --- a/services/core/java/com/android/server/trust/TrustArchive.java +++ b/services/core/java/com/android/server/trust/TrustArchive.java @@ -33,6 +33,8 @@ public class TrustArchive { private static final int TYPE_REVOKE_TRUST = 1; private static final int TYPE_TRUST_TIMEOUT = 2; private static final int TYPE_AGENT_DIED = 3; + private static final int TYPE_AGENT_CONNECTED = 4; + private static final int TYPE_AGENT_STOPPED = 5; private static final int HISTORY_LIMIT = 200; @@ -79,6 +81,14 @@ public class TrustArchive { addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false)); } + public void logAgentConnected(int userId, ComponentName agent) { + addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, false)); + } + + public void logAgentStopped(int userId, ComponentName agent) { + addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, false)); + } + private void addEvent(Event e) { if (mEvents.size() >= HISTORY_LIMIT) { mEvents.removeFirst(); @@ -152,6 +162,10 @@ public class TrustArchive { return "TrustTimeout"; case TYPE_AGENT_DIED: return "AgentDied"; + case TYPE_AGENT_CONNECTED: + return "AgentConnected"; + case TYPE_AGENT_STOPPED: + return "AgentStopped"; default: return "Unknown(" + type + ")"; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6fbb39d..c23d1ea 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3189,6 +3189,7 @@ public class WindowManagerService extends IWindowManager.Stub WindowState win = atoken.findMainWindow(); Rect containingFrame = new Rect(0, 0, width, height); Rect contentInsets = new Rect(); + boolean isFullScreen = true; if (win != null) { if (win.mContainingFrame != null) { containingFrame.set(win.mContainingFrame); @@ -3196,11 +3197,11 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mContentInsets != null) { contentInsets.set(win.mContentInsets); } + isFullScreen = + ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) == + SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN); } - boolean isFullScreen = - ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) - == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN); Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height, mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen); if (a != null) { |